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 | |
| parent | 7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff) | |
Add usblib and utils
Diffstat (limited to 'usblib/device')
26 files changed, 25424 insertions, 0 deletions
diff --git a/usblib/device/usbdaudio.c b/usblib/device/usbdaudio.c new file mode 100644 index 0000000..18c90b5 --- /dev/null +++ b/usblib/device/usbdaudio.c @@ -0,0 +1,1510 @@ +//*****************************************************************************
+//
+// usbdaudio.c - USB audio device class driver.
+//
+// Copyright (c) 2009-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_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbaudio.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdaudio.h"
+
+//*****************************************************************************
+//
+//! \addtogroup audio_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following are the USB audio descriptor identifiers.
+//
+//*****************************************************************************
+#define AUDIO_IN_TERMINAL_ID 1
+#define AUDIO_OUT_TERMINAL_ID 2
+#define AUDIO_CONTROL_ID 3
+
+//*****************************************************************************
+//
+// The following are the USB interface numbers for this audio device.
+//
+//*****************************************************************************
+#define AUDIO_INTERFACE_CONTROL 0
+#define AUDIO_INTERFACE_OUTPUT 1
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define ISOC_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// Max size is (48000 samples/sec * 4 bytes/sample) * 0.001 seconds/frame.
+//
+//*****************************************************************************
+#define ISOC_OUT_EP_MAX_SIZE ((48000*4)/1000)
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8AudioDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ 0, // USB Device Class (spec 5.1.1)
+ 0, // USB Device Sub-class (spec 5.1.1)
+ 0, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during USBDAudioInit).
+ USBShort(0), // Product ID (filled in during USBDAudioInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Audio class device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8AudioDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(32), // The total size of this full structure.
+ 2, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_BUS_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// This is the Interface Association Descriptor for the serial device used in
+// composite devices.
+//
+//*****************************************************************************
+uint8_t g_pui8IADAudioDescriptor[AUDIODESCRIPTOR_SIZE] =
+{
+
+ 8, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE_ASC, // Interface Association Type.
+ 0x0, // Default starting interface is 0.
+ 0x2, // Number of interfaces in this association.
+ USB_CLASS_AUDIO, // The device class for this association.
+ USB_SUBCLASS_UNDEFINED, // The device subclass for this association.
+ USB_PROTOCOL_UNDEFINED, // The protocol for this association.
+ 0 // The string index for this association.
+};
+
+const tConfigSection g_sIADAudioConfigSection =
+{
+ sizeof(g_pui8IADAudioDescriptor),
+ g_pui8IADAudioDescriptor
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const uint8_t g_pui8AudioControlInterface[CONTROLINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ AUDIO_INTERFACE_CONTROL, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 0, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_AUDIO, // The interface class
+ USB_ASC_AUDIO_CONTROL, // The interface sub-class.
+ 0, // The interface protocol for the sub-class
+ // specified above.
+ 0, // The string index for this interface.
+
+ //
+ // Audio Header Descriptor.
+ //
+ 9, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_HEADER, // Descriptor sub-type is HEADER.
+ USBShort(0x0100), // Audio Device Class Specification Release
+ // Number in Binary-Coded Decimal.
+ // Total number of bytes in
+ // g_pui8AudioControlInterface
+ USBShort((9 + 9 + 12 + 13 + 9)),
+ 1, // Number of streaming interfaces.
+ 1, // Index of the first and only streaming
+ // interface.
+
+ //
+ // Audio Input Terminal Descriptor.
+ //
+ 12, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_IN_TERMINAL, // Descriptor sub-type is INPUT_TERMINAL.
+ AUDIO_IN_TERMINAL_ID, // Terminal ID for this interface.
+ // USB streaming interface.
+ USBShort(USB_TTYPE_STREAMING),
+ 0, // ID of the Output Terminal to which this
+ // Input Terminal is associated.
+ 2, // Number of logical output channels in the
+ // Terminal's output audio channel cluster.
+ USBShort((USB_CHANNEL_L | // Describes the spatial location of the
+ USB_CHANNEL_R)), // logical channels.
+ 0, // Channel Name string index.
+ 0, // Terminal Name string index.
+
+ //
+ // Audio Feature Unit Descriptor
+ //
+ 13, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_FEATURE_UNIT, // Descriptor sub-type is FEATURE_UNIT.
+ AUDIO_CONTROL_ID, // Unit ID for this interface.
+ AUDIO_IN_TERMINAL_ID, // ID of the Unit or Terminal to which this
+ // Feature Unit is connected.
+ 2, // Size in bytes of an element of the
+ // bmaControls() array that follows.
+ // Master Mute control.
+ USBShort(USB_ACONTROL_MUTE),
+ // Left channel volume control.
+ USBShort(USB_ACONTROL_VOLUME),
+ // Right channel volume control.
+ USBShort(USB_ACONTROL_VOLUME),
+ 0, // Feature unit string index.
+
+ //
+ // Audio Output Terminal Descriptor.
+ //
+ 9, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_OUT_TERMINAL, // Descriptor sub-type is INPUT_TERMINAL.
+ AUDIO_OUT_TERMINAL_ID, // Terminal ID for this interface.
+ // Output type is a generic speaker.
+ USBShort(USB_ATTYPE_SPEAKER),
+ AUDIO_IN_TERMINAL_ID, // ID of the input terminal to which this
+ // output terminal is connected.
+ AUDIO_CONTROL_ID, // ID of the feature unit that this output
+ // terminal is connected to.
+ 0, // Output terminal string index.
+
+};
+
+//*****************************************************************************
+//
+// The audio streaming interface descriptor. This describes the two valid
+// interfaces for this class. The first interface has no endpoints and is used
+// by host operating systems to put the device in idle mode, while the second
+// is used when the audio device is active.
+//
+//*****************************************************************************
+const uint8_t g_pui8AudioStreamInterface[STREAMINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ AUDIO_INTERFACE_OUTPUT, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 0, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_AUDIO, // The interface class
+ USB_ASC_AUDIO_STREAMING, // The interface sub-class.
+ 0, // Unused must be 0.
+ 0, // The string index for this interface.
+
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 1, // The index for this interface.
+ 1, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_AUDIO, // The interface class
+ USB_ASC_AUDIO_STREAMING, // The interface sub-class.
+ 0, // Unused must be 0.
+ 0, // The string index for this interface.
+
+ //
+ // Class specific Audio Streaming Interface descriptor.
+ //
+ 7, // Size of the interface descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ASDSTYPE_GENERAL, // General information.
+ AUDIO_IN_TERMINAL_ID, // ID of the terminal to which this streaming
+ // interface is connected.
+ 1, // One frame delay.
+ USBShort(USB_ADF_PCM), //
+
+ //
+ // Format type Audio Streaming descriptor.
+ //
+ 11, // Size of the interface descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ASDSTYPE_FORMAT_TYPE, // Audio Streaming format type.
+ USB_AF_TYPE_TYPE_I, // Type I audio format type.
+ 2, // Two audio channels.
+ 2, // Two bytes per audio sub-frame.
+ 16, // 16 bits per sample.
+ 1, // One sample rate provided.
+ USB3Byte(48000), // Only 48000 sample rate supported.
+
+ //
+ // Endpoint Descriptor
+ //
+ 9, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ // OUT endpoint with address
+ // ISOC_OUT_ENDPOINT.
+ USB_EP_DESC_OUT | USBEPToIndex(ISOC_OUT_ENDPOINT),
+ USB_EP_ATTR_ISOC | // Endpoint is an adaptive isochronous data
+ USB_EP_ATTR_ISOC_ADAPT | // endpoint.
+ USB_EP_ATTR_USAGE_DATA,
+ USBShort(ISOC_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 1, // The polling interval for this endpoint.
+ 0, // Refresh is unused.
+ 0, // Synch endpoint address.
+
+ //
+ // Audio Streaming Isochronous Audio Data Endpoint Descriptor
+ //
+ 7, // The size of the descriptor.
+ USB_ACSDT_ENDPOINT, // Audio Class Specific Endpoint
+ // Descriptor.
+ USB_ASDSTYPE_GENERAL, // This is a general descriptor.
+ USB_EP_ATTR_ACG_SAMPLING, // Sampling frequency is supported.
+ USB_EP_LOCKDELAY_UNDEF, // Undefined lock delay units.
+ USBShort(0), // No lock delay.
+};
+
+//*****************************************************************************
+//
+// The audio device configuration descriptor is defined as three sections,
+// one containing just the 9 byte USB configuration descriptor. The second
+// holds the audio streaming interface and the third holds the audio control
+// interface.
+//
+//*****************************************************************************
+const tConfigSection g_sAudioConfigSection =
+{
+ sizeof(g_pui8AudioDescriptor),
+ g_pui8AudioDescriptor
+};
+
+const tConfigSection g_sAudioStreamInterfaceSection =
+{
+ sizeof(g_pui8AudioStreamInterface),
+ g_pui8AudioStreamInterface
+};
+
+const tConfigSection g_sAudioControlInterfaceSection =
+{
+ sizeof(g_pui8AudioControlInterface),
+ g_pui8AudioControlInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete audio device configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psAudioSections[] =
+{
+ &g_sAudioConfigSection,
+ &g_sIADAudioConfigSection,
+ &g_sAudioControlInterfaceSection,
+ &g_sAudioStreamInterfaceSection
+};
+
+#define NUM_AUDIO_SECTIONS (sizeof(g_psAudioSections) / \
+ sizeof(g_psAudioSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sAudioConfigHeader =
+{
+ NUM_AUDIO_SECTIONS,
+ g_psAudioSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppAudioConfigDescriptors[] =
+{
+ &g_sAudioConfigHeader
+};
+
+//*****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//*****************************************************************************
+static void HandleDisconnect(void *pvAudioDevice);
+static void InterfaceChange(void *pvAudioDevice, uint8_t ui8Interface,
+ uint8_t ui8AlternateSetting);
+static void ConfigChangeHandler(void *pvAudioDevice, uint32_t ui32Value);
+static void DataReceived(void *pvAudioDevice, uint32_t ui32Info);
+static void HandleEndpoints(void *pvAudioDevice, uint32_t ui32Status);
+static void HandleRequests(void *pvAudioDevice, tUSBRequest *psUSBRequest);
+static void HandleDevice(void *pvAudioDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB Audio device.
+//
+//*****************************************************************************
+static const tCustomHandlers g_sAudioHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ InterfaceChange,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ 0,
+
+ //
+ // ResumeHandler
+ //
+ 0,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// This function is called to handle data being received back from the host so
+// that the application callback can be called when the new data is ready.
+//
+//*****************************************************************************
+static void
+DataReceived(void *pvAudioDevice, uint32_t ui32Info)
+{
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Make a copy of this pointer for ease of use in this function.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // If there is an update pending and the request was to set a current
+ // value then check which value was set.
+ //
+ if(psInst->ui16Update && (psInst->ui8Request == USB_AC_SET_CUR))
+ {
+ //
+ // Only handling interface requests.
+ //
+ if((psInst->ui16RequestType & USB_RTYPE_RECIPIENT_M) ==
+ USB_RTYPE_INTERFACE)
+ {
+ if(psInst->ui16Update == VOLUME_CONTROL)
+ {
+ //
+ // Inform the callback of the new volume.
+ //
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_VOLUME,
+ psInst->i16Volume, 0);
+ }
+ else if(psAudioDevice->sPrivateData.ui16Update == MUTE_CONTROL)
+ {
+ //
+ // Inform the callback of the new data.
+ //
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_MUTE,
+ psInst->ui8Mute, 0);
+ }
+ }
+ psInst->ui16Update = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called to handle the interrupts on the isochronous endpoint
+// for the audio device class.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvAudioDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus;
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+ uint32_t ui32Size;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Read out the current endpoint status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // See if there is a receive interrupt pending.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Get the amount of data available in the FIFO.
+ //
+ ui32Size = USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Configure the next DMA transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ psInst->sBuffer.pvData, ui32Size);
+ }
+ else if((USBLibDMAChannelStatus(psInst->psDMAInstance,
+ psInst->ui8OUTDMA) ==
+ USBLIBSTATUS_DMA_COMPLETE))
+ {
+ USBEndpointDMADisable(USB0_BASE,
+ psInst->ui8OUTEndpoint, USB_EP_DEV_OUT);
+
+ //
+ // Acknowledge that the data was read, this will not cause a bus
+ // acknowledgment.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, psInst->ui8OUTEndpoint, 0);
+
+ //
+ // Inform the callback of the new data.
+ //
+ psInst->sBuffer.pfnCallback(psInst->sBuffer.pvData,
+ psInst->sBuffer.ui32Size,
+ USBD_AUDIO_EVENT_DATAOUT);
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvAudioDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tAudioInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDAudioDevice *psAudioDevice;
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the appropriate interface number.
+ //
+ if(pui8Data[0] == AUDIO_INTERFACE_CONTROL)
+ {
+ psInst->ui8InterfaceControl = pui8Data[1];
+ }
+ else if(pui8Data[0] == AUDIO_INTERFACE_OUTPUT)
+ {
+ psInst->ui8InterfaceAudio = pui8Data[1];
+ }
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if((pui8Data[0] & USB_EP_DESC_IN) == 0)
+ {
+ //
+ // Extract the new endpoint number without the DIR bit.
+ //
+ psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f);
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psInst->ui8OUTDMA != 0)
+ {
+ USBLibDMAChannelRelease(psInst->psDMAInstance,
+ psInst->ui8OUTDMA);
+ }
+
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ psInst->ui8OUTDMA =
+ USBLibDMAChannelAllocate(psInst->psDMAInstance,
+ psInst->ui8OUTEndpoint,
+ ISOC_OUT_EP_MAX_SIZE,
+ (USB_DMA_EP_RX |
+ USB_DMA_EP_TYPE_ISOC |
+ USB_DMA_EP_DEVICE));
+
+ //
+ // Set the DMA individual transfer size.
+ //
+ USBLibDMAUnitSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 32);
+
+ //
+ // Set the DMA arbitration size.
+ //
+ USBLibDMAArbSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 16);
+ }
+ break;
+ }
+
+ //
+ // Handle class specific reconfiguring of the configuration descriptor
+ // once the composite class has built the full descriptor.
+ //
+ case USB_EVENT_COMP_CONFIG:
+ {
+ //
+ // This sets the bFirstInterface of the Interface Association
+ // descriptor to the first interface which is the control
+ // interface used by this instance.
+ //
+ pui8Data[2] = psInst->ui8InterfaceControl;
+
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvAudioDevice)
+{
+ const tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (const tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_DISCONNECTED, 0, 0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// interface changes. This occurs when the audio device transitions between
+// being active and inactive. Interface AUDIO_INTERFACE_CONTROL is the
+// inactive interface that has no endpoints, while interface
+// AUDIO_INTERFACE_AUDIO has the single Isochronous OUT endpoint.
+//
+//*****************************************************************************
+static void
+InterfaceChange(void *pvAudioDevice, uint8_t ui8Interface,
+ uint8_t ui8AlternateSetting)
+{
+ const tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (const tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Check which interface to change into.
+ //
+ if(ui8AlternateSetting == 0)
+ {
+ //
+ // Alternate setting 0 is an inactive state.
+ //
+ if(psAudioDevice->pfnCallback)
+ {
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_IDLE, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Alternate setting 1 is the active state.
+ //
+ if(psAudioDevice->pfnCallback)
+ {
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_ACTIVE, 0, 0);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes.
+//
+//*****************************************************************************
+static void
+ConfigChangeHandler(void *pvAudioDevice, uint32_t ui32Value)
+{
+ const tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (const tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psAudioDevice->pfnCallback(pvAudioDevice, USB_EVENT_CONNECTED, 0, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the audio class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! audio class device operation.
+//! \param psAudioDevice points to a structure containing parameters
+//! customizing the operation of the audio device.
+//!
+//! In order for an application to initialize the USB audio device class, it
+//! must first call this function with the a valid audio device class structure
+//! in the \e psAudioDevice parameter. This allows this function to initialize
+//! the USB controller and device code to be prepared to enumerate and function
+//! as a USB audio device.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the audio class.
+//!
+//! See the documentation on the tUSBDAudioDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return Returns 0 on failure or a non-zero void pointer on success.
+//
+//*****************************************************************************
+void *
+USBDAudioInit(uint32_t ui32Index, tUSBDAudioDevice *psAudioDevice)
+{
+ tConfigDescriptor *psConfigDesc;
+ tDeviceDescriptor *psDevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psAudioDevice);
+ ASSERT(psAudioDevice->ppui8StringDescriptors);
+
+ //
+ // Composite Init handles all initialization that is not specific to a
+ // multiple instance device.
+ //
+ USBDAudioCompositeInit(ui32Index, psAudioDevice, 0);
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8AudioDeviceDescriptor;
+ psDevDesc->idVendor = psAudioDevice->ui16VID;
+ psDevDesc->idProduct = psAudioDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psConfigDesc = (tConfigDescriptor *)g_pui8AudioDescriptor;
+ psConfigDesc->bmAttributes = psAudioDevice->ui8PwrAttributes;
+ psConfigDesc->bMaxPower = (uint8_t)(psAudioDevice->ui16MaxPowermA / 2);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psAudioDevice->sPrivateData.sDevInfo,
+ (void *)psAudioDevice);
+
+ //
+ // Configure the DMA for the OUT endpoint.
+ //
+ psAudioDevice->sPrivateData.ui8OUTDMA =
+ USBLibDMAChannelAllocate(psAudioDevice->sPrivateData.psDMAInstance,
+ psAudioDevice->sPrivateData.ui8OUTEndpoint,
+ ISOC_OUT_EP_MAX_SIZE,
+ USB_DMA_EP_RX | USB_DMA_EP_TYPE_ISOC |
+ USB_DMA_EP_DEVICE);
+
+ USBLibDMAUnitSizeSet(psAudioDevice->sPrivateData.psDMAInstance,
+ psAudioDevice->sPrivateData.ui8OUTDMA, 32);
+ USBLibDMAArbSizeSet(psAudioDevice->sPrivateData.psDMAInstance,
+ psAudioDevice->sPrivateData.ui8OUTDMA, 16);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psAudioDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the audio class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! audio class device operation.
+//! \param psAudioDevice points to a structure containing parameters
+//! customizing the operation of the audio device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! In order for an application to initialize the USB audio device class, it
+//! must first call this function with the a valid audio device class structure
+//! in the \e psAudioDevice parameter. This allows this function to initialize
+//! the USB controller and device code to be prepared to enumerate and function
+//! as a USB audio device. When this audio device is part of a composite
+//! device, then the \e psCompEntry should point to the composite device entry
+//! to initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the audio class.
+//!
+//! See the documentation on the tUSBDAudioDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB audio APIs.
+//
+//*****************************************************************************
+void *
+USBDAudioCompositeInit(uint32_t ui32Index, tUSBDAudioDevice *psAudioDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tAudioInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psAudioDevice);
+ ASSERT(psAudioDevice->ppui8StringDescriptors);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+ psInst->ui32USBBase = USB0_BASE;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psAudioDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sAudioHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8AudioDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppAudioConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the HID device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // The Control interface is at index 0.
+ //
+ psInst->ui8InterfaceControl = AUDIO_INTERFACE_CONTROL;
+
+ //
+ // The Audio interface is at index 1.
+ //
+ psInst->ui8InterfaceAudio = AUDIO_INTERFACE_OUTPUT;
+
+ //
+ // Set the default Isochronous OUT endpoint.
+ //
+ psInst->ui8OUTEndpoint = ISOC_OUT_ENDPOINT;
+ psInst->ui8OUTDMA = 0;
+
+ //
+ // Set the initial buffer to null.
+ //
+ psInst->sBuffer.pvData = 0;
+
+ //
+ // Save the volume settings.
+ //
+ psInst->i16VolumeMax = psAudioDevice->i16VolumeMax;
+ psInst->i16VolumeMin = psAudioDevice->i16VolumeMin;
+ psInst->i16VolumeStep = psAudioDevice->i16VolumeStep;
+
+ //
+ // No update pending to any command.
+ //
+ psInst->ui16Update = 0;
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psAudioDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psAudioDevice->ui32NumStringDescriptors;
+
+ //
+ // Get the DMA instance pointer.
+ //
+ psInst->psDMAInstance = USBLibDMAInit(0);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psAudioDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the audio device.
+//!
+//! \param pvAudioDevice is the pointer to the device instance structure as
+//! returned by USBDAudioInit().
+//!
+//! This function terminates audio interface for the instance supplied. This
+//! function should not be called if the audio device is part of a composite
+//! device and instead the USBDCompositeTerm() function should be called for
+//! the full composite device.
+//! Following this call, the \e pvAudioDevice instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDAudioTerm(void *pvAudioDevice)
+{
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // Cleanly exit device mode.
+ //
+ USBDCDTerm(0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvAudioDevice is the instance data for this request.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure to the type of request and
+// will respond to all commands that are understood by the class.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HandleRequests(void *pvAudioDevice, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Control, ui32Recipient, ui32Stall;
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Make sure to acknowledge that the data was read, this will not send and
+ // ACK that has already been done at this point. This just tells the
+ // hardware that the data was read.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // Don't stall by default.
+ //
+ ui32Stall = 0;
+
+ //
+ // Get the request type.
+ //
+ ui32Recipient = psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M;
+
+ //
+ // Save the request type and request value.
+ //
+ psInst->ui16RequestType = psUSBRequest->bmRequestType;
+ psInst->ui8Request = psUSBRequest->bRequest;
+
+ //
+ // Check if this is an endpoint request to the audio streaming endpoint.
+ //
+ if((ui32Recipient == USB_RTYPE_ENDPOINT) &&
+ (psUSBRequest->wIndex == USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Determine the type of request.
+ //
+ switch(psInst->ui8Request)
+ {
+ case USB_AC_SET_CUR:
+ {
+ //
+ // Handle retrieving the sample rate.
+ //
+ if(psUSBRequest->wValue == SAMPLING_FREQ_CONTROL)
+ {
+ //
+ // Retrieve the requested sample rate.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->ui32SampleRate,
+ 3);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = SAMPLING_FREQ_CONTROL;
+ }
+ break;
+ }
+ case USB_AC_GET_CUR:
+ {
+ //
+ // Handle retrieving the sample rate.
+ //
+ if(psUSBRequest->wValue == SAMPLING_FREQ_CONTROL)
+ {
+ //
+ // Send back the current sample rate.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->ui32SampleRate,
+ 3);
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ break;
+ }
+ }
+ }
+ else if(ui32Recipient == USB_RTYPE_INTERFACE)
+ {
+ //
+ // Make sure the request was for the control interface.
+ //
+ if((uint8_t)psUSBRequest->wIndex != psInst->ui8InterfaceControl)
+ {
+ return;
+ }
+
+ //
+ // Extract the control value from the message.
+ //
+ ui32Control = psUSBRequest->wValue & USB_CS_CONTROL_M;
+
+ //
+ // Handle an audio control request to the feature control unit.
+ //
+ if((AUDIO_CONTROL_ID << 8) ==
+ (psUSBRequest->wIndex & USB_CS_CONTROL_M))
+ {
+ //
+ // Determine the type of request.
+ //
+ switch(psInst->ui8Request)
+ {
+ case USB_AC_GET_MAX:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Return the maximum volume setting.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeMax,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_MIN:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Return the minimum volume setting.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeMin,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_RES:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Return the volume step setting.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeStep,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_CUR:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Send back the current volume level.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16Volume,
+ 2);
+ }
+ else if(ui32Control == MUTE_CONTROL)
+ {
+ //
+ // Send back the current mute value.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->ui8Mute, 1);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_SET_CUR:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Read the new volume level.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->i16Volume,
+ 2);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = VOLUME_CONTROL;
+ }
+ else if(ui32Control == MUTE_CONTROL)
+ {
+ //
+ // Read the new mute setting.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->ui8Mute,
+ 1);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = MUTE_CONTROL;
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_SET_RES:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Read the new volume step setting.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeStep, 2);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = VOLUME_CONTROL;
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Stall on all unknown commands.
+ //
+ if(ui32Stall)
+ {
+ USBDCDStallEP0(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to supply buffers to the audio class to be filled
+//! from the USB host device.
+//!
+//! \param pvAudioDevice is the pointer to the device instance structure as
+//! returned by USBDAudioInit() or USBDAudioCompositeInit().
+//! \param pvBuffer is a pointer to the buffer to fill with audio data.
+//! \param ui32Size is the size in bytes of the buffer pointed to by the
+//! \e pvBuffer
+//! parameter.
+//! \param pfnCallback is a callback that will provide notification when this
+//! buffer has valid data.
+//!
+//! This function fills the buffer pointed to by the \e pvBuffer parameter with
+//! at most \e ui32Size one packet of data from the host controller. The
+//! \e ui32Size has a minimum value of \b ISOC_OUT_EP_MAX_SIZE since each USB
+//! packet can be at most \b ISOC_OUT_EP_MAX_SIZE bytes in size. Since the
+//! audio data may not be received in amounts that evenly fit in the buffer
+//! provided, the buffer may not be completely filled. The \e pfnCallback
+//! function will provide the amount of valid data that was actually stored in
+//! the buffer provided. The function will return zero if the buffer could be
+//! scheduled to be filled, otherwise the function will return a non-zero value
+//! if there was some reason that the buffer could not be added.
+//!
+//! \return Returns 0 to indicate success any other value indicates that the
+//! buffer will not be filled.
+//
+//*****************************************************************************
+int32_t
+USBAudioBufferOut(void *pvAudioDevice, void *pvBuffer, uint32_t ui32Size,
+ tUSBAudioBufferCallback pfnCallback)
+{
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+
+ //
+ // Make sure we were not passed NULL pointers.
+ //
+ ASSERT(pvAudioDevice != 0);
+ ASSERT(pvBuffer != 0);
+
+ //
+ // Buffer must be at least one packet in size.
+ //
+ ASSERT(ui32Size >= ISOC_OUT_EP_MAX_SIZE);
+ ASSERT(pfnCallback);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Initialize the buffer instance.
+ //
+ psInst->sBuffer.pvData = pvBuffer;
+ psInst->sBuffer.ui32Size = ui32Size;
+ psInst->sBuffer.ui32NumBytes = 0;
+ psInst->sBuffer.pfnCallback = pfnCallback;
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/usblib/device/usbdaudio.h b/usblib/device/usbdaudio.h new file mode 100644 index 0000000..e934914 --- /dev/null +++ b/usblib/device/usbdaudio.h @@ -0,0 +1,382 @@ +//*****************************************************************************
+//
+// usbdaudio.h - USB audio device class driver.
+//
+// Copyright (c) 2009-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.
+//
+//*****************************************************************************
+
+#ifndef __USBDAUDIO_H__
+#define __USBDAUDIO_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup audio_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+typedef void (* tUSBAudioBufferCallback)(void *pvBuffer, uint32_t ui32Param,
+ uint32_t ui32Event);
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// audio device class. The memory for this structure is pointed to by
+// the pi16PrivateData field in the tUSBDAudioDevice structure passed on
+// USBDAudioInit() and should not be modified by any code outside of the audio
+// device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The maximum volume expressed as an 8.8 signed value.
+ //
+ int16_t i16VolumeMax;
+
+ //
+ // The minimum volume expressed as an 8.8 signed value.
+ //
+ int16_t i16VolumeMin;
+
+ //
+ // The minimum volume step expressed as an 8.8 signed value.
+ //
+ int16_t i16VolumeStep;
+
+ struct
+ {
+ //
+ // Pointer to a buffer provided by caller.
+ //
+ void *pvData;
+
+ //
+ // Size of the data area provided in pvData in bytes.
+ //
+ uint32_t ui32Size;
+
+ //
+ // Number of valid bytes copied into the pvData area.
+ //
+ uint32_t ui32NumBytes;
+
+ //
+ // The buffer callback for this function.
+ //
+ tUSBAudioBufferCallback pfnCallback;
+ }
+ sBuffer;
+
+ //
+ // Pending request type.
+ //
+ uint16_t ui16RequestType;
+
+ //
+ // Pending request.
+ //
+ uint8_t ui8Request;
+
+ //
+ // Pending update value.
+ //
+ uint16_t ui16Update;
+
+ //
+ // Current Volume setting.
+ //
+ int16_t i16Volume;
+
+ //
+ // Current Mute setting.
+ //
+ uint8_t ui8Mute;
+
+ //
+ // Current Sample rate, this is not writable but the host will try.
+ //
+ uint32_t ui32SampleRate;
+
+ //
+ // The OUT endpoint in use by this instance.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The OUT endpoint DMA channel in use by this instance.
+ //
+ uint8_t ui8OUTDMA;
+
+ //
+ // The control interface number associated with this instance.
+ //
+ uint8_t ui8InterfaceControl;
+
+ //
+ // The audio interface number associated with this instance.
+ //
+ uint8_t ui8InterfaceAudio;
+
+ //
+ // A copy of the DMA instance data used with calls to USBLibDMA functions.
+ //
+ tUSBDMAInstance *psDMAInstance;
+}
+tAudioInstance;
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8IADAudioDescriptor array in bytes.
+//
+//*****************************************************************************
+#define AUDIODESCRIPTOR_SIZE (8)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8AudioControlInterface array in bytes.
+//
+//*****************************************************************************
+#define CONTROLINTERFACE_SIZE (52)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8AudioStreamInterface array in bytes.
+//
+//*****************************************************************************
+#define STREAMINTERFACE_SIZE (52)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Audio Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DAUDIO_SIZE (AUDIODESCRIPTOR_SIZE + \
+ CONTROLINTERFACE_SIZE + STREAMINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the device audio class.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! 8 byte vendor string.
+ //
+ const char pcVendor[8];
+
+ //
+ //! 16 byte vendor string.
+ //
+ const char pcProduct[16];
+
+ //
+ //! 4 byte vendor string.
+ //
+ const char pcVersion[4];
+
+ //
+ //! The maximum power consumption of the device, expressed in mA.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self or bus-powered and whether or not
+ //! it supports remote wake up. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the audio
+ //! device.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1), Audio
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (number of strings)) *
+ //! (number of languages)).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The maximum volume expressed as an 8.8 signed value.
+ //
+ const int16_t i16VolumeMax;
+
+ //
+ //! The minimum volume expressed as an 8.8 signed value.
+ //
+ const int16_t i16VolumeMin;
+
+ //
+ //! The minimum volume step expressed as an 8.8 signed value.
+ //
+ const int16_t i16VolumeStep;
+
+ //
+ //! The private instance data for the audio device.
+ //
+ tAudioInstance sPrivateData;
+}
+tUSBDAudioDevice;
+
+//*****************************************************************************
+//
+// Audio specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that the device is connected but not active.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_IDLE (USBD_AUDIO_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that the device is connected and is now
+//! active.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_ACTIVE (USBD_AUDIO_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that the device is returning a data buffer
+//! provided by the USBAudioBufferOut() function back to the application with
+//! valid audio data received from the USB host controller. The \e pvBuffer
+//! parameter holds the pointer to the buffer with the new audio data and
+//! the \e ui32Param value holds the amount of valid data in bytes that are
+//! contained in the \e pvBuffer parameter.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_DATAOUT (USBD_AUDIO_EVENT_BASE + 2)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that a volume change has occurred. The
+//! \e ui32Param value contains a signed 8.8 fixed point value that represents
+//! the current volume gain/attenuation in decibels(dB). The provided message
+//! handler should be prepared to handle negative and positive values with the
+//! value 0x8000 indicating maximum attenuation. The \e pvBuffer parameter
+//! should be ignored.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_VOLUME (USBD_AUDIO_EVENT_BASE + 4)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that a mute request has occurred. The
+//! \e ui32Param value will either be a 1 to indicate that the audio is now
+//! muted, and a value of 0 indicates that the audio has been unmuted.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_MUTE (USBD_AUDIO_EVENT_BASE + 5)
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDAudioInit(uint32_t ui32Index,
+ tUSBDAudioDevice *psAudioDevice);
+extern void *USBDAudioCompositeInit(uint32_t ui32Index,
+ tUSBDAudioDevice *psAudioDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDAudioTerm(void *pvAudioDevice);
+extern int32_t USBAudioBufferOut(void *pvAudioDevice, void *pvBuffer,
+ uint32_t ui32Size,
+ tUSBAudioBufferCallback pfnCallback);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/usblib/device/usbdbulk.c b/usblib/device/usbdbulk.c new file mode 100644 index 0000000..1e4cf0b --- /dev/null +++ b/usblib/device/usbdbulk.c @@ -0,0 +1,1562 @@ +//*****************************************************************************
+//
+// usbdbulk.c - USB bulk device class driver.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdbulk.h"
+#include "usblib/device/usbdcomp.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bulk_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// Flags that may appear in ui16DeferredOpFlags to indicate some operation that
+// has been requested but could not be processed at the time it was received.
+// Each deferred operation is defined as the bit number that should be set in
+// tBulkInstance->ui16DeferredOpFlags to indicate that the operation is
+// pending.
+//
+//*****************************************************************************
+#define BULK_DO_PACKET_RX 5
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.'
+//
+//*****************************************************************************
+#define DATA_IN_ENDPOINT USB_EP_1
+#define DATA_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// Maximum packet size for the bulk endpoints used for bulk data
+// transmission and reception and the associated FIFO sizes to set aside
+// for each endpoint.
+//
+//*****************************************************************************
+#define DATA_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define DATA_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
+
+#define DATA_IN_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE)
+#define DATA_OUT_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_OUT_EP_FIFO_SIZE)
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8BulkDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_VEND_SPECIFIC, // USB Device Class
+ 0, // USB Device Sub-class
+ 0, // USB Device protocol
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (VID).
+ USBShort(0), // Product ID (PID).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Bulk device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8BulkDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(32), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const uint8_t g_pui8BulkInterface[BULKINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 2, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_VEND_SPECIFIC, // The interface class
+ 0, // The interface sub-class.
+ 0, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The bulk configuration descriptor is defined as two sections, one
+// containing just the 9 byte USB configuration descriptor and the other
+// containing everything else that is sent to the host along with it.
+//
+//*****************************************************************************
+const tConfigSection g_sBulkConfigSection =
+{
+ sizeof(g_pui8BulkDescriptor),
+ g_pui8BulkDescriptor
+};
+
+const tConfigSection g_sBulkInterfaceSection =
+{
+ sizeof(g_pui8BulkInterface),
+ g_pui8BulkInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete bulk device configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psBulkSections[] =
+{
+ &g_sBulkConfigSection,
+ &g_sBulkInterfaceSection
+};
+
+#define NUM_BULK_SECTIONS (sizeof(g_psBulkSections) / \
+ sizeof(g_psBulkSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sBulkConfigHeader =
+{
+ NUM_BULK_SECTIONS,
+ g_psBulkSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppBulkConfigDescriptors[] =
+{
+ &g_sBulkConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleConfigChange(void *pvBulkDevice, uint32_t ui32Info);
+static void HandleDisconnect(void *pvBulkDevice);
+static void HandleEndpoints(void *pvBulkDevice, uint32_t ui32Status);
+static void HandleSuspend(void *pvBulkDevice);
+static void HandleResume(void *pvBulkDevice);
+static void HandleDevice(void *pvBulkDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// Device event handler callbacks.
+//
+//*****************************************************************************
+const tCustomHandlers g_sBulkHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ 0,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ HandleConfigChange,
+
+ //
+ // DataReceived
+ //
+ 0,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ HandleSuspend,
+
+ //
+ // ResumeHandler
+ //
+ HandleResume,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pui16DeferredOp points to the flags variable which is to be modified.
+// \param ui16Bit indicates which bit number is to be set or cleared.
+// \param bSet indicates the state that the flag must be set to. If \b true,
+// the flag is set, if \b false, the flag is cleared.
+//
+// This function safely sets or clears a bit in a flag variable. The operation
+// makes use of bitbanding to ensure that the operation is atomic (no read-
+// modify-write is required).
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
+ bool bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psBulkDevice is the device instance whose endpoint is to be
+// processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts signaling
+// the arrival of data on the bulk OUT endpoint (in other words, whenever the
+// host has sent us a packet of data). We inform the client that a packet
+// is available and, on return, check to see if the packet has been read. If
+// not, we schedule another notification to the client for a later time.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataFromHost(tUSBDBulkDevice *psBulkDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus;
+ uint32_t ui32Size;
+ tBulkInstance *psInst;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Set the flag we use to indicate that a packet read is pending. This
+ // will be cleared if the packet is read. If the client does not read
+ // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
+ // the event will be signaled later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, BULK_DO_PACKET_RX,
+ true);
+
+ //
+ // How big is the packet we have just received?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // The receive channel is not blocked so let the caller know
+ // that a packet is waiting. The parameters are set to indicate
+ // that the packet has not been read from the hardware FIFO yet.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE,
+ ui32Size, (void *)0);
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ui32EPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so allow the callback
+ // to handle it.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ui32EPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psBulkDevice is the device instance whose endpoint is to be
+// processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the bulk IN endpoint (in other words, whenever data has been
+// transmitted to the USB host). We examine the cause of the interrupt and,
+// if due to completion of a transmission, notify the client.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataToHost(tUSBDBulkDevice *psBulkDevice, uint32_t ui32Status)
+{
+ tBulkInstance *psInst;
+ uint32_t ui32EPStatus, ui32Size;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8INEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase, psInst->ui8INEndpoint,
+ ui32EPStatus);
+
+ //
+ // Our last transmission completed. Clear our state back to idle and
+ // see if we need to send any more data.
+ //
+ psInst->iBulkTxState = eBulkStateIdle;
+
+ //
+ // Notify the client that the last transmission completed.
+ //
+ ui32Size = psInst->ui16LastTxSize;
+ psInst->ui16LastTxSize = 0;
+ psBulkDevice->pfnTxCallback(psBulkDevice->pvTxCBData,
+ USB_EVENT_TX_COMPLETE, ui32Size, (void *)0);
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack for any activity involving one of our endpoints
+// other than EP0. This function is a fan out that merely directs the call to
+// the correct handler depending upon the endpoint and transaction direction
+// signaled in ui32Status.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvBulkDevice, uint32_t ui32Status)
+{
+ tUSBDBulkDevice *psBulkDevice;
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(psBulkDevice, ui32Status);
+ }
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint)))
+ {
+ ProcessDataToHost(psBulkDevice, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvBulkDevice, uint32_t ui32Info)
+{
+ tBulkInstance *psInst;
+ tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->iBulkRxState = eBulkStateIdle;
+ psInst->iBulkTxState = eBulkStateIdle;
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvBulkDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tBulkInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDBulkDevice *psBulkDevice;
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB Bulk
+ // class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_LPM_SLEEP, 0, (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_LPM_ERROR, 0, (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvBulkDevice)
+{
+ tUSBDBulkDevice *psBulkDevice;
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(psInst->bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psInst->bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvBulkDevice)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_SUSPEND, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is taken
+// out of suspend state.
+//
+//*****************************************************************************
+static void
+HandleResume(void *pvBulkDevice)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_RESUME, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called periodically and provides us with a time reference
+// and method of implementing delayed or time-dependent operations.
+//
+// \param ui32Index is the index of the USB controller for which this tick
+// is being generated.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+BulkTickHandler(void *pvBulkDevice, uint32_t ui32TimemS)
+{
+ tBulkInstance *psInst;
+ uint32_t ui32Size;
+ tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << BULK_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Tell the client that there is a packet waiting for it.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes bulk device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for bulk device operation.
+//! \param psBulkDevice points to a structure containing parameters customizing
+//! the operation of the bulk device.
+//!
+//! An application wishing to make use of a USB bulk communication channel
+//! must call this function to initialize the USB controller and attach the
+//! device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function will return the \e psBulkDevice
+//! pointer passed to it. This must be passed on all future calls to the
+//! device driver related to this device.
+//!
+//! The USBDBulk interface offers packet-based transmit and receive operation.
+//! If the application would rather use block based communication with
+//! transmit and receive buffers, USB buffers may be used above the bulk
+//! transmit and receive channels to offer this functionality.
+//!
+//! Transmit Operation:
+//!
+//! Calls to USBDBulkPacketWrite() must send no more than 64 bytes of data at a
+//! time and may only be made when no other transmission is currently
+//! outstanding.
+//!
+//! Once a packet of data has been acknowledged by the USB host, a
+//! \b USB_EVENT_TX_COMPLETE event is sent to the application callback to
+//! inform it that another packet may be transmitted.
+//!
+//! Receive Operation:
+//!
+//! An incoming USB data packet will result in a call to the application
+//! callback with event \b USBD_EVENT_RX_AVAILABLE. The application must then
+//! call USBDBulkPacketRead(), passing a buffer capable of holding 64 bytes, to
+//! retrieve the data and acknowledge reception to the USB host.
+//!
+//! \note The application must not make any calls to the low level USB Device
+//! API if interacting with USB via the USB bulk device class API. Doing so
+//! will cause unpredictable (though almost certainly unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or void pointer that should be used with
+//! the remaining USB bulk class APSs.
+//
+//*****************************************************************************
+void *
+USBDBulkInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice)
+{
+ void *pvBulkDevice;
+ tDeviceDescriptor *psDevDesc;
+ tConfigDescriptor *psConfigDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psBulkDevice);
+
+ pvBulkDevice = USBDBulkCompositeInit(ui32Index, psBulkDevice, 0);
+
+ if(pvBulkDevice)
+ {
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8BulkDeviceDescriptor;
+ psDevDesc->idVendor = psBulkDevice->ui16VID;
+ psDevDesc->idProduct = psBulkDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psConfigDesc = (tConfigDescriptor *)g_pui8BulkDescriptor;
+ psConfigDesc->bmAttributes = psBulkDevice->ui8PwrAttributes;
+ psConfigDesc->bMaxPower = (uint8_t)(psBulkDevice->ui16MaxPowermA / 2);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psBulkDevice->sPrivateData.sDevInfo,
+ (void *)psBulkDevice);
+ }
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return(pvBulkDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes bulk device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for bulk device operation.
+//! \param psBulkDevice points to a structure containing parameters customizing
+//! the operation of the bulk device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDBulkInit() except that it is used for
+//! initializing an instance of the bulk device for use in a composite device.
+//! When this bulk device is part of a composite device, then the
+//! \e psCompEntry should point to the composite device entry to initialize.
+//! This is part of the array that is passed to the USBDCompositeInit()
+//! function.
+//!
+//! \return Returns zero on failure or a non-zero value that should be
+//! used with the remaining USB Bulk APIs.
+//
+//*****************************************************************************
+void *
+USBDBulkCompositeInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tBulkInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psBulkDevice);
+ ASSERT(psBulkDevice->ppui8StringDescriptors);
+ ASSERT(psBulkDevice->pfnRxCallback);
+ ASSERT(psBulkDevice->pfnTxCallback);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psBulkDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sBulkHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8BulkDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppBulkConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Set the basic state information for the class.
+ //
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->iBulkRxState = eBulkStateUnconfigured;
+ psInst->iBulkTxState = eBulkStateUnconfigured;
+ psInst->ui16DeferredOpFlags = 0;
+ psInst->bConnected = false;
+
+ //
+ // Initialize the device info structure for the Bulk device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ui8INEndpoint = DATA_IN_ENDPOINT;
+ psInst->ui8OUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ui8Interface = 0;
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psBulkDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psBulkDevice->ui32NumStringDescriptors;
+
+ //
+ // Initialize the USB tick module, this will prevent it from being
+ // initialized later in the call to USBDCDInit();
+ //
+ InternalUSBTickInit();
+
+ //
+ // Register our tick handler (this must be done after USBDCDInit).
+ //
+ InternalUSBRegisterTickHandler(BulkTickHandler, (void *)psBulkDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psBulkDevice);
+}
+
+//*****************************************************************************
+//
+//! Shut down the bulk device.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//!
+//! This function terminates device operation for the instance supplied and
+//! removes the device from the USB bus. This function should not be called
+//! if the bulk device is part of a composite device and instead the
+//! USBDCompositeTerm() function should be called for the full composite
+//! device.
+//!
+//! Following this call, the \e pvBulkDevice instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDBulkTerm(void *pvBulkDevice)
+{
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase));
+
+ psInst->ui32USBBase = 0;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the receive channel
+//! callback.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the receive channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnRxCallback function
+//! passed on USBDBulkInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the \e pvBulkDevice structure passed to USBDBulkInit() resides
+//! in RAM. If this structure is in flash, callback pointer changes are not
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's receive callback.
+//
+//*****************************************************************************
+void *
+USBDBulkSetRxCBData(void *pvBulkDevice, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDBulkDevice *)pvBulkDevice)->pvRxCBData;
+ ((tUSBDBulkDevice *)pvBulkDevice)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the transmit callback.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the transmit channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnTxCallback function
+//! passed on USBDBulkInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the \e pvBulkDevice structure passed to USBDBulkInit() resides
+//! in RAM. If this structure is in flash, callback pointer changes are not
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's transmit callback.
+//
+//*****************************************************************************
+void *
+USBDBulkSetTxCBData(void *pvBulkDevice, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Set the callback pointer for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDBulkDevice *)pvBulkDevice)->pvTxCBData;
+ ((tUSBDBulkDevice *)pvBulkDevice)->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a packet of data to the USB host via the bulk data interface.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pi8Data points to the first byte of data which is to be transmitted.
+//! \param ui32Length is the number of bytes of data to transmit.
+//! \param bLast indicates whether more data is to be written before a packet
+//! should be scheduled for transmission. If \b true, the client will make
+//! a further call to this function. If \b false, no further call will be
+//! made and the driver should schedule transmission of a short packet.
+//!
+//! This function schedules the supplied data for transmission to the USB
+//! host in a single USB packet. If no transmission is currently ongoing,
+//! the data is immediately copied to the relevant USB endpoint FIFO for
+//! transmission. Whenever a USB packet is acknowledged by the host, a
+//! \b USB_EVENT_TX_COMPLETE event will be sent to the transmit channel
+//! callback indicating that more data can now be transmitted.
+//!
+//! The maximum value for \e ui32Length is 64 bytes (the maximum USB packet
+//! size for the bulk endpoints in use by the device). Attempts to send more
+//! data than this will result in a return code of 0 indicating that the data
+//! cannot be sent.
+//!
+//! The \e bLast parameter allows a client to make multiple calls to this
+//! function before scheduling transmission of the packet to the host. This
+//! can be helpful if, for example, constructing a packet on the fly or
+//! writing a packet which spans the wrap point in a ring buffer.
+//!
+//! \return Returns the number of bytes actually sent. At this level, this
+//! will either be the number of bytes passed (if less than or equal to the
+//! maximum packet size for the USB endpoint in use and no outstanding
+//! transmission ongoing) or 0 to indicate a failure.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkPacketWrite(void *pvBulkDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ tBulkInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Can we send the data provided?
+ //
+ if((ui32Length > DATA_IN_EP_MAX_SIZE) ||
+ (psInst->iBulkTxState != eBulkStateIdle))
+ {
+ //
+ // Either the packet was too big or we are in the middle of sending
+ // another packet. Return 0 to indicate that we can't send this data.
+ //
+ return(0);
+ }
+
+ //
+ // Copy the data into the USB endpoint FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8INEndpoint,
+ pi8Data, ui32Length);
+
+ //
+ // Did we copy the data successfully?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // Remember how many bytes we sent.
+ //
+ psInst->ui16LastTxSize += (uint16_t)ui32Length;
+
+ //
+ // If this is the last call for this packet, schedule transmission.
+ //
+ if(bLast)
+ {
+ //
+ // Send the packet to the host if we have received all the data we
+ // can expect for this packet.
+ //
+ psInst->iBulkTxState = eBulkStateWaitData;
+ i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ui32Length);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we could not send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the bulk data
+//! interface.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pi8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by pi8Data.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to \e ui32Length bytes of data received from the USB
+//! host into the supplied application buffer. If the driver detects that the
+//! entire packet has been read, it is acknowledged to the host.
+//!
+//! The \e bLast parameter is ignored in this implementation since the end of
+//! a packet can be determined without relying upon the client to provide
+//! this information.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkPacketRead(void *pvBulkDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ uint32_t ui32EPStatus, ui32Count, ui32Pkt;
+ tBulkInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // How many bytes are available for us to receive?
+ //
+ ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ui32Count = ui32Length;
+ i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ pi8Data, &ui32Count);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ui32Count == ui32Pkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint, true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, BULK_DO_PACKET_RX,
+ false);
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(i32Retcode != -1)
+ {
+ return(ui32Count);
+ }
+ }
+
+ //
+ // No packet was available or an error occurred while reading so tell
+ // the caller no bytes were returned.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the transmit buffer.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//!
+//! This function returns the maximum number of bytes that can be passed on a
+//! call to USBDBulkPacketWrite() and accepted for transmission. The value
+//! returned will be the maximum USB packet size (64) if no transmission is
+//! currently outstanding or 0 if a transmission is in progress.
+//!
+//! \return Returns the number of bytes available in the transmit buffer.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkTxPacketAvailable(void *pvBulkDevice)
+{
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->iBulkTxState != eBulkStateIdle)
+ {
+ //
+ // We are not ready to receive a new packet so return 0.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // We can receive a packet so return the max packet size for the
+ // relevant endpoint.
+ //
+ return(DATA_IN_EP_MAX_SIZE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//!
+//! This function may be used to determine if a received packet remains to be
+//! read and allows the application to determine the buffer size needed to
+//! read the data.
+//!
+//! \return Returns 0 if no received packet remains unprocessed or the
+//! size of the packet if a packet is waiting to be read.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkRxPacketAvailable(void *pvBulkDevice)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvBulkDevice is the pointer to the bulk device instance structure.
+//! \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 USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDBulkPowerStatusSet(void *pvBulkDevice, uint8_t ui8Power)
+{
+ ASSERT(pvBulkDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvBulkDevice is the pointer to the bulk device instance structure.
+//!
+//! 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
+USBDBulkRemoteWakeupRequest(void *pvBulkDevice)
+{
+ ASSERT(pvBulkDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDCDRemoteWakeupRequest(0));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdbulk.h b/usblib/device/usbdbulk.h new file mode 100644 index 0000000..0f6887d --- /dev/null +++ b/usblib/device/usbdbulk.h @@ -0,0 +1,300 @@ +//*****************************************************************************
+//
+// usbdcdc.h - USBLib support for a generic bulk device.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDBULK_H__
+#define __USBDBULK_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup bulk_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB Bulk example code and are here only to help with the application
+// allocating the correct amount of memory for the Bulk example device code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Not configured.
+ //
+ eBulkStateUnconfigured,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ eBulkStateIdle,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ eBulkStateWaitData,
+
+ //
+ // Waiting for client to process data.
+ //
+ eBulkStateWaitClient
+}
+tBulkState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// Bulk only example device. The memory for this structure is inlcluded in
+// the sPrivateData field in the tUSBDBulkDevice structure passed on
+// USBDBulkInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The state of the bulk receive channel.
+ //
+ volatile tBulkState iBulkRxState;
+
+ //
+ // The state of the bulk transmit channel.
+ //
+ volatile tBulkState iBulkTxState;
+
+ //
+ // State of any pending operations that could not be handled immediately
+ // upon receipt.
+ //
+ volatile uint16_t ui16DeferredOpFlags;
+
+ //
+ // Size of the last transmit.
+ //
+ uint16_t ui16LastTxSize;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8INEndpoint;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The bulk class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+}
+tBulkInstance;
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8BulkInterface array in bytes.
+//
+//*****************************************************************************
+#define BULKINTERFACE_SIZE (23)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Bulk Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DBULK_SIZE (BULKINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the bulk device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data receive channel.
+ //
+ const tUSBCallback pfnRxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the receive channel callback,
+ //! pfnRxCallback.
+ //
+ void *pvRxCBData;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data transmit
+ //! channel.
+ //
+ const tUSBCallback pfnTxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the transmit channel callback,
+ //! pfnTxCallback.
+ //
+ void *pvTxCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain pointers to the following string descriptors in this
+ //! order. Language descriptor, Manufacturer name string (language 1),
+ //! Product name string (language 1), Serial number string (language 1),
+ //! Interface description string (language 1) and Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the strings for indices 1 through 5
+ //! must be repeated for each of the other languages defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors array.
+ //! This must be 1 + (5 * number of supported languages).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! not be modified by any code outside the bulk class driver.
+ //
+ tBulkInstance sPrivateData;
+}
+tUSBDBulkDevice;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDBulkInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice);
+extern void *USBDBulkCompositeInit(uint32_t ui32Index,
+ tUSBDBulkDevice *psBulkDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDBulkTerm(void *pvBulkInstance);
+extern void *USBDBulkSetRxCBData(void *pvBulkInstance, void *pvCBData);
+extern void *USBDBulkSetTxCBData(void *pvBulkInstance, void *pvCBData);
+extern uint32_t USBDBulkPacketWrite(void *pvBulkInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDBulkPacketRead(void *pvBulkInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDBulkTxPacketAvailable(void *pvBulkInstance);
+extern uint32_t USBDBulkRxPacketAvailable(void *pvBulkInstance);
+extern bool USBDBulkRemoteWakeupRequest(void *pvBulkInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+extern void USBDBulkPowerStatusSet(void *pvBulkInstance, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDBULK_H__
diff --git a/usblib/device/usbdcdc.c b/usblib/device/usbdcdc.c new file mode 100644 index 0000000..a4dc73a --- /dev/null +++ b/usblib/device/usbdcdc.c @@ -0,0 +1,3043 @@ +//*****************************************************************************
+//
+// usbdcdc.c - USB CDC ACM (serial) device class driver.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usbcdc.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdcomp.h"
+#include "usblib/device/usbdcdc.h"
+
+//*****************************************************************************
+//
+//! \addtogroup cdc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Some assumptions and deviations from the CDC specification
+// ----------------------------------------------------------
+//
+// 1. Although the CDC specification indicates that the following requests
+// should be supported by ACM CDC devices, these don't seem relevant to a
+// virtual COM port implementation and are never seen when connecting to a
+// Windows host and running either Hyperterminal or TeraTerm. As a result,
+// this implementation does not support them and stalls endpoint 0 if they are
+// received.
+// - SEND_ENCAPSULATED_COMMAND
+// - GET_ENCAPSULATED_RESPONSE
+// - SET_COMM_FEATURE
+// - GET_COMM_FEATURE
+// - CLEAR_COMM_FEATURE
+//
+// 2. The CDC specification is very clear on the fact that an ACM device
+// should offer two interfaces - a control interface offering an interrupt IN
+// endpoint and a data interface offering bulk IN and OUT endpoints. Using
+// this descriptor configuration, however, Windows insists on enumerating the
+// device as two separate entities resulting in two virtual COM ports or one
+// COM port and an Unknown Device (depending upon INF contents) appearing
+// in Device Manager. This implementation, derived by experimentation and
+// examination of other virtual COM and CDC solutions, uses only a single
+// interface combining all three endpoints. This appears to satisfy
+// Windows2000, XP and Vista and operates as intended using the Hyperterminal
+// and TeraTerm terminal emulators. Your mileage may vary with other
+// (untested) operating systems!
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// Size of the buffer to hold request-specific data read from the host. This
+// must be sized to accommodate the largest request structure that we intend
+// processing.
+//
+//*****************************************************************************
+#define MAX_REQUEST_DATA_SIZE sizeof(tLineCoding)
+
+//*****************************************************************************
+//
+// Flags that may appear in ui16DeferredOpFlags to indicate some operation that
+// has been requested but could not be processed at the time it was received.
+//
+//*****************************************************************************
+#define CDC_DO_SERIAL_STATE_CHANGE \
+ 0
+#define CDC_DO_SEND_BREAK 1
+#define CDC_DO_CLEAR_BREAK 2
+#define CDC_DO_LINE_CODING_CHANGE \
+ 3
+#define CDC_DO_LINE_STATE_CHANGE \
+ 4
+#define CDC_DO_PACKET_RX 5
+
+//*****************************************************************************
+//
+// The subset of deferred operations which result in the receive channel
+// being blocked.
+//
+//*****************************************************************************
+#define RX_BLOCK_OPS ((1 << CDC_DO_SEND_BREAK) | \
+ (1 << CDC_DO_LINE_CODING_CHANGE) | \
+ (1 << CDC_DO_LINE_STATE_CHANGE))
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define CONTROL_ENDPOINT USB_EP_1
+#define DATA_IN_ENDPOINT USB_EP_2
+#define DATA_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// The following are the USB interface numbers for the CDC serial device.
+//
+//*****************************************************************************
+#define SERIAL_INTERFACE_CONTROL \
+ 0
+#define SERIAL_INTERFACE_DATA 1
+
+//*****************************************************************************
+//
+// Maximum packet size for the bulk endpoints used for serial data
+// transmission and reception and the associated FIFO sizes to set aside
+// for each endpoint.
+//
+//*****************************************************************************
+#define DATA_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define DATA_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define CTL_IN_EP_FIFO_SIZE USB_FIFO_SZ_16
+
+#define DATA_IN_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE)
+#define DATA_OUT_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE)
+#define CTL_IN_EP_MAX_SIZE USBFIFOSizeToBytes(CTL_IN_EP_FIFO_SIZE)
+
+//*****************************************************************************
+//
+// The collection of serial state flags indicating character errors.
+//
+//*****************************************************************************
+#define USB_CDC_SERIAL_ERRORS (USB_CDC_SERIAL_STATE_OVERRUN | \
+ USB_CDC_SERIAL_STATE_PARITY | \
+ USB_CDC_SERIAL_STATE_FRAMING)
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8CDCSerDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts
+ // assume high-speed - see USB 2.0 spec
+ // 9.2.6.6)
+ USB_CLASS_CDC, // USB Device Class (spec 5.1.1)
+ 0, // USB Device Sub-class (spec 5.1.1)
+ USB_CDC_PROTOCOL_NONE, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during
+ // USBDCDCInit).
+ USBShort(0), // Product ID (filled in during
+ // USBDCDCInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// CDC Serial configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8CDCSerDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(9), // The total size of this full structure,
+ // this will be patched so it is just set
+ // to the size of this structure.
+ 2, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes
+ // this configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake
+ // up.
+ 250, // The maximum power in 2mA increments.
+};
+
+const tConfigSection g_sCDCSerConfigSection =
+{
+ sizeof(g_pui8CDCSerDescriptor),
+ g_pui8CDCSerDescriptor
+};
+
+//*****************************************************************************
+//
+// This is the Interface Association Descriptor for the serial device used in
+// composite devices.
+//
+//*****************************************************************************
+uint8_t g_pui8IADSerDescriptor[SERDESCRIPTOR_SIZE] =
+{
+
+ 8, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE_ASC, // Interface Association Type.
+ 0x0, // Default starting interface is 0.
+ 0x2, // Number of interfaces in this
+ // association.
+ USB_CLASS_CDC, // The device class for this association.
+ USB_CDC_SUBCLASS_ABSTRACT_MODEL,
+ // The device subclass for this
+ // association.
+ USB_CDC_PROTOCOL_V25TER, // The protocol for this association.
+ 0 // The string index for this association.
+};
+
+const tConfigSection g_sIADSerConfigSection =
+{
+ sizeof(g_pui8IADSerDescriptor),
+ g_pui8IADSerDescriptor
+};
+
+//*****************************************************************************
+//
+// This is the control interface for the serial device.
+//
+//*****************************************************************************
+const uint8_t g_pui8CDCSerCommInterface[SERCOMMINTERFACE_SIZE] =
+{
+ //
+ // Communication Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ SERIAL_INTERFACE_CONTROL, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_CDC, // The interface class constant defined by
+ // USB-IF (spec 5.1.3).
+ USB_CDC_SUBCLASS_ABSTRACT_MODEL,
+ // The interface sub-class constant
+ // defined by USB-IF (spec 5.1.3).
+ USB_CDC_PROTOCOL_V25TER, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+
+ //
+ // Communication Class Interface Functional Descriptor - Header
+ //
+ 5, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_HEADER, // Header functional descriptor
+ USBShort(0x110), // Complies with CDC version 1.1
+
+ //
+ // Communication Class Interface Functional Descriptor - ACM
+ //
+ 4, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_ABSTRACT_CTL_MGMT,
+ USB_CDC_ACM_SUPPORTS_LINE_PARAMS | USB_CDC_ACM_SUPPORTS_SEND_BREAK,
+
+ //
+ // Communication Class Interface Functional Descriptor - Unions
+ //
+ 5, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_UNION,
+ SERIAL_INTERFACE_CONTROL,
+ SERIAL_INTERFACE_DATA, // Data interface number
+
+ //
+ // Communication Class Interface Functional Descriptor - Call Management
+ //
+ 5, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_CALL_MGMT,
+ USB_CDC_CALL_MGMT_HANDLED,
+ SERIAL_INTERFACE_DATA, // Data interface number
+
+ //
+ // Endpoint Descriptor (interrupt, IN)
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(CONTROL_ENDPOINT),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(CTL_IN_EP_MAX_SIZE), // The maximum packet size.
+ 1 // The polling interval for this endpoint.
+};
+
+const tConfigSection g_sCDCSerCommInterfaceSection =
+{
+ sizeof(g_pui8CDCSerCommInterface),
+ g_pui8CDCSerCommInterface
+};
+
+//*****************************************************************************
+//
+// This is the Data interface for the serial device.
+//
+//*****************************************************************************
+const uint8_t g_pui8CDCSerDataInterface[SERDATAINTERFACE_SIZE] =
+{
+ //
+ // Communication Class Data Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ SERIAL_INTERFACE_DATA, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 2, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_CDC_DATA, // The interface class constant defined by
+ // USB-IF (spec 5.1.3).
+ 0, // The interface sub-class constant
+ // defined by USB-IF (spec 5.1.3).
+ USB_CDC_PROTOCOL_NONE, // The interface protocol for the sub-class
+ // specified above.
+ 0, // The string index for this interface.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+};
+
+const tConfigSection g_sCDCSerDataInterfaceSection =
+{
+ sizeof(g_pui8CDCSerDataInterface),
+ g_pui8CDCSerDataInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete CDC ACM configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psCDCSerSections[] =
+{
+ &g_sCDCSerConfigSection,
+ &g_sCDCSerCommInterfaceSection,
+ &g_sCDCSerDataInterfaceSection,
+};
+
+#define NUM_CDCSER_SECTIONS (sizeof(g_psCDCSerSections) / \
+ sizeof(g_psCDCSerSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration. This is the root of the data
+// structure that defines all the bits and pieces that are pulled together to
+// generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sCDCSerConfigHeader =
+{
+ NUM_CDCSER_SECTIONS,
+ g_psCDCSerSections
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete CDC ACM configuration descriptor used in composite devices.
+// The only addition is the g_sIADSerConfigSection.
+//
+//*****************************************************************************
+const tConfigSection *g_psCDCCompSerSections[] =
+{
+ &g_sCDCSerConfigSection,
+ &g_sIADSerConfigSection,
+ &g_sCDCSerCommInterfaceSection,
+ &g_sCDCSerDataInterfaceSection,
+};
+
+#define NUM_COMP_CDCSER_SECTIONS (sizeof(g_psCDCCompSerSections) / \
+ sizeof(g_psCDCCompSerSections[0]))
+
+//*****************************************************************************
+//
+// The header for the composite configuration. This is the root of the data
+// structure that defines all the bits and pieces that are pulled together to
+// generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sCDCCompSerConfigHeader =
+{
+ NUM_COMP_CDCSER_SECTIONS,
+ g_psCDCCompSerSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor for the CDC serial class device.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppCDCSerConfigDescriptors[] =
+{
+ &g_sCDCSerConfigHeader
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor for the CDC serial class device used in a composite
+// device.
+//
+//*****************************************************************************
+const tConfigHeader * const g_pCDCCompSerConfigDescriptors[] =
+{
+ &g_sCDCCompSerConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleRequests(void *pvCDCDevice, tUSBRequest *pUSBRequest);
+static void HandleConfigChange(void *pvCDCDevice, uint32_t ui32Info);
+static void HandleEP0Data(void *pvCDCDevice, uint32_t ui32DataSize);
+static void HandleDisconnect(void *pvCDCDevice);
+static void HandleEndpoints(void *pvCDCDevice, uint32_t ui32Status);
+static void HandleSuspend(void *pvCDCDevice);
+static void HandleResume(void *pvCDCDevice);
+static void HandleDevice(void *pvCDCDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB serial device.
+//
+//*****************************************************************************
+const tCustomHandlers g_sCDCHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ HandleConfigChange,
+
+ //
+ // DataReceived
+ //
+ HandleEP0Data,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ HandleSuspend,
+
+ //
+ // ResumeHandler
+ //
+ HandleResume,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler.
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pui16DeferredOp points to the flags variable which is to be modified.
+// \param ui16Bit indicates which bit number is to be set or cleared.
+// \param bSet indicates the state that the flag must be set to. If \b true,
+// the flag is set, if \b false, the flag is cleared.
+//
+// This function safely sets or clears a bit in a flag variable. The operation
+// makes use of bitbanding to ensure that the operation is atomic (no read-
+// modify-write is required).
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
+ bool bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// Determines whether or not a client has consumed all received data previously
+// passed to it.
+//
+//! \param psCDCDevice is the pointer to the device instance structure as returned
+//! by USBDCDCInit().
+//
+// This function is called to determine whether or not a device has consumed
+// all data previously passed to it via its receive callback.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+DeviceConsumedAllData(const tUSBDCDCDevice *psCDCDevice)
+{
+ uint32_t ui32Remaining;
+
+ //
+ // Send the device an event requesting that it tell us how many bytes
+ // of data it still has to process.
+ //
+ ui32Remaining = psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData,
+ USB_EVENT_DATA_REMAINING, 0, (void *)0);
+
+ //
+ // If any data remains to be processed, return false, else return true.
+ //
+ return(ui32Remaining ? false : true);
+}
+
+//*****************************************************************************
+//
+// Notifies the client that it should set or clear a break condition.
+//
+// \param psCDCDevice is the pointer to the device instance structure as returned
+// by USBDCDCInit().
+// \param bSend is \b true if a break condition is to be set or \b false if
+// it is to be cleared.
+//
+// This function is called to instruct the client to start or stop sending a
+// break condition on its serial transmit line.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static void
+SendBreak(tUSBDCDCDevice *psCDCDevice, bool bSend)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Set the break state flags as necessary. If we are turning the break on,
+ // set the flag to tell ourselves that we need to notify the client when
+ // it is time to turn it off again.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_SEND_BREAK, false);
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_CLEAR_BREAK, bSend);
+
+ //
+ // Tell the client to start or stop sending the break.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ (bSend ? USBD_CDC_EVENT_SEND_BREAK :
+ USBD_CDC_EVENT_CLEAR_BREAK), 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a host request to set the serial communication
+// parameters.
+//
+// \param psCDCDevice is the device instance whose communication parameters are to
+// be set.
+//
+// This function is called to notify the client when the host requests a change
+// in the serial communication parameters (baud rate, parity, number of bits
+// per character and number of stop bits) to use.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SendLineCodingChange(tUSBDCDCDevice *psCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Clear the flag we use to tell ourselves that the line coding change has
+ // yet to be notified to the client.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_LINE_CODING_CHANGE,
+ false);
+
+ //
+ // Tell the client to update their serial line coding parameters.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USBD_CDC_EVENT_SET_LINE_CODING, 0,
+ &(psInst->sLineCoding));
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a host request to set the RTS and DTR handshake line
+// states.
+//
+// \param psCDCDevice is the device instance whose break condition is to be set or
+// cleared.
+//
+// This function is called to notify the client when the host requests a change
+// in the state of one or other of the RTS and DTR handshake lines.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SendLineStateChange(tUSBDCDCDevice *psCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Clear the flag we use to tell ourselves that the line coding change has
+ // yet to be notified to the client.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_LINE_STATE_CHANGE,
+ false);
+
+ //
+ // Tell the client to update their serial line coding parameters.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USBD_CDC_EVENT_SET_CONTROL_LINE_STATE,
+ psInst->ui16ControlLineState,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a break request if no data remains to be processed.
+//
+// \param psCDCDevice is the device instance that is to be commanded to send a
+// break condition.
+//
+// This function is called when the host requests that the device set a break
+// condition on the serial transmit line. If no data received from the host
+// remains to be processed, the break request is passed to the control
+// callback. If data is outstanding, the call is ignored (with the operation
+// being retried on the next timer tick).
+//
+// \return Returns \b true if the break notification was sent, \b false
+// otherwise.
+//
+//*****************************************************************************
+static bool
+CheckAndSendBreak(tUSBDCDCDevice *psCDCDevice, uint16_t ui16Duration)
+{
+ bool bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the break request on to the client since no data remains to be
+ // consumed.
+ //
+ SendBreak(psCDCDevice, (ui16Duration ? true : false));
+ }
+
+ //
+ // Tell the caller whether or not we sent the notification.
+ //
+ return(bCanSend);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a request to change the serial line parameters if no
+// data remains to be processed.
+//
+// \param psCDCDevice is the device instance whose line coding parameters are to
+// be changed.
+//
+// This function is called when the host requests that the device change the
+// serial line coding parameters. If no data received from the host remains
+// to be processed, the request is passed to the control callback. If data is
+// outstanding, the call is ignored (with the operation being retried on the
+// next timer tick).
+//
+// \return Returns \b true if the notification was sent, \b false otherwise.
+//
+//*****************************************************************************
+static bool
+CheckAndSendLineCodingChange(tUSBDCDCDevice *psCDCDevice)
+{
+ bool bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the request on to the client since no data remains to be
+ // consumed.
+ //
+ SendLineCodingChange(psCDCDevice);
+ }
+
+ //
+ // Tell the caller whether or not we sent the notification.
+ //
+ return(bCanSend);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a request to change the handshake line states if no
+// data remains to be processed.
+//
+// \param psCDCDevice is the device instance whose handshake line states are to
+// be changed.
+//
+// This function is called when the host requests that the device change the
+// state of one or other of the RTS or DTR handshake lines. If no data
+// received from the host remains to be processed, the request is passed to
+// the control callback. If data is outstanding, the call is ignored (with
+// the operation being retried on the next timer tick).
+//
+// \return Returns \b true if the notification was sent, \b false otherwise.
+//
+//*****************************************************************************
+static bool
+CheckAndSendLineStateChange(tUSBDCDCDevice *psCDCDevice)
+{
+ bool bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the request on to the client since no data remains to be
+ // consumed.
+ //
+ SendLineStateChange(psCDCDevice);
+ }
+
+ //
+ // Tell the caller whether or not we sent the notification.
+ //
+ return(bCanSend);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a change in the serial line state.
+//
+// \param psInst is the instance whose serial state is to be reported.
+//
+// This function is called to send the current serial state information to
+// the host via the the interrupt IN endpoint. This notification informs the
+// host of problems or conditions such as parity errors, breaks received,
+// framing errors, etc.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+SendSerialState(tUSBDCDCDevice *psCDCDevice)
+{
+ tUSBRequest sRequest;
+ uint16_t ui16SerialState;
+ tCDCSerInstance *psInst;
+ int32_t i32Retcode;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Remember that we are in the middle of sending a notification.
+ //
+ psInst->iCDCInterruptState = eCDCStateWaitData;
+
+ //
+ // Clear the flag we use to indicate that a send is required.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
+ false);
+ //
+ // Take a snapshot of the serial state.
+ //
+ ui16SerialState = psInst->ui16SerialState;
+
+ //
+ // Build the request we will use to send the notification.
+ //
+ sRequest.bmRequestType = (USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE);
+ sRequest.bRequest = USB_CDC_NOTIFY_SERIAL_STATE;
+ sRequest.wValue = 0;
+ sRequest.wIndex = 0;
+ sRequest.wLength = USB_CDC_NOTIFY_SERIAL_STATE_SIZE;
+
+ //
+ // Write the request structure to the USB FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint,
+ (uint8_t *)&sRequest,
+ sizeof(tUSBRequest));
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint,
+ (uint8_t *)&ui16SerialState,
+ USB_CDC_NOTIFY_SERIAL_STATE_SIZE);
+
+ //
+ // Did we correctly write the data to the endpoint FIFO?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // We put the data into the FIFO so now schedule it to be
+ // sent.
+ //
+ i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint,
+ USB_TRANS_IN);
+ }
+
+ //
+ // If an error occurred, mark the endpoint as idle (to prevent possible
+ // lockup) and return an error.
+ //
+ if(i32Retcode == -1)
+ {
+ psInst->iCDCInterruptState = eCDCStateIdle;
+ return(false);
+ }
+ else
+ {
+ //
+ // Everything went fine. Clear the error bits that we just notified
+ // and return true.
+ //
+ psInst->ui16SerialState &= ~(ui16SerialState & USB_CDC_SERIAL_ERRORS);
+ return(true);
+ }
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psCDCDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts signaling
+// the arrival of data on the bulk OUT endpoint (in other words, whenever the
+// host has sent us a packet of data). We inform the client that a packet
+// is available and, on return, check to see if the packet has been read. If
+// not, we schedule another notification to the client for a later time.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessDataFromHost(tUSBDCDCDevice *psCDCDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Set the flag we use to indicate that a packet read is pending. This
+ // will be cleared if the packet is read. If the client doesn't read
+ // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
+ // the event will be notified later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_PACKET_RX,
+ true);
+
+ //
+ // Is the receive channel currently blocked?
+ //
+ if(!psInst->bControlBlocked && !psInst->bRxBlocked)
+ {
+ //
+ // How big is the packet we have just been received?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ //
+ // The receive channel is not blocked so let the caller know
+ // that a packet is waiting. The parameters are set to indicate
+ // that the packet has not been read from the hardware FIFO yet.
+ //
+ psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ui32EPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData, USB_EVENT_ERROR,
+ (ui32EPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to interrupt messages sent to the host.
+//
+// \param psCDCDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the interrupt IN endpoint (in other words, whenever a notification has
+// been transmitted to the USB host).
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessNotificationToHost(tUSBDCDCDevice *psCDCDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus;
+ tCDCSerInstance *psInst;
+ bool bRetcode;
+
+ //
+ // Assume all will go well until we have reason to believe otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint, ui32EPStatus);
+
+ //
+ // Did the state change while we were waiting for the previous notification
+ // to complete?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_SERIAL_STATE_CHANGE))
+ {
+ //
+ // The state changed while we were waiting so we need to schedule
+ // another notification immediately.
+ //
+ bRetcode = SendSerialState(psCDCDevice);
+ }
+ else
+ {
+ //
+ // Our last notification completed and we did not have any new
+ // notifications to make so the interrupt channel is now idle again.
+ //
+ psInst->iCDCInterruptState = eCDCStateIdle;
+ }
+
+ //
+ // Tell the caller how things went.
+ //
+ return(bRetcode);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psCDCDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the bulk IN endpoint (in other words, whenever data has been
+// transmitted to the USB host). We examine the cause of the interrupt and,
+// if due to completion of a transmission, notify the client.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessDataToHost(tUSBDCDCDevice *psCDCDevice, uint32_t ui32Status)
+{
+ tCDCSerInstance *psInst;
+ uint32_t ui32EPStatus, ui32Size;
+ bool bSentFullPacket;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint, ui32EPStatus);
+
+ //
+ // Our last transmission completed. Clear our state back to idle and
+ // see if we need to send any more data.
+ //
+ psInst->iCDCTxState = eCDCStateIdle;
+
+ //
+ // If this notification is not as a result of sending a zero-length packet,
+ // call back to the client to let it know we sent the last thing it passed
+ // us.
+ //
+ if(psInst->ui16LastTxSize)
+ {
+ //
+ // Have we just sent a 64 byte packet?
+ //
+ bSentFullPacket = (psInst->ui16LastTxSize == DATA_IN_EP_MAX_SIZE) ?
+ true : false;
+
+ //
+ // Notify the client that the last transmission completed.
+ //
+ ui32Size = (uint32_t)psInst->ui16LastTxSize;
+ psInst->ui16LastTxSize = 0;
+ psCDCDevice->pfnTxCallback(psCDCDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
+ ui32Size, (void *)0);
+
+ //
+ // If we had previously sent a full packet and the callback didn't
+ // schedule a new transmission, send a zero length packet to indicate
+ // the end of the transfer.
+ //
+ if(bSentFullPacket && !psInst->ui16LastTxSize)
+ {
+ //
+ // We can expect another transmit complete notification after doing
+ // this.
+ //
+ psInst->iCDCTxState = eCDCStateWaitData;
+
+ //
+ // Send the zero-length packet.
+ //
+ MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack for any activity involving one of our endpoints
+// other than EP0. This function is a fan out that merely directs the call to
+// the correct handler depending upon the endpoint and transaction direction
+// signaled in ui32Status.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvCDCDevice, uint32_t ui32Status)
+{
+ tUSBDCDCDevice *psCDCDeviceInst;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ui32Index is different in both cases.
+ //
+ psCDCDeviceInst = pvCDCDevice;
+ psInst = &psCDCDeviceInst->sPrivateData;
+
+ //
+ // Handler for the interrupt IN notification endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8ControlEndpoint)))
+ {
+ //
+ // We have sent an interrupt notification to the host.
+ //
+ ProcessNotificationToHost(psCDCDeviceInst, ui32Status);
+ }
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8BulkOUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(psCDCDeviceInst, ui32Status);
+ }
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8BulkINEndpoint)))
+ {
+ ProcessDataToHost(psCDCDeviceInst, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvCDCDevice, uint32_t ui32Info)
+{
+ tCDCSerInstance *psInst;
+ tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->iCDCInterruptState = eCDCStateIdle;
+ psInst->iCDCRequestState = eCDCStateIdle;
+ psInst->iCDCRxState = eCDCStateIdle;
+ psInst->iCDCTxState = eCDCStateIdle;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(!psInst->bConnected)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// USB data received callback.
+//
+// This function is called by the USB stack whenever any data requested from
+// EP0 is received.
+//
+//*****************************************************************************
+static void
+HandleEP0Data(void *pvCDCDevice, uint32_t ui32DataSize)
+{
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+ bool bRetcode;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // If we were not passed any data, just return.
+ //
+ if(ui32DataSize == 0)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Make sure we are actually expecting something.
+ //
+ if(psInst->iCDCRequestState != eCDCStateWaitData)
+ {
+ return;
+ }
+
+ //
+ // Process the data received. This will be a request-specific data
+ // block associated with the last request received.
+ //
+ switch (psInst->ui8PendingRequest)
+ {
+ //
+ // We just got the line coding structure. Make sure the client has
+ // read all outstanding data then pass it back to initiate a change
+ // in the line state.
+ //
+ case USB_CDC_SET_LINE_CODING:
+ {
+ if(ui32DataSize != sizeof(tLineCoding))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Set the flag telling us that we need to send a line coding
+ // notification to the client.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_LINE_CODING_CHANGE, true);
+
+ //
+ // See if we can send the notification immediately.
+ //
+ bRetcode = CheckAndSendLineCodingChange(psCDCDevice);
+
+ //
+ // If we could not send the line coding change request to the
+ // client, block reception of more data from the host until
+ // previous data is processed and we send the change request.
+ //
+ if(!bRetcode)
+ {
+ psInst->bRxBlocked = true;
+ }
+ }
+ break;
+ }
+
+ //
+ // Oops - we seem to be waiting on a request which has not yet been
+ // coded here. Flag the error and stall EP0 anyway (even though
+ // this would indicate a coding error).
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ ASSERT(0);
+ break;
+ }
+ }
+
+ //
+ // All is well. Set the state back to IDLE.
+ //
+ psInst->iCDCRequestState = eCDCStateIdle;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvCDCDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tCDCSerInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDCDCDevice *psCDCDevice;
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the appropriate interface number.
+ //
+ if(pui8Data[0] == SERIAL_INTERFACE_CONTROL)
+ {
+ psInst->ui8InterfaceControl = pui8Data[1];
+ }
+ else if(pui8Data[0] == SERIAL_INTERFACE_DATA)
+ {
+ psInst->ui8InterfaceData = pui8Data[1];
+ }
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ //
+ // Determine which IN endpoint to modify.
+ //
+ if((pui8Data[0] & 0x7f) == USBEPToIndex(CONTROL_ENDPOINT))
+ {
+ psInst->ui8ControlEndpoint =
+ IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ else
+ {
+ psInst->ui8BulkINEndpoint =
+ IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ui8BulkOUTEndpoint =
+ IndexToUSBEP(pui8Data[1] & 0x7f);
+ }
+ break;
+ }
+
+ //
+ // Handle class specific reconfiguring of the configuration descriptor
+ // once the composite class has built the full descriptor.
+ //
+ case USB_EVENT_COMP_CONFIG:
+ {
+ //
+ // This sets the bFirstInterface of the Interface Association
+ // descriptor to the first interface which is the control
+ // interface used by this instance.
+ //
+ pui8Data[2] = psInst->ui8InterfaceControl;
+
+ //
+ // This sets the bMasterInterface of the Union descriptor to the
+ // Control interface and the bSlaveInterface of the Union
+ // Descriptor to the Data interface used by this instance.
+ //
+ pui8Data[29] = psInst->ui8InterfaceControl;
+ pui8Data[30] = psInst->ui8InterfaceData;
+
+ //
+ // This sets the bDataInterface of the Union descriptor to the
+ // Data interface used by this instance.
+ pui8Data[35] = psInst->ui8InterfaceData;
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psCDCDevice->pfnControlCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psCDCDevice->pfnControlCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psCDCDevice->pfnControlCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// USB non-standard request callback.
+//
+// This function is called by the USB stack whenever any non-standard request
+// is made to the device. The handler should process any requests that it
+// supports or stall EP0 in any unsupported cases.
+//
+//*****************************************************************************
+static void
+HandleRequests(void *pvCDCDevice, tUSBRequest *pUSBRequest)
+{
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+ bool bRetcode;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Only handle requests meant for this interface.
+ //
+ if(pUSBRequest->wIndex != psInst->ui8InterfaceControl)
+ {
+ return;
+ }
+
+ //
+ // Handle each of the requests that we expect from the host.
+ //
+ switch(pUSBRequest->bRequest)
+ {
+ case USB_CDC_SEND_ENCAPSULATED_COMMAND:
+ {
+ //
+ // This implementation makes use of no communication protocol so
+ // this request is meaningless. We stall endpoint 0 if we receive
+ // it.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_GET_ENCAPSULATED_RESPONSE:
+ {
+ //
+ // This implementation makes use of no communication protocol so
+ // this request is meaningless. We stall endpoint 0 if we receive
+ // it.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_SET_COMM_FEATURE:
+ {
+ //
+ // This request is apparently required by an ACM device but does
+ // not appear relevant to a virtual COM port and is never used by
+ // Windows (or, at least, is not seen when using Hyperterminal or
+ // TeraTerm via a Windows virtual COM port). We stall endpoint 0
+ // to indicate that we do not support the request.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_GET_COMM_FEATURE:
+ {
+ //
+ // This request is apparently required by an ACM device but does
+ // not appear relevant to a virtual COM port and is never used by
+ // Windows (or, at least, is not seen when using Hyperterminal or
+ // TeraTerm via a Windows virtual COM port). We stall endpoint 0
+ // to indicate that we do not support the request.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_CLEAR_COMM_FEATURE:
+ {
+ //
+ // This request is apparently required by an ACM device but does
+ // not appear relevant to a virtual COM port and is never used by
+ // Windows (or, at least, is not seen when using Hyperterminal or
+ // TeraTerm via a Windows virtual COM port). We stall endpoint 0
+ // to indicate that we do not support the request.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ //
+ // Set the serial communication parameters.
+ //
+ case USB_CDC_SET_LINE_CODING:
+ {
+ //
+ // Remember the request we are processing.
+ //
+ psInst->ui8PendingRequest = USB_CDC_SET_LINE_CODING;
+
+ //
+ // Set the state to indicate we are waiting for data.
+ //
+ psInst->iCDCRequestState = eCDCStateWaitData;
+
+ //
+ // Now read the payload of the request. We handle the actual
+ // operation in the data callback once this data is received.
+ //
+ USBDCDRequestDataEP0(0, (uint8_t *)&psInst->sLineCoding,
+ sizeof(tLineCoding));
+
+ //
+ // ACK what we have already received. We must do this after
+ // requesting the data or we get into a race condition where the
+ // data may return before we have set the stack state appropriately
+ // to receive it.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ break;
+ }
+
+ //
+ // Return the serial communication parameters.
+ //
+ case USB_CDC_GET_LINE_CODING:
+ {
+ tLineCoding sLineCoding;
+
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ //
+ // Ask the client for the current line coding.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USBD_CDC_EVENT_GET_LINE_CODING, 0,
+ &sLineCoding);
+
+ //
+ // Send the line coding information back to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&sLineCoding, sizeof(tLineCoding));
+
+ break;
+ }
+
+ case USB_CDC_SET_CONTROL_LINE_STATE:
+ {
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ //
+ // Set the handshake lines as required.
+ //
+ psInst->ui16ControlLineState = pUSBRequest->wValue;
+
+ //
+ // Remember that we are due to notify the client of a line
+ // state change.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_LINE_STATE_CHANGE, true);
+
+ //
+ // See if we can notify now.
+ //
+ bRetcode = CheckAndSendLineStateChange(psCDCDevice);
+
+ //
+ // If we could not send the line state change request to the
+ // client, block reception of more data from the host until
+ // previous data is processed and we send the change request.
+ //
+ if(!bRetcode)
+ {
+ psInst->bRxBlocked = true;
+ }
+
+ break;
+ }
+
+ case USB_CDC_SEND_BREAK:
+ {
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ //
+ // Keep a copy of the requested break duration.
+ //
+ psInst->ui16BreakDuration = pUSBRequest->wValue;
+
+ //
+ // Remember that we need to send a break request.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_SEND_BREAK, true);
+
+ //
+ // Send the break request if all outstanding receive data has been
+ // processed.
+ //
+ bRetcode = CheckAndSendBreak(psCDCDevice, pUSBRequest->wValue);
+
+ //
+ // If we could not send the line coding change request to the
+ // client, block reception of more data from the host until
+ // previous data is processed and we send the change request.
+ //
+ if(!bRetcode)
+ {
+ psInst->bRxBlocked = true;
+ }
+
+ break;
+ }
+
+ //
+ // These are valid CDC requests but not ones that an ACM device should
+ // receive.
+ //
+ case USB_CDC_SET_AUX_LINE_STATE:
+ case USB_CDC_SET_HOOK_STATE:
+ case USB_CDC_PULSE_SETUP:
+ case USB_CDC_SEND_PULSE:
+ case USB_CDC_SET_PULSE_TIME:
+ case USB_CDC_RING_AUX_JACK:
+ case USB_CDC_SET_RINGER_PARMS:
+ case USB_CDC_GET_RINGER_PARMS:
+ case USB_CDC_SET_OPERATION_PARMS:
+ case USB_CDC_GET_OPERATION_PARMS:
+ case USB_CDC_SET_LINE_PARMS:
+ case USB_CDC_GET_LINE_PARMS:
+ case USB_CDC_DIAL_DIGITS:
+ case USB_CDC_SET_UNIT_PARAMETER:
+ case USB_CDC_GET_UNIT_PARAMETER:
+ case USB_CDC_CLEAR_UNIT_PARAMETER:
+ case USB_CDC_GET_PROFILE:
+ case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+ case USB_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
+ case USB_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
+ case USB_CDC_SET_ETHERNET_PACKET_FILTER:
+ case USB_CDC_GET_ETHERNET_STATISTIC:
+ case USB_CDC_SET_ATM_DATA_FORMAT:
+ case USB_CDC_GET_ATM_DEVICE_STATISTICS:
+ case USB_CDC_SET_ATM_DEFAULT_VC:
+ case USB_CDC_GET_ATM_VC_STATISTICS:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ default:
+ {
+ //
+ // This request is not part of the CDC specification.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvCDCDevice)
+{
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // If we are not currently connected and we have a control callback,
+ // let the client know we are open for business.
+ //
+ if(psInst->bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psInst->bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvCDCDevice)
+{
+ const tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (const tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_SUSPEND, 0, (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is taken
+// out of suspend state.
+//
+//*****************************************************************************
+static void
+HandleResume(void *pvCDCDevice)
+{
+ tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_RESUME, 0, (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called periodically and provides us with a time reference
+// and method of implementing delayed or time-dependent operations.
+//
+// \param ui32Index is the index of the USB controller for which this tick
+// is being generated.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+CDCTickHandler(void *pvCDCDevice, uint32_t ui32TimemS)
+{
+ bool bCanSend;
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+ uint32_t ui32Size;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Is there any outstanding operation that we should try to perform?
+ //
+ if(psInst->ui16DeferredOpFlags)
+ {
+ //
+ // Yes - we have at least one deferred operation pending. First check
+ // to see if it is time to turn off a break condition.
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_CLEAR_BREAK))
+ {
+ //
+ // Will our break timer expire this time?
+ //
+ if(psInst->ui16BreakDuration <= ui32TimemS)
+ {
+ //
+ // Yes - turn off the break condition.
+ //
+ SendBreak(psCDCDevice, false);
+ }
+ else
+ {
+ //
+ // We have not timed out yet. Decrement the break timer.
+ //
+ psInst->ui16BreakDuration -= (uint16_t)ui32TimemS;
+ }
+ }
+
+ // Now check to see if the client has any data remaining to be
+ // processed. This information is needed by the remaining deferred
+ // operations which are waiting for the receive pipe to be emptied
+ // before they can be carried out.
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Has all outstanding data been consumed?
+ //
+ if(bCanSend)
+ {
+ //
+ // Yes - go ahead and notify the client of the various things
+ // it has been asked to do while we waited for data to be
+ // consumed.
+ //
+
+ //
+ // Do we need to start sending a break condition?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_SEND_BREAK))
+ {
+ SendBreak(psCDCDevice, true);
+ }
+
+ //
+ // Do we need to set the RTS/DTR states?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_LINE_STATE_CHANGE))
+ {
+ SendLineStateChange(psCDCDevice);
+ }
+
+ //
+ // Do we need to change the line coding parameters?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_LINE_CODING_CHANGE))
+ {
+ SendLineCodingChange(psCDCDevice);
+ }
+
+ //
+ // NOTE: We do not need to handle CDC_DO_SERIAL_STATE_CHANGE here
+ // since this is handled in the transmission complete notification
+ // for the control IN endpoint (ProcessNotificationToHost()).
+ //
+
+ //
+ // If all the deferred operations which caused the receive channel
+ // to be blocked are now handled, we can unblock receive and handle
+ // any packet that is currently waiting to be received.
+ //
+ if(!(psInst->ui16DeferredOpFlags & RX_BLOCK_OPS))
+ {
+ //
+ // We can remove the receive block.
+ //
+ psInst->bRxBlocked = false;
+ }
+ }
+
+ //
+ // Is the receive channel unblocked?
+ //
+ if(!psInst->bRxBlocked)
+ {
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ // Tell the client that there is a packet waiting for it.
+ //
+ psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+ }
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes CDC device operation when used with a composite device.
+//!
+//! \param ui32Index is the index of the USB controller in use.
+//! \param psCDCDevice points to a structure containing parameters customizing
+//! the operation of the CDC device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDCDCInit() except that it is used for
+//! initializing an instance of the serial device for use in a composite
+//! device. When this CDC serial device is part of a composite device, then
+//! the \e psCompEntry should point to the composite device entry to
+//! initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB CDC APIs.
+//
+//*****************************************************************************
+void *
+USBDCDCCompositeInit(uint32_t ui32Index, tUSBDCDCDevice *psCDCDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psCDCDevice);
+ ASSERT(psCDCDevice->pfnControlCallback);
+ ASSERT(psCDCDevice->pfnRxCallback);
+ ASSERT(psCDCDevice->pfnTxCallback);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psCDCDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sCDCHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8CDCSerDeviceDescriptor;
+
+ //
+ // The CDC serial configuration is different for composite devices and
+ // stand alone devices.
+ //
+ if(psCompEntry == 0)
+ {
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppCDCSerConfigDescriptors;
+ }
+ else
+ {
+ psInst->sDevInfo.ppsConfigDescriptors = g_pCDCCompSerConfigDescriptors;
+ }
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ui8BulkINEndpoint = DATA_IN_ENDPOINT;
+ psInst->ui8BulkOUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ui8InterfaceControl = SERIAL_INTERFACE_CONTROL;
+ psInst->ui8InterfaceData = SERIAL_INTERFACE_DATA;
+
+ //
+ // By default do not use the interrupt control endpoint. The single
+ // instance CDC serial device will turn this on in USBDCDCInit();
+ //
+ psInst->ui8ControlEndpoint = CONTROL_ENDPOINT;
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->iCDCRxState = eCDCStateUnconfigured;
+ psInst->iCDCTxState = eCDCStateUnconfigured;
+ psInst->iCDCInterruptState = eCDCStateUnconfigured;
+ psInst->iCDCRequestState = eCDCStateUnconfigured;
+ psInst->ui8PendingRequest = 0;
+ psInst->ui16BreakDuration = 0;
+ psInst->ui16SerialState = 0;
+ psInst->ui16DeferredOpFlags = 0;
+ psInst->ui16ControlLineState = 0;
+ psInst->bRxBlocked = false;
+ psInst->bControlBlocked = false;
+ psInst->bConnected = false;
+
+ //
+ // Initialize the device info structure for the serial device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psCDCDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psCDCDevice->ui32NumStringDescriptors;
+
+ //
+ // Initialize the USB tick module, this will prevent it from being
+ // initialized later in the call to USBDCDInit();
+ //
+ InternalUSBTickInit();
+
+ //
+ // Register our tick handler (this must be done after USBDCDInit).
+ //
+ InternalUSBRegisterTickHandler(CDCTickHandler, (void *)psCDCDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psCDCDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes CDC device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for CDC device operation.
+//! \param psCDCDevice points to a structure containing parameters customizing
+//! the operation of the CDC device.
+//!
+//! An application wishing to make use of a USB CDC communication channel and
+//! appear as a virtual serial port on the host system must call this function
+//! to initialize the USB controller and attach the device to the USB bus.
+//! This function performs all required USB initialization.
+//!
+//! The value returned by this function is the \e psCDCDevice pointer passed
+//! to it if successful. This pointer must be passed to all later calls to the
+//! CDC class driver to identify the device instance.
+//!
+//! The USB CDC device class driver offers packet-based transmit and receive
+//! operation. If the application would rather use block based communication
+//! with transmit and receive buffers, USB buffers on the transmit and receive
+//! channels may be used to offer this functionality.
+//!
+//! Transmit Operation:
+//!
+//! Calls to USBDCDCPacketWrite() must send no more than 64 bytes of data at a
+//! time and may only be made when no other transmission is currently
+//! outstanding.
+//!
+//! Once a packet of data has been acknowledged by the USB host, a
+//! \b USB_EVENT_TX_COMPLETE event is sent to the application callback to
+//! inform it that another packet may be transmitted.
+//!
+//! Receive Operation:
+//!
+//! An incoming USB data packet will result in a call to the application
+//! callback with event \b USB_EVENT_RX_AVAILABLE. The application must then
+//! call USBDCDCPacketRead(), passing a buffer capable of holding the received
+//! packet to retrieve the data and acknowledge reception to the USB host. The
+//! size of the received packet may be queried by calling
+//! USBDCDCRxPacketAvailable().
+//!
+//! \note The application must not make any calls to the low level USB Device
+//! API if interacting with USB via the CDC device class API. Doing so
+//! will cause unpredictable (though almost certainly unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the psCDCDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDCDCInit(uint32_t ui32Index, tUSBDCDCDevice *psCDCDevice)
+{
+ void *pvRet;
+ tCDCSerInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+ tConfigDescriptor *psConfigDesc;
+
+ //
+ // Initialize the internal state for this class.
+ //
+ pvRet = USBDCDCCompositeInit(ui32Index, psCDCDevice, 0);
+
+ if(pvRet)
+ {
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8CDCSerDeviceDescriptor;
+ psDevDesc->idVendor = psCDCDevice->ui16VID;
+ psDevDesc->idProduct = psCDCDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psConfigDesc = (tConfigDescriptor *)g_pui8CDCSerDescriptor;
+ psConfigDesc->bmAttributes = psCDCDevice->ui8PwrAttributes;
+ psConfigDesc->bMaxPower = (uint8_t)(psCDCDevice->ui16MaxPowermA / 2);
+
+ //
+ // Create an instance pointer to the private data area.
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Enable the default interrupt control endpoint if this class is not
+ // being used in a composite device.
+ //
+ psInst->ui8ControlEndpoint = CONTROL_ENDPOINT;
+
+ //
+ // Use the configuration descriptor with the interrupt control
+ // endpoint.
+ //
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppCDCSerConfigDescriptors;
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the CDC device on the bus.
+ //
+ USBDCDInit(ui32Index, &psInst->sDevInfo, (void *)psCDCDevice);
+ }
+
+ return(pvRet);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the CDC device instance.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//!
+//! This function terminates CDC operation for the instance supplied and
+//! removes the device from the USB bus. This function should not be called
+//! if the CDC device is part of a composite device and instead the
+//! USBDCompositeTerm() function should be called for the full composite
+//! device.
+//!
+//! Following this call, the \e pvCDCDevice instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCTerm(void *pvCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase));
+
+ psInst->ui32USBBase = 0;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer for the control callback.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the control channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnControlCallback function
+//! passed on USBDCDCInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
+//! RAM. If this structure is in flash, callback pointer changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's control callback.
+//
+//*****************************************************************************
+void *
+USBDCDCSetControlCBData(void *pvCDCDevice, void *pvCBData)
+{
+ tUSBDCDCDevice *psBulkDevice;
+ void *pvOldValue;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psBulkDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Set the callback pointer for the control channel after remembering the
+ // previous value.
+ //
+ pvOldValue = psBulkDevice->pvControlCBData;
+ psBulkDevice->pvControlCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data parameter for the receive channel callback.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the receive channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnRxCallback function
+//! passed on USBDCDCInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's receive callback.
+//
+//*****************************************************************************
+void *
+USBDCDCSetRxCBData(void *pvCDCDevice, void *pvCBData)
+{
+ tUSBDCDCDevice *psBulkDevice;
+ void *pvOldValue;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psBulkDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = psBulkDevice->pvRxCBData;
+ psBulkDevice->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data parameter for the transmit callback.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the transmit channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnTxCallback function
+//! passed on USBDCDCInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's transmit callback.
+//
+//*****************************************************************************
+void *
+USBDCDCSetTxCBData(void *pvCDCDevice, void *pvCBData)
+{
+ tUSBDCDCDevice *psBulkDevice;
+ void *pvOldValue;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psBulkDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Set the callback data for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = psBulkDevice->pvTxCBData;
+ psBulkDevice->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a packet of data to the USB host via the CDC data interface.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pi8Data points to the first byte of data which is to be transmitted.
+//! \param ui32Length is the number of bytes of data to transmit.
+//! \param bLast indicates whether more data is to be written before a packet
+//! should be scheduled for transmission. If \b true, the client will make
+//! a further call to this function. If \b false, no further call will be
+//! made and the driver should schedule transmission of a short packet.
+//!
+//! This function schedules the supplied data for transmission to the USB
+//! host in a single USB packet. If no transmission is currently ongoing
+//! the data is immediately copied to the relevant USB endpoint FIFO. If the
+//! \e bLast parameter is \b true, the newly written packet is then scheduled
+//! for transmission. Whenever a USB packet is acknowledged by the host, a
+//! \b USB_EVENT_TX_COMPLETE event will be sent to the application transmit
+//! callback indicating that more data can now be transmitted.
+//!
+//! The maximum value for \e ui32Length is 64 bytes (the maximum USB packet
+//! size for the bulk endpoints in use by CDC). Attempts to send more data
+//! than this will result in a return code of 0 indicating that the data cannot
+//! be sent.
+//!
+//! \return Returns the number of bytes actually sent. At this level, this
+//! will either be the number of bytes passed (if less than or equal to the
+//! maximum packet size for the USB endpoint in use and no outstanding
+//! transmission ongoing) or 0 to indicate a failure.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCPacketWrite(void *pvCDCDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ tCDCSerInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Can we send the data provided?
+ //
+ if((ui32Length > DATA_IN_EP_MAX_SIZE) ||
+ (psInst->iCDCTxState != eCDCStateIdle))
+ {
+ //
+ // Either the packet was too big or we are in the middle of sending
+ // another packet. Return 0 to indicate that we can't send this data.
+ //
+ return(0);
+ }
+
+ //
+ // Copy the data into the USB endpoint FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint, pi8Data,
+ ui32Length);
+
+ //
+ // Did we copy the data successfully?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // Remember how many bytes we sent.
+ //
+ psInst->ui16LastTxSize += (uint16_t)ui32Length;
+
+ //
+ // If this is the last call for this packet, schedule transmission.
+ //
+ if(bLast)
+ {
+ //
+ // Send the packet to the host if we have received all the data we
+ // can expect for this packet.
+ //
+ psInst->iCDCTxState = eCDCStateWaitData;
+ i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ui32Length);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we could not send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the CDC data
+//! interface.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pi8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by \e pi8Data.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to ui32Length bytes of data received from the USB
+//! host into the supplied application buffer.
+//!
+//! \note The \e bLast parameter is ignored in this implementation since the
+//! end of a packet can be determined without relying upon the client to
+//! provide this information.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCPacketRead(void *pvCDCDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ uint32_t ui32EPStatus, ui32Count, ui32Pkt;
+ tCDCSerInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // If receive is currently blocked or the buffer we were passed is
+ // (potentially) too small, set the flag telling us that we have a
+ // packet waiting but return 0.
+ //
+ if(psInst->bRxBlocked || psInst->bControlBlocked)
+ {
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_PACKET_RX,
+ true);
+ return(0);
+ }
+ else
+ {
+ //
+ // It is OK to receive the new packet. How many bytes are
+ // available for us to receive?
+ //
+ ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ui32Count = ui32Length;
+ i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ pi8Data, &ui32Count);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ui32Count == ui32Pkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_PACKET_RX, false);
+
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(i32Retcode != -1)
+ {
+ return(ui32Count);
+ }
+ }
+ }
+
+ //
+ // No packet was available or an error occurred while reading so tell
+ // the caller no bytes were returned.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the transmit buffer.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//!
+//! This function returns the maximum number of bytes that can be passed on a
+//! call to USBDCDCPacketWrite() and accepted for transmission. The value
+//! returned will be the maximum USB packet size if no transmission is
+//! currently outstanding or 0 if a transmission is in progress.
+//!
+//! \return Returns the number of bytes available in the transmit buffer.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCTxPacketAvailable(void *pvCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->iCDCTxState != eCDCStateIdle)
+ {
+ //
+ // We are not ready to receive a new packet so return 0.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // We can receive a packet so return the max packet size for the
+ // relevant endpoint.
+ //
+ return(DATA_IN_EP_MAX_SIZE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//!
+//! This function may be used to determine if a received packet remains to be
+//! read and allows the application to determine the buffer size needed to
+//! read the data.
+//!
+//! \return Returns 0 if no received packet remains unprocessed or the
+//! size of the packet if a packet is waiting to be read.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCRxPacketAvailable(void *pvCDCDevice)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // If receive is currently blocked, return 0.
+ //
+ if(psInst->bRxBlocked || psInst->bControlBlocked)
+ {
+ return(0);
+ }
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Informs the CDC module of changes in the serial control line states or
+//! receive error conditions.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param ui16State indicates the states of the various control lines and
+//! any receive errors detected. Bit definitions are as for the USB CDC
+//! SerialState asynchronous notification and are defined in header file
+//! usbcdc.h.
+//!
+//! The application should call this function whenever the state of any of
+//! the incoming RS232 handshake signals changes or in response to a receive
+//! error or break condition. The \e ui16State parameter is the ORed
+//! combination of the following flags with each flag indicating the presence
+//! of that condition.
+//!
+//! - USB_CDC_SERIAL_STATE_OVERRUN
+//! - USB_CDC_SERIAL_STATE_PARITY
+//! - USB_CDC_SERIAL_STATE_FRAMING
+//! - USB_CDC_SERIAL_STATE_RING_SIGNAL
+//! - USB_CDC_SERIAL_STATE_BREAK
+//! - USB_CDC_SERIAL_STATE_TXCARRIER
+//! - USB_CDC_SERIAL_STATE_RXCARRIER
+//!
+//! This function should be called only when the state of any flag changes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCSerialStateChange(void *pvCDCDevice, uint16_t ui16State)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Add the newly reported state bits to the current collection. We do this
+ // in case two state changes occur back-to-back before the first has been
+ // notified. There are two distinct types of signals that we report here
+ // and we deal with them differently:
+ //
+ // 1. Errors (overrun, parity, framing error) are ORed together so that
+ // any reported error is sent on the next notification.
+ // 2. Signal line states (RI, break, TX carrier, RX carrier) always
+ // report the last state notified to us. The implementation here will
+ // send an interrupt showing the last state but, if two state changes
+ // occur very quickly, the host may receive a notification containing
+ // the same state that was last reported (in other words, a short pulse
+ // will be lost). It would be possible to reduce the likelihood of
+ // this happening by building a queue of state changes and sending
+ // these in order but you are left with exactly the same problem if the
+ // queue fills up. For now, therefore, we run the risk of missing very
+ // short pulses on the "steady-state" signal lines.
+ //
+ psInst->ui16SerialState |= (ui16State & USB_CDC_SERIAL_ERRORS);
+ psInst->ui16SerialState &= ~USB_CDC_SERIAL_ERRORS;
+ psInst->ui16SerialState |= (ui16State & ~USB_CDC_SERIAL_ERRORS);
+
+ //
+ // Set the flag indicating that a serial state change is to be sent.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
+ true);
+
+ //
+ // Can we send the state change immediately?
+ //
+ if(psInst->iCDCInterruptState == eCDCStateIdle)
+ {
+ //
+ // The interrupt channel is free so send the notification immediately.
+ // If we can't do this, the tick timer will catch this next time
+ // round.
+ //
+ psInst->iCDCInterruptState = eCDCStateWaitData;
+ SendSerialState(pvCDCDevice);
+ }
+
+ return;
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvCDCDevice is the pointer to the CDC device instance structure.
+//! \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 USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCPowerStatusSet(void *pvCDCDevice, uint8_t ui8Power)
+{
+ ASSERT(pvCDCDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wakeup to resume communication when in suspended state.
+//!
+//! \param pvCDCDevice is the pointer to the CDC device instance structure.
+//!
+//! When the bus is suspended, an application which supports remote wakeup
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wakeup signaling to the host. If the remote
+//! wakeup feature has not been disabled by the host, this will cause the bus
+//! to resume operation within 20mS. If the host has disabled remote wakeup,
+//! \b false will be returned to indicate that the wakeup request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wakeup is not disabled and the
+//! signaling was started or \b false if remote wakeup is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDCDCRemoteWakeupRequest(void *pvCDCDevice)
+{
+ ASSERT(pvCDCDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDCDRemoteWakeupRequest(0));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdcdc.h b/usblib/device/usbdcdc.h new file mode 100644 index 0000000..dc96086 --- /dev/null +++ b/usblib/device/usbdcdc.h @@ -0,0 +1,447 @@ +//*****************************************************************************
+//
+// usbdcdc.h - USBLib support for generic CDC ACM (serial) device.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDCDC_H__
+#define __USBDCDC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup cdc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB CDC Serial code and are here only to help with the application
+// allocating the correct amount of memory for the CDC Serial device code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ eCDCStateUnconfigured,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ eCDCStateIdle,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ eCDCStateWaitData,
+
+ //
+ // Waiting for client to process data.
+ //
+ eCDCStateWaitClient
+}
+tCDCState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// CDC Serial device. The memory for this structure is allocated in the
+// tUSBDCDCDevice structure passed on USBDCDCInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The state of the serial receive state.
+ //
+ volatile tCDCState iCDCRxState;
+
+ //
+ // The state of the serial transmit state.
+ //
+ volatile tCDCState iCDCTxState;
+
+ //
+ // The state of the serial request state.
+ //
+ volatile tCDCState iCDCRequestState;
+
+ //
+ // The state of the serial interrupt state.
+ //
+ volatile tCDCState iCDCInterruptState;
+
+ //
+ // The current pending request.
+ //
+ volatile uint8_t ui8PendingRequest;
+
+ //
+ // The current break duration used during send break requests.
+ //
+ uint16_t ui16BreakDuration;
+
+ //
+ // The current line control state for the serial port.
+ //
+ uint16_t ui16ControlLineState;
+
+ //
+ // The general serial state.
+ //
+ uint16_t ui16SerialState;
+
+ //
+ // State of any pending operations that could not be handled immediately
+ // upon receipt.
+ //
+ volatile uint16_t ui16DeferredOpFlags;
+
+ //
+ // Size of the last transmit.
+ //
+ uint16_t ui16LastTxSize;
+
+ //
+ // The current serial line coding.
+ //
+ tLineCoding sLineCoding;
+
+ //
+ // Serial port receive is blocked.
+ //
+ volatile bool bRxBlocked;
+
+ //
+ // Serial control port is blocked.
+ //
+ volatile bool bControlBlocked;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // The control endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8ControlEndpoint;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8BulkINEndpoint;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8BulkOUTEndpoint;
+
+ //
+ // The interface number for the control interface, this is modified in
+ // composite devices.
+ //
+ uint8_t ui8InterfaceControl;
+
+ //
+ // The interface number for the data interface, this is modified in
+ // composite devices.
+ //
+ uint8_t ui8InterfaceData;
+}
+tCDCSerInstance;
+
+//*****************************************************************************
+//
+// The following defines are used when working with composite devices.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8IADSerDescriptor array in bytes.
+//
+//*****************************************************************************
+#define SERDESCRIPTOR_SIZE (8)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8CDCSerCommInterface array in bytes.
+//
+//*****************************************************************************
+#define SERCOMMINTERFACE_SIZE (35)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8CDCSerDataInterface array in bytes.
+//
+//*****************************************************************************
+#define SERDATAINTERFACE_SIZE (23)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Serial CDC Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DCDC_SIZE (SERDESCRIPTOR_SIZE + SERCOMMINTERFACE_SIZE + \
+ SERDATAINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+// CDC-specific events These events are provided to the application in the
+// \e ui32Msg parameter of the tUSBCallback function.
+//
+//*****************************************************************************
+
+//
+//! The host requests that the device send a BREAK condition on its
+//! serial communication channel. The BREAK should remain active until
+//! a USBD_CDC_EVENT_CLEAR_BREAK event is received.
+//
+#define USBD_CDC_EVENT_SEND_BREAK (USBD_CDC_EVENT_BASE + 0)
+
+//
+//! The host requests that the device stop sending a BREAK condition on its
+//! serial communication channel.
+//
+#define USBD_CDC_EVENT_CLEAR_BREAK (USBD_CDC_EVENT_BASE + 1)
+
+//
+//! The host requests that the device set the RS232 signaling lines to
+//! a particular state. The ui32MsgValue parameter contains the RTS and
+//! DTR control line states as defined in table 51 of the USB CDC class
+//! definition and is a combination of the following values:
+//!
+//! (RTS) USB_CDC_DEACTIVATE_CARRIER or USB_CDC_ACTIVATE_CARRIER
+//! (DTR) USB_CDC_DTE_NOT_PRESENT or USB_CDC_DTE_PRESENT
+//
+#define USBD_CDC_EVENT_SET_CONTROL_LINE_STATE (USBD_CDC_EVENT_BASE + 2)
+
+//
+//! The host requests that the device set the RS232 communication
+//! parameters. The pvMsgData parameter points to a tLineCoding structure
+//! defining the required number of bits per character, parity mode,
+//! number of stop bits and the baud rate.
+//
+#define USBD_CDC_EVENT_SET_LINE_CODING (USBD_CDC_EVENT_BASE + 3)
+
+//
+//! The host is querying the current RS232 communication parameters. The
+//! pvMsgData parameter points to a tLineCoding structure that the
+//! application must fill with the current settings prior to returning
+//! from the callback.
+//
+#define USBD_CDC_EVENT_GET_LINE_CODING (USBD_CDC_EVENT_BASE + 4)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the CDC device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of all asynchronous control events related to the
+ //! operation of the device.
+ //
+ const tUSBCallback pfnControlCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the control channel callback,
+ //! pfnControlCallback.
+ //
+ void *pvControlCBData;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data receive channel.
+ //
+ const tUSBCallback pfnRxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the receive channel callback,
+ //! pfnRxCallback.
+ //
+ void *pvRxCBData;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data transmit
+ //! channel.
+ //
+ const tUSBCallback pfnTxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the transmit channel callback,
+ //! pfnTxCallback.
+ //
+ void *pvTxCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),
+ //! Control interface description string (language 1), Configuration
+ //! description string (language 1).
+ //!
+ //! If supporting more than 1 language, the strings for indices 1 through 5
+ //! must be repeated for each of the other languages defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + (5 * number of supported languages).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory
+ //! must remain accessible for as long as the CDC device is in use and
+ //! must not be modified by any code outside the CDC class driver.
+ //
+ tCDCSerInstance sPrivateData;
+}
+tUSBDCDCDevice;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDCDCCompositeInit(uint32_t ui32Index,
+ tUSBDCDCDevice *psCDCDevice,
+ tCompositeEntry *psCompEntry);
+extern void *USBDCDCInit(uint32_t ui32Index,
+ tUSBDCDCDevice *psCDCDevice);
+extern void USBDCDCTerm(void *pvCDCDevice);
+extern void *USBDCDCSetControlCBData(void *pvCDCDevice, void *pvCBData);
+extern void *USBDCDCSetRxCBData(void *pvCDCDevice, void *pvCBData);
+extern void *USBDCDCSetTxCBData(void *pvCDCDevice, void *pvCBData);
+extern uint32_t USBDCDCPacketWrite(void *pvCDCDevice, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDCDCPacketRead(void *pvCDCDevice, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDCDCTxPacketAvailable(void *pvCDCDevice);
+extern uint32_t USBDCDCRxPacketAvailable(void *pvCDCDevice);
+extern void USBDCDCSerialStateChange(void *pvCDCDevice, uint16_t ui16State);
+extern bool USBDCDCRemoteWakeupRequest(void *pvCDCDevice);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+
+//
+// Use USBDCDFeatureSet() or USBHCDFeatureSet() with \b USBLIB_FEATURE_POWER
+// configuration option.
+//
+extern void USBDCDCPowerStatusSet(void *pvCDCDevice, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDCDC_H__
diff --git a/usblib/device/usbdcdesc.c b/usblib/device/usbdcdesc.c new file mode 100644 index 0000000..6260d42 --- /dev/null +++ b/usblib/device/usbdcdesc.c @@ -0,0 +1,643 @@ +//*****************************************************************************
+//
+// usbcdesc.c - Config descriptor parsing functions.
+//
+// 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_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+
+//*****************************************************************************
+//
+// The functions in this file mirror the descriptor parsing APIs available
+// in usblib.h but parse configuration descriptors defined in terms of a list
+// of sections rather than as a single block of descriptor data.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Walk to the next descriptor after the supplied one within a section-based
+//! config descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor which contains \e pi16Desc.
+//! \param pui32Sec points to a variable containing the section within
+//! \e psConfig which contains \e pi16Desc.
+//! \param pi16Desc points to the descriptor that we want to step past.
+//!
+//! This function walks forward one descriptor within a configuration
+//! descriptor. The value returned is a pointer to the header of the next
+//! descriptor after the descriptor supplied in \e pi16Desc. If the next
+//! descriptor is in the next section, \e *pui32Sec will be incremented
+//! accordingly.
+//!
+//! \return Returns a pointer to the next descriptor in the configuration
+//! descriptor.
+//
+//*****************************************************************************
+static tDescriptorHeader *
+NextConfigDescGet(const tConfigHeader *psConfig, uint32_t *pui32Sec,
+ tDescriptorHeader *psDesc)
+{
+ //
+ // Determine where the next descriptor after the supplied one should be
+ // assuming it is within the current section.
+ //
+ psDesc = NEXT_USB_DESCRIPTOR(psDesc);
+
+ //
+ // Did we run off the end of the section?
+ //
+ if((uint8_t *)psDesc >= (psConfig->psSections[*pui32Sec]->pui8Data +
+ psConfig->psSections[*pui32Sec]->ui16Size))
+ {
+ //
+ // Yes - move to the next section.
+ //
+ (*pui32Sec)++;
+
+ //
+ // Are we still within the configuration descriptor?
+ //
+ if(*pui32Sec < psConfig->ui8NumSections)
+ {
+ //
+ // Yes - the new descriptor is at the start of the new section.
+ //
+ psDesc =
+ (tDescriptorHeader *)psConfig->psSections[*pui32Sec]->pui8Data;
+ }
+ else
+ {
+ //
+ // No - we ran off the end of the descriptor so return NULL.
+ //
+ psDesc = (tDescriptorHeader *)0;
+ }
+ }
+
+ //
+ // Return the new descriptor pointer.
+ //
+ return(psDesc);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Returns a pointer to the n-th interface descriptor in a configuration
+//! descriptor with the supplied interface number.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor to search.
+//! \param ui8InterfaceNumber is the interface number of the descriptor to
+//! query.
+//! \param ui32Index is the zero based index of the descriptor.
+//! \param pui32Section points to storage which is written with the index
+//! of the section containing the returned descriptor.
+//!
+//! This function returns a pointer to the n-th interface descriptor in the
+//! supplied configuration which has the requested interface number. It may be
+//! used by a client to retrieve the descriptors for each alternate setting
+//! of a given interface within the configuration passed.
+//!
+//! \return Returns a pointer to the n-th interface descriptor with interface
+//! number as specified or NULL of this descriptor does not exist.
+//
+//*****************************************************************************
+static tInterfaceDescriptor *
+ConfigAlternateInterfaceGet(const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNumber, uint32_t ui32Index,
+ uint32_t *pui32Section)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32Count, ui32Sec;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pui8Data;
+ ui32Count = 0;
+ ui32Sec = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(psDescCheck)
+ {
+ //
+ // Does this descriptor match the type passed (if a specific type
+ // has been specified)?
+ //
+ if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
+ (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
+ ui8InterfaceNumber))
+ {
+ //
+ // This is an interface descriptor for interface
+ // ui8InterfaceNumber. Determine if this is the n-th one we have
+ // found and, if so, return its pointer.
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Found it - return the pointer and section number.
+ //
+ *pui32Section = ui32Sec;
+ return((tInterfaceDescriptor *)psDescCheck);
+ }
+
+ //
+ // Increment our count of matching descriptors found and go back
+ // to look for another since we have not yet reached the n-th
+ // match.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ psDescCheck = NextConfigDescGet(psConfig, &ui32Sec, psDescCheck);
+ }
+
+ //
+ // If we drop out the end of the loop, we did not find the requested
+ // descriptor so return NULL.
+ //
+ return((tInterfaceDescriptor *)0);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Determines the total length of a configuration descriptor defined in terms
+//! of a collection of concatenated sections.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor whose size is to be determined.
+//!
+//! \return Returns the number of bytes in the configuration descriptor will
+//! result from concatenating the required sections.
+//
+//*****************************************************************************
+uint32_t
+USBDCDConfigDescGetSize(const tConfigHeader *psConfig)
+{
+ uint32_t ui32Loop, ui32Len;
+
+ ui32Len = 0;
+
+ //
+ // Determine the size of the whole descriptor by adding the sizes of
+ // each section which will be concatenated to produce it.
+ //
+ for(ui32Loop = 0; ui32Loop < psConfig->ui8NumSections; ui32Loop++)
+ {
+ ui32Len += psConfig->psSections[ui32Loop]->ui16Size;
+ }
+
+ return(ui32Len);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Determines the number of individual descriptors of a particular type within
+//! a supplied configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32Type identifies the type of descriptor that is to be counted.
+//! If the value is \b USB_DESC_ANY, the function returns the total number of
+//! descriptors regardless of type.
+//!
+//! This function can be used to count the number of descriptors of a
+//! particular type within a configuration descriptor. The caller can provide
+//! a specific type value which the function matches against the second byte
+//! of each descriptor or, alternatively, can specify \b USB_DESC_ANY to have
+//! the function count all descriptors regardless of their type.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetNum(), searches through a single, contiguous
+//! block of data to perform the same enumeration.
+//!
+//! \return Returns the number of descriptors found in the supplied block of
+//! data.
+//
+//*****************************************************************************
+uint32_t
+USBDCDConfigDescGetNum(const tConfigHeader *psConfig, uint32_t ui32Type)
+{
+ uint32_t ui32Section, ui32NumDescs;
+
+ //
+ // Initialize our counts.
+ //
+ ui32NumDescs = 0;
+
+ //
+ // Determine the number of descriptors of the given type in each of the
+ // sections comprising the configuration descriptor. Note that this
+ // assumes each section contains only whole descriptors!
+ //
+ for(ui32Section = 0; ui32Section < (uint32_t)psConfig->ui8NumSections;
+ ui32Section++)
+ {
+ ui32NumDescs += USBDescGetNum(
+ (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data,
+ psConfig->psSections[ui32Section]->ui16Size, ui32Type);
+ }
+
+ return(ui32NumDescs);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Finds the n-th descriptor of a particular type within the supplied
+//! configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32Type identifies the type of descriptor that is to be found. If
+//! the value is \b USB_DESC_ANY, the function returns a pointer to the n-th
+//! descriptor regardless of type.
+//! \param ui32Index is the zero based index of the descriptor whose pointer is
+//! to be returned. For example, passing value 1 in \e ui32Index returns the
+//! second matching descriptor.
+//! \param pui32Section points to storage which will receive the section index
+//! containing the requested descriptor.
+//!
+//! Return a pointer to the n-th descriptor of a particular type found in the
+//! configuration descriptor passed.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGet(), searches through a single, contiguous
+//! block of data to perform the same enumeration.
+//!
+//! \return Returns a pointer to the header of the required descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tDescriptorHeader *
+USBDCDConfigDescGet(const tConfigHeader *psConfig, uint32_t ui32Type,
+ uint32_t ui32Index, uint32_t *pui32Section)
+{
+ uint32_t ui32Section, ui32TotalDescs, ui32NumDescs;
+
+ //
+ // Initialize our counts.
+ //
+ ui32TotalDescs = 0;
+
+ //
+ // Determine the number of descriptors of the given type in each of the
+ // sections comprising the configuration descriptor. This allows us to
+ // determine which section contains the descriptor we are being asked for.
+ //
+ for(ui32Section = 0; ui32Section < (uint32_t)psConfig->ui8NumSections;
+ ui32Section++)
+ {
+ //
+ // How many descriptors of the requested type exist in this section?
+ //
+ ui32NumDescs = USBDescGetNum(
+ (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data,
+ psConfig->psSections[ui32Section]->ui16Size, ui32Type);
+
+ //
+ // Does this section contain the descriptor whose index we are looking
+ // for?
+ //
+ if((ui32TotalDescs + ui32NumDescs) > ui32Index)
+ {
+ //
+ // We know the requested descriptor exists in the current
+ // block so write the section number to the caller's storage.
+ //
+ *pui32Section = ui32Section;
+
+ //
+ // Now find the actual descriptor requested and return its pointer.
+ //
+ return(USBDescGet(
+ (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data,
+ psConfig->psSections[ui32Section]->ui16Size,
+ ui32Type, ui32Index - ui32TotalDescs));
+ }
+
+ //
+ // We have not found the required descriptor yet. Update our running
+ // count of the number of type matches found so far then move on to
+ // the next section.
+ //
+ ui32TotalDescs += ui32NumDescs;
+ }
+
+ //
+ // If we drop out of the loop, we can't find the requested descriptor
+ // so return NULL.
+ //
+ return((tDescriptorHeader *)0);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Determines the number of different alternate configurations for a given
+//! interface within a configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui8InterfaceNumber is the interface number for which the number of
+//! alternate configurations is to be counted.
+//!
+//! This function can be used to count the number of alternate settings for a
+//! specific interface within a configuration.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetNumAlternateInterfaces(), searches through
+//! a single, contiguous block of data to perform the same enumeration.
+//!
+//! \return Returns the number of alternate versions of the specified interface
+//! or 0 if the interface number supplied cannot be found in the configuration
+//! descriptor.
+//
+//*****************************************************************************
+uint32_t
+USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNumber)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32Count, ui32Sec;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pui8Data;
+ ui32Sec = 0;
+ ui32Count = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(psDescCheck)
+ {
+ //
+ // Is this an interface descriptor with the required interface number?
+ //
+ if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
+ (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
+ ui8InterfaceNumber))
+ {
+ //
+ // Yes - increment our count.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ psDescCheck = NextConfigDescGet(psConfig, &ui32Sec, psDescCheck);
+ }
+
+ //
+ // Return the descriptor count to the caller.
+ //
+ return(ui32Count);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Returns a pointer to the n-th interface descriptor in a configuration
+//! descriptor that applies to the supplied alternate setting number.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32Index is the zero based index of the interface that is to be
+//! found. If \e ui32Alt is set to a value other than \b USB_DESC_ANY, this
+//! is equivalent to the interface number being searched for.
+//! \param ui32Alt is the alternate setting number which is to be
+//! searched for. If this value is \b USB_DESC_ANY, the alternate setting
+//! is ignored and all interface descriptors are considered in the search.
+//! \param pui32Section points to storage which will receive the index of the
+//! config descriptor section which contains the requested interface
+//! descriptor.
+//!
+//! Return a pointer to the n-th interface descriptor found in the supplied
+//! configuration descriptor. If \e ui32Alt is not \b USB_DESC_ANY, only
+//! interface descriptors which are part of the supplied alternate setting are
+//! considered in the search otherwise all interface descriptors are
+//! considered.
+//!
+//! Note that, although alternate settings can be applied on an interface-by-
+//! interface basis, the number of interfaces offered is fixed for a given
+//! config descriptor. Hence, this function will correctly find the unique
+//! interface descriptor for that interface's alternate setting number \e
+//! ui32Alt if \e ui32Index is set to the required interface number and
+//! \e ui32Alt is set to a valid alternate setting number for that interface.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetInterface(), searches through a single,
+//! contiguous block of data to perform the same enumeration.
+//!
+//! \return Returns a pointer to the required interface descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tInterfaceDescriptor *
+USBDCDConfigGetInterface(const tConfigHeader *psConfig, uint32_t ui32Index,
+ uint32_t ui32Alt, uint32_t *pui32Section)
+{
+ //
+ // If we are being told to ignore the alternate configuration, this boils
+ // down to a very simple query.
+ //
+ if(ui32Alt == USB_DESC_ANY)
+ {
+ //
+ // Return the ui32Index-th interface descriptor we find in the
+ // configuration descriptor.
+ //
+ return((tInterfaceDescriptor *)USBDCDConfigDescGet(psConfig,
+ USB_DTYPE_INTERFACE,
+ ui32Index,
+ pui32Section));
+ }
+ else
+ {
+ //
+ // In this case, a specific alternate setting number is required.
+ // Given that interface numbers are zero based indices, we can
+ // pass the supplied ui32Index parameter directly as the interface
+ // number to USBDescGetAlternateInterface() to retrieve the requested
+ // interface descriptor pointer.
+ //
+ return(ConfigAlternateInterfaceGet(psConfig, ui32Index, ui32Alt,
+ pui32Section));
+ }
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Return a pointer to the n-th endpoint descriptor in a particular interface
+//! within a configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32InterfaceNumber is the interface number whose endpoint is to be
+//! found.
+//! \param ui32AltCfg is the alternate setting number which is to be searched
+//! for. This must be a valid alternate setting number for the requested
+//! interface.
+//! \param ui32Index is the zero based index of the endpoint that is to be
+//! found within the appropriate alternate setting for the interface.
+//!
+//! Return a pointer to the n-th endpoint descriptor found in the supplied
+//! interface descriptor. If the \e ui32Index parameter is invalid (greater
+//! than or equal to the bNumEndpoints field of the interface descriptor) or
+//! the endpoint descriptor cannot be found, the function will return NULL.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetInterfaceEndpoint(), searches through a
+//! single, contiguous block of data to perform the same enumeration.
+//!
+//! \return Returns a pointer to the requested endpoint descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tEndpointDescriptor *
+USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig,
+ uint32_t ui32InterfaceNumber,
+ uint32_t ui32AltCfg, uint32_t ui32Index)
+{
+ tInterfaceDescriptor *psInterface;
+ tDescriptorHeader *psEndpoint;
+ uint32_t ui32Section, ui32Count;
+
+ //
+ // Find the requested interface descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ui32InterfaceNumber,
+ ui32AltCfg, &ui32Section);
+
+ //
+ // Did we find the requested interface?
+ //
+ if(psInterface)
+ {
+ //
+ // Is the index passed valid?
+ //
+ if(ui32Index >= psInterface->bNumEndpoints)
+ {
+ //
+ // It's out of bounds so return a NULL.
+ //
+ return((tEndpointDescriptor *)0);
+ }
+ else
+ {
+ //
+ // Endpoint index is valid so find the descriptor. We start from
+ // the interface descriptor and look for following endpoint
+ // descriptors.
+ //
+ ui32Count = 0;
+ psEndpoint = (tDescriptorHeader *)psInterface;
+
+ while(psEndpoint)
+ {
+ if(psEndpoint->bDescriptorType == USB_DTYPE_ENDPOINT)
+ {
+ //
+ // We found an endpoint descriptor. Have we reached the
+ // one we want?
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Yes - return the descriptor pointer to the caller.
+ //
+ return((tEndpointDescriptor *)psEndpoint);
+ }
+
+ //
+ // Move on to look for the next endpoint.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move to the next descriptor.
+ //
+ psEndpoint = NextConfigDescGet(psConfig, &ui32Section,
+ psEndpoint);
+ }
+ }
+ }
+
+ //
+ // We could not find the requested interface or we got to the end of the
+ // descriptor without finding the requested endpoint.
+ //
+ return((tEndpointDescriptor *)0);
+
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdcomp.c b/usblib/device/usbdcomp.c new file mode 100644 index 0000000..727ed42 --- /dev/null +++ b/usblib/device/usbdcomp.c @@ -0,0 +1,1544 @@ +//****************************************************************************
+//
+// usbdcomp.c - USB composite device class driver.
+//
+// Copyright (c) 2010-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_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usb-ids.h"
+#include "usblib/usbcdc.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdcdc.h"
+#include "usblib/device/usbdcomp.h"
+
+//****************************************************************************
+//
+//! \addtogroup composite_device_class_api
+//! @{
+//
+//****************************************************************************
+
+//****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//****************************************************************************
+static uint8_t g_pui8CompDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_MISC, // USB Device Class (spec 5.1.1)
+ USB_MISC_SUBCLASS_COMMON, // USB Device Sub-class (spec 5.1.1)
+ USB_MISC_PROTOCOL_IAD, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during USBDCompositeInit).
+ USBShort(0), // Product ID (filled in during USBDCompositeInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//****************************************************************************
+//
+// Composite class device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//****************************************************************************
+static const uint8_t g_pui8CompConfigDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(0), // The total size of this full structure.
+ 0, // The number of interfaces in this
+ // configuration, this will be filled by
+ // the class as it discovers all classes
+ // supported.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_BUS_PWR, // .
+ 250, // The maximum power in 2mA increments.
+};
+
+//****************************************************************************
+//
+// Byte offsets used to access various fields in our index/interface/endpoint
+// lookup table (tUSBDCompositeDevice.pui32DeviceWorkspace). This workspace
+// contains one 4 byte entry per device. The LSB is the device index, next byte
+// is the number of the first interface not within this device, next byte is
+// the number of the first IN endpoint not within this device and the final
+// byte is the number of the first OUT endpoint not within this device. Using
+// this simple table we can reasonably quickly cross-reference index with
+// interface and endpoint numbers.
+//
+//****************************************************************************
+#define LOOKUP_INDEX_BYTE 0
+#define LOOKUP_INTERFACE_BYTE 1
+#define LOOKUP_IN_END_BYTE 2
+#define LOOKUP_OUT_END_BYTE 3
+
+//****************************************************************************
+//
+// A marker used to indicate an invalid index into the device table.
+//
+//****************************************************************************
+#define INVALID_DEVICE_INDEX 0xFFFFFFFF
+
+//****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//****************************************************************************
+static void HandleDisconnect(void *pvCompositeInstance);
+static void InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting);
+static void ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value);
+static void DataSent(void *pvCompositeInstance, uint32_t ui32Info);
+static void DataReceived(void *pvCompositeInstance, uint32_t ui32Info);
+static void HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status);
+static void HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest);
+static void SuspendHandler(void *pvCompositeInstance);
+static void ResumeHandler(void *pvCompositeInstance);
+static void ResetHandler(void *pvCompositeInstance);
+static void HandleDevice(void *pvCompositeInstance, uint32_t ui32Request,
+ void *pvRequestData);
+static void GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest);
+
+//****************************************************************************
+//
+// Configuration Descriptor.
+//
+//****************************************************************************
+tConfigHeader *g_ppCompConfigDescriptors[1];
+
+//****************************************************************************
+//
+// The device information structure for the USB Composite device.
+//
+//****************************************************************************
+const tCustomHandlers g_sCompHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ GetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ InterfaceChange,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ DataSent,
+
+ //
+ // ResetHandler
+ //
+ ResetHandler,
+
+ //
+ // SuspendHandler
+ //
+ SuspendHandler,
+
+ //
+ // ResumeHandler
+ //
+ ResumeHandler,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // DeviceHandler
+ //
+ HandleDevice,
+};
+
+//****************************************************************************
+//
+// Use the lookup table from the field pui32DeviceWorkspace in the
+// tUSBDCompositeDevice structure to determine which device to call given a
+// particular composite device interface number.
+//
+// The returned value is the index into psDevice->tCompositeEntry indicating
+// the device which contains this interface or INVALID_DEVICE_INDEX if no
+// device contains the passed interface number.
+//
+//****************************************************************************
+static uint32_t
+InterfaceToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Interface)
+{
+ uint32_t ui32Loop;
+ uint32_t ui32Lookup;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++)
+ {
+ //
+ // Get the look up value from the device.
+ //
+ ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace;
+ ui32Lookup = (ui32Lookup >> (8 * LOOKUP_INTERFACE_BYTE)) & 0xff;
+
+ //
+ // If the desired interface number is lower than the value in the
+ // current lookup table entry, we have found the desired device so
+ // return its index.
+ //
+ if(ui32Interface < ui32Lookup)
+ {
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we get here, an invalid interface number was passed so return a
+ // marker to indicate this.
+ //
+ return(INVALID_DEVICE_INDEX);
+}
+
+//****************************************************************************
+//
+// Use the lookup table from the field pui32DeviceWorkspace in the
+// tUSBDCompositeDevice structure to determine which device to call given a
+// particular composite device endpoint number.
+//
+// The returned value is the index into psDevice->tCompositeEntry indicating
+// the device which contains this endpoint or INVALID_DEVICE_INDEX if no
+// device contains the passed endpoint number.
+//
+//****************************************************************************
+static uint32_t
+EndpointToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Endpoint,
+ bool bInEndpoint)
+{
+ uint32_t ui32Loop, ui32EndpointByte, ui32Lookup;
+
+ //
+ // Are we considering an IN or OUT endpoint?
+ //
+ ui32EndpointByte = bInEndpoint ? LOOKUP_IN_END_BYTE : LOOKUP_OUT_END_BYTE;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++)
+ {
+ //
+ // Get the look up byte from the device.
+ //
+ ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace;
+ ui32Lookup = (ui32Lookup >> (ui32EndpointByte * 8)) & 0xff;
+
+ //
+ // If the desired endpoint number is lower than the value in the
+ // current lookup table entry, we have found the desired device so
+ // return its index.
+ //
+ if(ui32Endpoint < ui32Lookup)
+ {
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we get here, an invalid endpoint number was passed so return a
+ // marker to indicate this.
+ //
+ return(INVALID_DEVICE_INDEX);
+}
+
+
+//****************************************************************************
+//
+// This function will check if any device classes need a get descriptor
+// handler called.
+//
+//****************************************************************************
+static void
+GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the composite device pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Determine which device this request is intended for. We have to be
+ // careful here to send this to the callback for the correct device
+ // depending upon whether it is a request sent to the device, the interface
+ // or the endpoint.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ui32Idx = InterfaceToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ui32Idx = EndpointToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0x0F),
+ (psUSBRequest->wIndex & 0x80) ? true : false);
+ break;
+ }
+
+ //
+ // Requests sent to the device or any other recipient can't be
+ // handled here since we have no way of telling where they are
+ // supposed to be handled. As a result, we just stall them.
+ //
+ // If your composite device has some device-specific descriptors,
+ // you should add code here to handle them.
+ //
+ case USB_RTYPE_DEVICE:
+ case USB_RTYPE_OTHER:
+ default:
+ {
+ ui32Idx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ //
+ // Does this device have a GetDescriptor callback?
+ //
+ if(psDeviceInfo->psCallbacks->pfnGetDescriptor)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx;
+
+ //
+ // Call the device to retrieve the descriptor.
+ //
+ psDeviceInfo->psCallbacks->pfnGetDescriptor(
+ psCompDevice->psDevices[ui32Idx].pvInstance, psUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an suspend handler
+// called.
+//
+//****************************************************************************
+static void
+SuspendHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_SUSPEND,
+ 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnSuspendHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnSuspendHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an resume handler
+// called.
+//
+//****************************************************************************
+static void
+ResumeHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_RESUME,
+ 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnResumeHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnResumeHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an reset handler
+// called.
+//
+//****************************************************************************
+static void
+ResetHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has been connected.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance,
+ USB_EVENT_CONNECTED, 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnResetHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnResetHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called to handle data being set to the host so that the
+// application callback can be called when the data has been transferred.
+//
+//****************************************************************************
+static void
+DataSent(void *pvCompositeInstance, uint32_t ui32Info)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner;
+
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDataSent)
+ {
+ psDeviceInfo->psCallbacks->pfnDataSent(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called to handle data being received back from the host so
+// that the application callback can be called when the new data is ready.
+//
+//****************************************************************************
+static void
+DataReceived(void *pvCompositeInstance, uint32_t ui32Info)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner;
+
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDataReceived)
+ {
+ psDeviceInfo->psCallbacks->pfnDataReceived(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an endpoint handler
+// called.
+//
+//****************************************************************************
+static void
+HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Call each of the endpoint handlers. This may seem odd since we should
+ // only call the handler whose endpoint needs service. Unfortunately, if
+ // the device class driver is using uDMA, we have no way of knowing which
+ // handler to call (since ui32Status will be 0). Since the handlers are
+ // set up to ignore any callback that is not for them, this is safe.
+ //
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnEndpointHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnEndpointHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Status);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvCompositeInstance, uint32_t ui32Request,
+ void *pvRequestData)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDeviceHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Request,
+ pvRequestData);
+ }
+ }
+
+ if(psCompDevice->pfnCallback)
+ {
+ switch(ui32Request)
+ {
+ case USB_EVENT_LPM_RESUME:
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//****************************************************************************
+static void
+HandleDisconnect(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance,
+ USB_EVENT_DISCONNECTED, 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDisconnectHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnDisconnectHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// interface changes. It will be passed on to the device classes if they have
+// a handler for this function.
+//
+//****************************************************************************
+static void
+InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnInterfaceChange)
+ {
+ psDeviceInfo->psCallbacks->pfnInterfaceChange(
+ psCompDevice->psDevices[ui32Idx].pvInstance,
+ ui8InterfaceNum, ui8AlternateSetting);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes. It will be passed on to the device classes if they
+// have a handler for this function.
+//
+//****************************************************************************
+static void
+ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnConfigChange)
+ {
+ psDeviceInfo->psCallbacks->pfnConfigChange(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Value);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvCompositeInstance
+// \param psUSBRequest points to the request received.
+//
+// This call will be passed on to the device classes if they have a handler
+// for this function.
+//
+// \return None.
+//
+//****************************************************************************
+static void
+HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Determine which device this request is intended for. We have to be
+ // careful here to send this to the callback for the correct device
+ // depending upon whether it is a request sent to the device, the interface
+ // or the endpoint.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ui32Idx = InterfaceToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ui32Idx = EndpointToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0x0F),
+ (psUSBRequest->wIndex & 0x80) ? true : false);
+ break;
+ }
+
+ //
+ // Requests sent to the device or any other recipient can't be
+ // handled here since we have no way of telling where they are
+ // supposed to be handled. As a result, we just stall them.
+ //
+ // If your composite device has some device-specific requests that need
+ // to be handled at the device (rather than interface or endpoint)
+ // level, you should add code here to handle them.
+ //
+ case USB_RTYPE_DEVICE:
+ case USB_RTYPE_OTHER:
+ default:
+ {
+ ui32Idx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ //
+ // Does this device have a RequestHandler callback?
+ //
+ if(psDeviceInfo->psCallbacks->pfnRequestHandler)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx;
+
+ //
+ // Yes - call the device to retrieve the descriptor.
+ //
+ psDeviceInfo->psCallbacks->pfnRequestHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance,
+ psUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending interface number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeIfaceChange(tCompositeEntry *psCompDevice, uint8_t ui8Old,
+ uint8_t ui8New)
+{
+ uint8_t pui8Interfaces[2];
+
+ if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pui8Interfaces[0] = ui8Old;
+ pui8Interfaces[1] = ui8New;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->pvInstance, USB_EVENT_COMP_IFACE_CHANGE,
+ (void *)pui8Interfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending endpoint number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeEPChange(tCompositeEntry *psCompDevice, uint8_t ui8Old,
+ uint8_t ui8New)
+{
+ uint8_t pui8Interfaces[2];
+
+ if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pui8Interfaces[0] = ui8Old;
+ pui8Interfaces[1] = ui8New;
+
+ ui8New--;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->pvInstance, USB_EVENT_COMP_EP_CHANGE,
+ (void *)pui8Interfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function merges the configuration descriptors into a single multiple
+// instance device.
+//
+//****************************************************************************
+uint32_t
+BuildCompositeDescriptor(tUSBDCompositeDevice *psCompDevice)
+{
+ uint32_t ui32Idx, ui32Offset, ui32CPIdx, ui32FixINT, ui32Dev;
+ uint16_t ui16TotalLength, ui16Bytes;
+ uint8_t ui8Interface, ui8INEndpoint, ui8OUTEndpoint;
+ uint8_t *pui8Data, *pui8Config;
+ const tConfigHeader *psConfigHeader;
+ tDescriptorHeader *psHeader;
+ const uint8_t *pui8Descriptor;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ const tDeviceInfo *psDevice;
+
+ //
+ // Save the number of devices to look through.
+ //
+ ui32Dev = 0;
+ ui32Idx = 0;
+ ui8Interface = 0;
+ ui8INEndpoint = 1;
+ ui8OUTEndpoint = 1;
+ ui32Offset = 0;
+ ui32FixINT = 0;
+
+ //
+ // This puts the first section pointer in the first entry in the list
+ // of sections.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[0] =
+ &psCompDevice->sPrivateData.psCompSections[0];
+
+ //
+ // Put the pointer to this instances configuration descriptor into the
+ // front of the list.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[0]->pui8Data =
+ (uint8_t *)&psCompDevice->sPrivateData.sConfigDescriptor;
+
+ psCompDevice->sPrivateData.ppsCompSections[0]->ui16Size =
+ psCompDevice->sPrivateData.sConfigDescriptor.bLength;
+
+ //
+ // The configuration descriptor is 9 bytes so initialize the total length
+ // to 9 bytes.
+ //
+ ui16TotalLength = 9;
+
+ //
+ // Copy the section pointer into the section array for the composite
+ // device. This is awkward but is required given the definition
+ // of the structures.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[1] =
+ &psCompDevice->sPrivateData.psCompSections[1];
+
+ //
+ // Copy the pointer to the application supplied space into the section
+ // list.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = 0;
+ psCompDevice->sPrivateData.ppsCompSections[1]->pui8Data =
+ psCompDevice->sPrivateData.pui8Data;
+
+ //
+ // Create a local pointer to the data that is used to copy data from
+ // the other devices into the composite descriptor.
+ //
+ pui8Data = psCompDevice->sPrivateData.pui8Data;
+
+ //
+ // Consider each device in turn.
+ //
+ while(ui32Dev < psCompDevice->ui32NumDevices)
+ {
+ //
+ // Save the current starting address of this descriptor.
+ //
+ pui8Config = pui8Data + ui32Offset;
+
+ //
+ // Create a local pointer to the configuration header.
+ //
+ psDevice = psCompDevice->psDevices[ui32Dev].psDevInfo;
+ psConfigHeader = psDevice->ppsConfigDescriptors[0];
+
+ //
+ // Loop through each of the sections in this device's configuration
+ // descriptor.
+ //
+ for(ui32Idx = 0; ui32Idx < psConfigHeader->ui8NumSections; ui32Idx++)
+ {
+ //
+ // Initialize the local offset in this descriptor. We include
+ // a special case here to ignore the initial 9 byte configuration
+ // descriptor since this has already been handled.
+ //
+ if(ui32Idx)
+ {
+ //
+ // This is not the first section so we handle everything in
+ // it.
+ //
+ ui16Bytes = 0;
+ }
+ else
+ {
+ //
+ // This is the first section for this device so skip the 9
+ // byte configuration descriptor since we've already handled
+ // this.
+ //
+ ui16Bytes = 9;
+
+ //
+ // If this section includes only the configuration descriptor,
+ // skip it entirely.
+ //
+ if(psConfigHeader->psSections[ui32Idx]->ui16Size <= ui16Bytes)
+ {
+ continue;
+ }
+ }
+
+ //
+ // Get a pointer to the configuration descriptor.
+ //
+ pui8Descriptor = psConfigHeader->psSections[ui32Idx]->pui8Data;
+
+ //
+ // Bounds check the allocated space and return if there is not
+ // enough space.
+ //
+ if(ui32Offset > psCompDevice->sPrivateData.ui32DataSize)
+ {
+ return(1);
+ }
+
+ //
+ // Copy the descriptor from the device into the descriptor list.
+ //
+ for(ui32CPIdx = 0;
+ ui32CPIdx < psConfigHeader->psSections[ui32Idx]->ui16Size;
+ ui32CPIdx++)
+ {
+ pui8Data[ui32CPIdx + ui32Offset] = pui8Descriptor[ui32CPIdx];
+ }
+
+ //
+ // Read out the descriptors in this section.
+ //
+ while(ui16Bytes < psConfigHeader->psSections[ui32Idx]->ui16Size)
+ {
+ //
+ // Create a descriptor header pointer.
+ //
+ psHeader = (tDescriptorHeader *)&pui8Data[ui32Offset +
+ ui16Bytes];
+
+ //
+ // Check for interface descriptors and modify the numbering to
+ // match the composite device.
+ //
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // See if this is an alternate setting or the initial
+ // setting.
+ //
+ if(psInterface->bAlternateSetting != 0)
+ {
+ //
+ // If this is an alternate setting then use the
+ // previous interface number because the current one
+ // has already been incremented.
+ //
+ psInterface->bInterfaceNumber = ui8Interface - 1;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeIfaceChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psInterface->bInterfaceNumber,
+ ui8Interface);
+ //
+ // This was the non-alternate setting so save the
+ // value and move to the next interface number.
+ //
+ psInterface->bInterfaceNumber = ui8Interface;
+
+ //
+ // No strings allowed on interface descriptors for
+ // composite devices.
+ //
+ psInterface->iInterface = 0;
+
+ ui8Interface++;
+ }
+ }
+ //
+ // Check for endpoint descriptors and modify the numbering to
+ // match the composite device.
+ //
+ else if(psHeader->bDescriptorType == USB_DTYPE_ENDPOINT)
+ {
+ psEndpoint = (tEndpointDescriptor *)psHeader;
+
+ //
+ // Check if this is an IN or OUT endpoint.
+ //
+ if(psEndpoint->bEndpointAddress & USB_RTYPE_DIR_IN)
+ {
+ //
+ // Check if this is the special Fixed Interrupt class
+ // and this is the interrupt endpoint.
+ //
+ if(((psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT) &&
+ (psCompDevice->ui16PID == USB_PID_COMP_SERIAL))
+ {
+ //
+ // Check if the Fixed Interrupt endpoint has been
+ // set yet.
+ //
+ if(ui32FixINT == 0)
+ {
+ //
+ // Allocate the fixed interrupt endpoint and
+ // save its number.
+ //
+ ui32FixINT = ui8INEndpoint++;
+ }
+
+ CompositeEPChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui32FixINT);
+
+ psEndpoint->bEndpointAddress = ui32FixINT |
+ USB_RTYPE_DIR_IN;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui8INEndpoint);
+
+ psEndpoint->bEndpointAddress = ui8INEndpoint++ |
+ USB_RTYPE_DIR_IN;
+ }
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(&psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui8OUTEndpoint);
+ psEndpoint->bEndpointAddress = ui8OUTEndpoint++;
+ }
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui16Bytes += psHeader->bLength;
+ }
+
+ ui32Offset += psConfigHeader->psSections[ui32Idx]->ui16Size;
+
+ ui16TotalLength += ui16Bytes;
+ }
+
+ //
+ // Allow the device class to make adjustments to the configuration
+ // descriptor.
+ //
+ psCompDevice->psDevices[ui32Dev].psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->psDevices[ui32Dev].pvInstance,
+ USB_EVENT_COMP_CONFIG, (void *)pui8Config);
+
+ //
+ // Add an entry into the device workspace array to allow us to quickly
+ // map interface and endpoint numbers to device instances later.
+ //
+ psCompDevice->psDevices[ui32Dev].ui32DeviceWorkspace =
+ (ui32Dev << (LOOKUP_INDEX_BYTE * 8)) |
+ (ui8Interface << (LOOKUP_INTERFACE_BYTE * 8)) |
+ (ui8OUTEndpoint << (LOOKUP_OUT_END_BYTE * 8)) |
+ (ui8INEndpoint << (LOOKUP_IN_END_BYTE * 8));
+
+ //
+ // Move on to the next device.
+ //
+ ui32Dev++;
+ }
+
+ //
+ // Modify the configuration descriptor to match the number of interfaces
+ // and the new total size.
+ //
+ psCompDevice->sPrivateData.sCompConfigHeader.ui8NumSections = 2;
+ psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = ui32Offset;
+ psCompDevice->sPrivateData.sConfigDescriptor.bNumInterfaces =
+ ui8Interface;
+ psCompDevice->sPrivateData.sConfigDescriptor.wTotalLength =
+ ui16TotalLength;
+
+
+ return(0);
+}
+
+//****************************************************************************
+//
+//! This function should be called once for the composite class device to
+//! initialize basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! composite device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the composite device.
+//! \param ui32Size is the size in bytes of the data pointed to by the
+//! \e pui8Data parameter.
+//! \param pui8Data is the data area that the composite class can use to build
+//! up descriptors.
+//!
+//! In order for an application to initialize the USB composite device class,
+//! it must first call this function with the a valid composite device class
+//! structure in the \e psDevice parameter. This allows this function to
+//! initialize the USB controller and device code to be prepared to enumerate
+//! and function as a USB composite device. The \e ui32Size and \e pui8Data
+//! parameters should be large enough to hold all of the class instances
+//! passed in via the \e psDevice structure. This is typically the full size
+//! of the configuration descriptor for a device minus its configuration
+//! header(9 bytes).
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the composite class.
+//!
+//! See the documentation on the tUSBDCompositeDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return This function returns 0 on failure or a non-zero void pointer on
+//! success.
+//
+//****************************************************************************
+void *
+USBDCompositeInit(uint32_t ui32Index, tUSBDCompositeDevice *psDevice,
+ uint32_t ui32Size, uint8_t *pui8Data)
+{
+ tCompositeInstance *psInst;
+ int32_t i32Idx;
+ uint8_t *pui8Temp;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppui8StringDescriptors);
+
+ //
+ // Initialize the work space in the passed instance structure.
+ //
+ psInst = &psDevice->sPrivateData;
+ psInst->ui32DataSize = ui32Size;
+ psInst->pui8Data = pui8Data;
+
+ //
+ // Save the base address of the USB controller.
+ //
+ psInst->ui32USBBase = USBIndexToBase(ui32Index);
+
+ //
+ // No device is currently transferring data on EP0.
+ //
+ psInst->ui32EP0Owner = INVALID_DEVICE_INDEX;
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sCompHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8CompDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors =
+ (const tConfigHeader * const *)g_ppCompConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the composite device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ g_ppCompConfigDescriptors[0] = &psInst->sCompConfigHeader;
+ g_ppCompConfigDescriptors[0]->ui8NumSections = 0;
+ g_ppCompConfigDescriptors[0]->psSections =
+ (const tConfigSection * const *)psDevice->sPrivateData.ppsCompSections;
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pui8Temp = (uint8_t *)&psInst->sConfigDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(i32Idx = 0; i32Idx < g_pui8CompConfigDescriptor[0]; i32Idx++)
+ {
+ pui8Temp[i32Idx] = g_pui8CompConfigDescriptor[i32Idx];
+ }
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pui8Temp = (uint8_t *)&psInst->sDeviceDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(i32Idx = 0; i32Idx < g_pui8CompDeviceDescriptor[0]; i32Idx++)
+ {
+ pui8Temp[i32Idx] = g_pui8CompDeviceDescriptor[i32Idx];
+ }
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psInst->sDeviceDescriptor.idVendor = psDevice->ui16VID;
+ psInst->sDeviceDescriptor.idProduct = psDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->sConfigDescriptor.bmAttributes = psDevice->ui8PwrAttributes;
+ psInst->sConfigDescriptor.bMaxPower =
+ (uint8_t)(psDevice->ui16MaxPowermA>>1);
+
+ psInst->sDevInfo.pui8DeviceDescriptor =
+ (const uint8_t *)&psInst->sDeviceDescriptor;
+
+ //
+ // Plug in the client's string table to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psDevice->ui32NumStringDescriptors;
+
+ //
+ // Enable Clocking to the USB controller so that changes to the USB
+ // controller can be made in the BuildCompositeDescriptor() function.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Create the combined descriptors.
+ //
+ if(BuildCompositeDescriptor(psDevice))
+ {
+ return(0);
+ }
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psInst->sDevInfo, (void *)psDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went
+ // well.
+ //
+ return((void *)psDevice);
+}
+
+//****************************************************************************
+//
+//! Shuts down the composite device.
+//!
+//! \param pvCompositeInstance is the pointer to the device instance structure
+//! as returned by USBDCompositeInit().
+//!
+//! This function terminates composite device interface for the instance
+//! not me supplied. Following this call, the \e pvCompositeInstance instance
+//! should not be used in any other calls.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+USBDCompositeTerm(void *pvCompositeInstance)
+{
+ ASSERT(pvCompositeInstance != 0);
+
+}
+
+//****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//****************************************************************************
+
diff --git a/usblib/device/usbdcomp.h b/usblib/device/usbdcomp.h new file mode 100644 index 0000000..e064193 --- /dev/null +++ b/usblib/device/usbdcomp.h @@ -0,0 +1,261 @@ +//*****************************************************************************
+//
+// usbdcomp.h - USB composite device class driver.
+//
+// Copyright (c) 2010-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.
+//
+//*****************************************************************************
+
+#ifndef __USBDCOMP_H__
+#define __USBDCOMP_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup composite_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//
+// Defines a single entry in a table of device types supported by the composite
+// device.
+//
+typedef struct
+{
+ //
+ // This is set internally by the composite class so it can be left
+ // uninitialized by the application.
+ //
+ const tDeviceInfo *psDeviceInfo;
+
+ //
+ // This should be the header to the configuration header for a class.
+ //
+ const tConfigHeader *psConfigHeader;
+
+ //
+ // The offset to this devices interface, filled in by the composite class.
+ //
+ uint8_t ui8IfaceOffset;
+}
+tUSBDCompositeEntry;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// composite device class. The memory for this structure is included in
+// the sPrivateData field in the tUSBDCompositeDevice structure passed on
+// USBDCompositeInit() and should not be modified by any code outside of the
+// composite device code.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Saves which USB controller is in use.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device information pointer.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // This is the configuration descriptor for this instance.
+ //
+ tConfigDescriptor sConfigDescriptor;
+
+ //
+ // This is the device descriptor for this instance.
+ //
+ tDeviceDescriptor sDeviceDescriptor;
+
+ //
+ // The configuration header for this instance.
+ //
+ tConfigHeader sCompConfigHeader;
+
+ //
+ // These are the configuration sections that will be built from the
+ // Configuration Descriptor header and the descriptors from the devices
+ // that are part of this composite device.
+ //
+ tConfigSection psCompSections[2];
+ tConfigSection *ppsCompSections[2];
+
+ //
+ // The size and pointer to the data used by the instance.
+ //
+ uint32_t ui32DataSize;
+ uint8_t *pui8Data;
+
+ //
+ // The current "owner" of endpoint 0. This is used to track the device
+ // class which is currently transferring data on EP0.
+ //
+ uint32_t ui32EP0Owner;
+}
+tCompositeInstance;
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the composite device class.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in mA.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self or bus-powered and whether or not
+ //! it supports remote wake up. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the composite
+ //! device.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1), Composite
+ //! device interface description string (language 1), Configuration
+ //! description string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (number of strings)) *
+ //! (number of languages)).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The number of devices in the psDevices array.
+ //
+ const uint32_t ui32NumDevices;
+
+ //
+ //! This application supplied array holds the the top level device class
+ //! information as well as the Instance data for that class.
+ //
+ tCompositeEntry * const psDevices;
+
+ //
+ //! The private data for this device instance. This memory must remain
+ //! accessible for as long as the composite device is in use and must
+ //! not be modified by any code outside the composite class driver.
+ //
+ tCompositeInstance sPrivateData;
+}
+tUSBDCompositeDevice;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// Composite specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDCompositeInit(uint32_t ui32Index,
+ tUSBDCompositeDevice *psCompDevice,
+ uint32_t ui32Size, uint8_t *pui8Data);
+extern void USBDCompositeTerm(void *pvInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/usblib/device/usbdconfig.c b/usblib/device/usbdconfig.c new file mode 100644 index 0000000..0a100cc --- /dev/null +++ b/usblib/device/usbdconfig.c @@ -0,0 +1,555 @@ +//*****************************************************************************
+//
+// usbdconfig.c - High level USB device configuration function.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Structure used in compiling FIFO size and endpoint properties from a
+// configuration descriptor.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint32_t pui32Size[2];
+}
+tUSBEndpointInfo;
+
+//*****************************************************************************
+//
+// Indices used when accessing the tUSBEndpointInfo structure.
+//
+//*****************************************************************************
+#define EP_INFO_IN 0
+#define EP_INFO_OUT 1
+
+//*****************************************************************************
+//
+// Given a maximum packet size and the user's FIFO scaling requirements,
+// determine the flags to use to configure the endpoint FIFO and the number
+// of bytes of FIFO space occupied.
+//
+//*****************************************************************************
+static uint32_t
+GetEndpointFIFOSize(uint32_t ui32MaxPktSize, uint32_t *pupBytesUsed)
+{
+ uint32_t ui32Loop, ui32FIFOSize;
+
+ //
+ // Now we need to find the nearest supported size that accommodates the
+ // requested size. Step through each of the supported sizes until we
+ // find one that will do.
+ //
+ for(ui32Loop = USB_FIFO_SZ_8; ui32Loop <= USB_FIFO_SZ_2048; ui32Loop++)
+ {
+ //
+ // How many bytes does this FIFO value represent?
+ //
+ ui32FIFOSize = USBFIFOSizeToBytes(ui32Loop);
+
+ //
+ // Is this large enough to hold one packet.
+ //
+ if(ui32FIFOSize >= ui32MaxPktSize)
+ {
+ //
+ // Return the FIFO size setting and the USB_FIFO_SZ_ value.
+ //
+ *pupBytesUsed = ui32FIFOSize;
+
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we drop out, we can't support the FIFO size requested. Signal a
+ // problem by returning 0 in the pBytesUsed
+ //
+ *pupBytesUsed = 0;
+
+ return(USB_FIFO_SZ_8);
+}
+
+//*****************************************************************************
+//
+// Translate a USB endpoint descriptor into the values we need to pass to the
+// USBDevEndpointConfigSet() API.
+//
+//*****************************************************************************
+static void
+GetEPDescriptorType(tEndpointDescriptor *psEndpoint, uint32_t *pui32EPIndex,
+ uint32_t *pui32MaxPktSize, uint32_t *pui32Flags)
+{
+ //
+ // Get the endpoint index.
+ //
+ *pui32EPIndex = psEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+
+ //
+ // Extract the maximum packet size.
+ //
+ *pui32MaxPktSize = psEndpoint->wMaxPacketSize & USB_EP_MAX_PACKET_COUNT_M;
+
+ //
+ // Is this an IN or an OUT endpoint?
+ //
+ *pui32Flags = (psEndpoint->bEndpointAddress & USB_EP_DESC_IN) ?
+ USB_EP_DEV_IN : USB_EP_DEV_OUT;
+
+ //
+ // Set the endpoint mode.
+ //
+ switch(psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M)
+ {
+ case USB_EP_ATTR_CONTROL:
+ {
+ *pui32Flags |= USB_EP_MODE_CTRL;
+ break;
+ }
+ case USB_EP_ATTR_BULK:
+ {
+ *pui32Flags |= USB_EP_MODE_BULK;
+ break;
+ }
+ case USB_EP_ATTR_INT:
+ {
+ *pui32Flags |= USB_EP_MODE_INT;
+ break;
+ }
+ case USB_EP_ATTR_ISOC:
+ {
+ *pui32Flags |= USB_EP_MODE_ISOC;
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Configure the USB controller appropriately for the device whose
+//! configuration descriptor is passed.
+//!
+//! \param psDevInst is a pointer to the device instance being configured.
+//! \param psConfig is a pointer to the configuration descriptor that the
+//! USB controller is to be set up to support.
+//!
+//! This function may be used to initialize a USB controller to operate as
+//! the device whose configuration descriptor is passed. The function
+//! enables the USB controller, partitions the FIFO appropriately and
+//! configures each endpoint required by the configuration. If the supplied
+//! configuration supports multiple alternate settings for any interface,
+//! the USB FIFO is set up assuming the worst case use (largest packet size
+//! for a given endpoint in any alternate setting using that endpoint) to
+//! allow for on-the-fly alternate setting changes later. On return from this
+//! function, the USB controller is configured for correct operation of
+//! the default configuration of the device described by the descriptor passed.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+USBDeviceConfig(tDCDInstance *psDevInst, const tConfigHeader *psConfig)
+{
+ uint32_t ui32Loop, ui32Count, ui32NumInterfaces, ui32EpIndex, ui32EpType,
+ ui32MaxPkt, ui32NumEndpoints, ui32Flags, ui32BytesUsed,
+ ui32Section;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ tUSBEndpointInfo psEPInfo[NUM_USB_EP - 1];
+
+ //
+ // A valid device instance is required.
+ //
+ ASSERT(psDevInst != 0);
+
+ //
+ // Catch bad pointers in a debug build.
+ //
+ ASSERT(psConfig);
+
+ //
+ // Clear out our endpoint info.
+ //
+ for(ui32Loop = 0; ui32Loop < (NUM_USB_EP - 1); ui32Loop++)
+ {
+ psEPInfo[ui32Loop].pui32Size[EP_INFO_IN] = 0;
+ psEPInfo[ui32Loop].pui32Size[EP_INFO_OUT] = 0;
+ }
+
+ //
+ // How many (total) endpoints does this configuration describe?
+ //
+ ui32NumEndpoints = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_ENDPOINT);
+
+ //
+ // How many interfaces are included?
+ //
+ ui32NumInterfaces = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_INTERFACE);
+
+ //
+ // Look at each endpoint and determine the largest max packet size for
+ // each endpoint. This will determine how we partition the USB FIFO.
+ //
+ for(ui32Loop = 0; ui32Loop < ui32NumEndpoints; ui32Loop++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = (tEndpointDescriptor *)USBDCDConfigDescGet(
+ psConfig, USB_DTYPE_ENDPOINT, ui32Loop,
+ &ui32Section);
+
+ //
+ // Extract the endpoint number and whether it is an IN or OUT
+ // endpoint.
+ //
+ ui32EpIndex = (uint32_t)
+ psEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+ ui32EpType = (psEndpoint->bEndpointAddress & USB_EP_DESC_IN) ?
+ EP_INFO_IN : EP_INFO_OUT;
+
+ //
+ // Make sure the endpoint number is valid for our controller. If not,
+ // return false to indicate an error. Note that 0 is invalid since
+ // you shouldn't reference endpoint 0 in the config descriptor.
+ //
+ if((ui32EpIndex >= NUM_USB_EP) || (ui32EpIndex == 0))
+ {
+ return(false);
+ }
+
+ //
+ // Does this endpoint have a max packet size requirement larger than
+ // any previous use we have seen?
+ //
+ if(psEndpoint->wMaxPacketSize >
+ psEPInfo[ui32EpIndex - 1].pui32Size[ui32EpType])
+ {
+ //
+ // Yes - remember the new maximum packet size.
+ //
+ psEPInfo[ui32EpIndex - 1].pui32Size[ui32EpType] =
+ psEndpoint->wMaxPacketSize;
+ }
+ }
+
+ //
+ // At this point, we have determined the maximum packet size required
+ // for each endpoint by any possible alternate setting of any interface
+ // in this configuration. Now determine the endpoint settings required
+ // for the interface setting we are actually going to use.
+ //
+ 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 default interface (bAlternateSetting set to 0)?
+ //
+ if(psInterface && (psInterface->bAlternateSetting == 0))
+ {
+ //
+ // This is an interface we are interested in so gather the
+ // information on its endpoints.
+ //
+ ui32NumEndpoints = (uint32_t)psInterface->bNumEndpoints;
+
+ //
+ // Walk through each endpoint in this interface and configure
+ // it appropriately.
+ //
+ for(ui32Count = 0; ui32Count < ui32NumEndpoints; ui32Count++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = USBDCDConfigGetInterfaceEndpoint(psConfig,
+ psInterface->bInterfaceNumber,
+ psInterface->bAlternateSetting,
+ ui32Count);
+
+ //
+ // Make sure we got a good pointer.
+ //
+ if(psEndpoint)
+ {
+ //
+ // Determine maximum packet size and flags from the
+ // endpoint descriptor.
+ //
+ GetEPDescriptorType(psEndpoint, &ui32EpIndex, &ui32MaxPkt,
+ &ui32Flags);
+
+ //
+ // Make sure no-one is trying to configure endpoint 0.
+ //
+ if(!ui32EpIndex)
+ {
+ return(false);
+ }
+
+ //
+ // Set the endpoint configuration.
+ //
+ USBDevEndpointConfigSet(USB0_BASE,
+ IndexToUSBEP(ui32EpIndex),
+ ui32MaxPkt, ui32Flags);
+ }
+ }
+ }
+ }
+
+ //
+ // At this point, we have configured all the endpoints that are to be
+ // used by this configuration's alternate setting 0. Now we go on and
+ // partition the FIFO based on the maximum packet size information we
+ // extracted earlier. Endpoint 0 is automatically configured to use the
+ // first MAX_PACKET_SIZE_EP0 bytes of the FIFO so we start from there.
+ //
+ ui32Count = MAX_PACKET_SIZE_EP0;
+ for(ui32Loop = 1; ui32Loop < NUM_USB_EP; ui32Loop++)
+ {
+ //
+ // Configure the IN endpoint at this index if it is referred to
+ // anywhere.
+ //
+ if(psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_IN])
+ {
+ //
+ // What FIFO size flag do we use for this endpoint?
+ //
+ ui32MaxPkt = GetEndpointFIFOSize(
+ psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_IN],
+ &ui32BytesUsed);
+
+ //
+ // The FIFO space could not be allocated.
+ //
+ if(ui32BytesUsed == 0)
+ {
+ return(false);
+ }
+
+ //
+ // Now actually configure the FIFO for this endpoint.
+ //
+ USBFIFOConfigSet(USB0_BASE, IndexToUSBEP(ui32Loop), ui32Count,
+ ui32MaxPkt, USB_EP_DEV_IN);
+ ui32Count += ui32BytesUsed;
+ }
+
+ //
+ // Configure the OUT endpoint at this index.
+ //
+ if(psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_OUT])
+ {
+ //
+ // What FIFO size flag do we use for this endpoint?
+ //
+ ui32MaxPkt = GetEndpointFIFOSize(
+ psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_OUT],
+ &ui32BytesUsed);
+
+ //
+ // The FIFO space could not be allocated.
+ //
+ if(ui32BytesUsed == 0)
+ {
+ return(false);
+ }
+
+ //
+ // Now actually configure the FIFO for this endpoint.
+ //
+ USBFIFOConfigSet(USB0_BASE, IndexToUSBEP(ui32Loop), ui32Count,
+ ui32MaxPkt, USB_EP_DEV_OUT);
+ ui32Count += ui32BytesUsed;
+ }
+
+ }
+
+ //
+ // If we get to the end, all is well.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+//! Configure the affected USB endpoints appropriately for one alternate
+//! interface setting.
+//!
+//! \param psDevInst is a pointer to the device instance being configured.
+//! \param psConfig is a pointer to the configuration descriptor that contains
+//! the interface whose alternate settings is to be configured.
+//! \param ui8InterfaceNum is the number of the interface whose alternate
+//! setting is to be configured. This number corresponds to the
+//! bInterfaceNumber field in the desired interface descriptor.
+//! \param ui8AlternateSetting is the alternate setting number for the desired
+//! interface. This number corresponds to the bAlternateSetting field in the
+//! desired interface descriptor.
+//!
+//! This function may be used to reconfigure the endpoints of an interface
+//! for operation in one of the interface's alternate settings. Note that this
+//! function assumes that the endpoint FIFO settings will not need to change
+//! and only the endpoint mode is changed. This assumption is valid if the
+//! USB controller was initialized using a previous call to USBDCDConfig().
+//!
+//! In reconfiguring the interface endpoints, any additional configuration
+//! bits set in the endpoint configuration other than the direction (\b
+//! USB_EP_DEV_IN or \b USB_EP_DEV_OUT) and mode (\b USB_EP_MODE_MASK) are
+//! preserved.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+USBDeviceConfigAlternate(tDCDInstance *psDevInst,
+ const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting)
+{
+ uint32_t ui32NumInterfaces, ui32NumEndpoints, ui32Loop, ui32Count,
+ ui32MaxPkt, ui32Flags, ui32Section, ui32EpIndex;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+
+ //
+ // 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 default interface (bAlternateSetting set to 0)?
+ //
+ if(psInterface &&
+ (psInterface->bInterfaceNumber == ui8InterfaceNum) &&
+ (psInterface->bAlternateSetting == ui8AlternateSetting))
+ {
+ //
+ // This is an interface we are interested in and the descriptor
+ // representing the alternate setting we want so go ahead and
+ // reconfigure the endpoints.
+ //
+
+ //
+ // How many endpoints does this interface have?
+ //
+ ui32NumEndpoints = (uint32_t)psInterface->bNumEndpoints;
+
+ //
+ // Walk through each endpoint in turn.
+ //
+ for(ui32Count = 0; ui32Count < ui32NumEndpoints; ui32Count++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = USBDCDConfigGetInterfaceEndpoint(psConfig,
+ psInterface->bInterfaceNumber,
+ psInterface->bAlternateSetting,
+ ui32Count);
+
+ //
+ // Make sure we got a good pointer.
+ //
+ if(psEndpoint)
+ {
+ //
+ // Determine maximum packet size and flags from the
+ // endpoint descriptor.
+ //
+ GetEPDescriptorType(psEndpoint, &ui32EpIndex, &ui32MaxPkt,
+ &ui32Flags);
+
+ //
+ // Make sure no-one is trying to configure endpoint 0.
+ //
+ if(!ui32EpIndex)
+ {
+ return(false);
+ }
+
+ //
+ // Set the endpoint configuration.
+ //
+ USBDevEndpointConfigSet(USB0_BASE,
+ IndexToUSBEP(ui32EpIndex),
+ ui32MaxPkt, ui32Flags);
+ }
+ }
+
+ //
+ // At this point, we have reconfigured the desired interface so
+ // return indicating all is well.
+ //
+ return(true);
+ }
+ }
+
+ return(false);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbddfu-rt.c b/usblib/device/usbddfu-rt.c new file mode 100644 index 0000000..24adb26 --- /dev/null +++ b/usblib/device/usbddfu-rt.c @@ -0,0 +1,661 @@ +//*****************************************************************************
+//
+// usbddfu-rt.c - USB Device Firmware Update runtime device class driver.
+//
+// Copyright (c) 2010-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_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_nvic.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/systick.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbdfu.h"
+#include "usblib/usb-ids.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbddfu-rt.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup dfu_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// DFU Device Descriptor. This is a dummy structure since runtime DFU must be
+// a part of a composite device and cannot be instantiated on its own.
+//
+//*****************************************************************************
+const uint8_t g_pui8DFUDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts
+ // assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_VEND_SPECIFIC, // USB Device Class
+ 0, // USB Device Sub-class
+ 0, // USB Device protocol
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (VID).
+ USBShort(0), // Product ID (PID).
+ USBShort(0), // Device Release Number BCD.
+ 0, // Manufacturer string identifier.
+ 0, // Product string identifier.
+ 0, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// DFU device runtime configuration descriptor. This is also a dummy structure
+// since the primary device class configuration will be used when DFU is added
+// to the composite device.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUConfigDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(27), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes
+ // this configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake
+ // up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The DFU runtime interface descriptor.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUInterface[DFUINTERFACE_SIZE] =
+{
+ //
+ // Interface descriptor for runtime DFU operation.
+ //
+ 9, // Length of this descriptor.
+ USB_DTYPE_INTERFACE, // This is an interface descriptor.
+ 0, // Interface number .
+ 0, // Alternate setting number.
+ 0, // Number of endpoints (only endpoint 0
+ // used)
+ USB_CLASS_APP_SPECIFIC, // Application specific interface class
+ USB_DFU_SUBCLASS, // Device Firmware Upgrade subclass
+ USB_DFU_RUNTIME_PROTOCOL, // DFU runtime protocol
+ 0, // No string descriptor for this interface.
+};
+
+//*****************************************************************************
+//
+// The DFU functional descriptor.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUFunctionalDesc[DFUFUNCTIONALDESC_SIZE] =
+{
+ //
+ // Device Firmware Upgrade functional descriptor.
+ //
+ 9, // Length of this descriptor.
+ USB_DFU_FUNC_DESCRIPTOR_TYPE, // DFU Functional descriptor type
+ (DFU_ATTR_CAN_DOWNLOAD | // DFU attributes.
+ DFU_ATTR_CAN_UPLOAD |
+ DFU_ATTR_WILL_DETACH |
+ DFU_ATTR_MANIFEST_TOLERANT),
+ USBShort(0xFFFF), // Detach timeout (set to maximum).
+ USBShort(DFU_TRANSFER_SIZE), // Transfer size 1KB.
+ USBShort(0x0110) // DFU Version 1.1
+};
+
+//*****************************************************************************
+//
+// The DFU runtime configuration descriptor is defined as two sections.
+// These sections are:
+//
+// 1. The 9 byte configuration descriptor.
+// 2. The interface descriptor + DFU functional descriptor.
+//
+//*****************************************************************************
+const tConfigSection g_sDFUConfigSection =
+{
+ sizeof(g_pui8DFUConfigDescriptor),
+ g_pui8DFUConfigDescriptor
+};
+
+const tConfigSection g_sDFUInterfaceSection =
+{
+ sizeof(g_pui8DFUInterface),
+ g_pui8DFUInterface
+};
+
+const tConfigSection g_sDFUFunctionalDescSection =
+{
+ sizeof(g_pui8DFUFunctionalDesc),
+ g_pui8DFUFunctionalDesc
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete DFU runtime configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psDFUSections[] =
+{
+ &g_sDFUConfigSection,
+ &g_sDFUInterfaceSection,
+ &g_sDFUFunctionalDescSection
+};
+
+#define NUM_DFU_SECTIONS (sizeof(g_psDFUSections) / \
+ sizeof(g_psDFUSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+tConfigHeader g_sDFUConfigHeader =
+{
+ NUM_DFU_SECTIONS,
+ g_psDFUSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppsDFUConfigDescriptors[] =
+{
+ &g_sDFUConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleGetDescriptor(void *pvDFUInstance, tUSBRequest *psUSBRequest);
+static void HandleRequest(void *pvDFUInstance, tUSBRequest *psUSBRequest);
+static void HandleDevice(void *pvDFUInstance, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB DFU devices.
+//
+//*****************************************************************************
+static const tCustomHandlers g_sDFUHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ HandleGetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequest,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ 0,
+
+ //
+ // DataReceived
+ //
+ 0,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ 0,
+
+ //
+ //
+
+ //
+ // ResumeHandler
+ //
+ 0,
+
+ //
+ // DisconnectHandler
+ //
+ 0,
+
+ //
+ // EndpointHandler
+ //
+ 0,
+
+ //
+ // Device handler.
+ //
+ HandleDevice,
+};
+
+//*****************************************************************************
+//
+// Device instance specific handler. This callback received notifications of
+// events related to handling interface, endpoint and string identifiers when
+// a device is part of a composite device. In this case, the only resource we
+// need which may be renumbered is the DFU runtime interface.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvDFUInstance, uint32_t ui32Request, void *pvRequestData)
+{
+ tDFUInstance *psInst;
+ uint8_t *pui8Data;
+
+ //
+ // Get a pointer to the DFU device instance data pointer
+ //
+ psInst = &((tUSBDDFUDevice *)pvDFUInstance)->sPrivateData;
+
+ //
+ // Get a byte pointer to the data.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ //
+ // Which request event have we been passed?
+ //
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the interface number.
+ //
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // We are not interested in any other event.
+ //
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a request for a
+// non-standard descriptor is received.
+//
+// \param pvDFUInstance is the instance data for this request.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure and determines which
+// descriptor is being requested. Assuming the descriptor can be found, it is
+// scheduled for transmission via endpoint zero. If the descriptor cannot be
+// found, the endpoint is stalled to indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleGetDescriptor(void *pvDFUInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Size;
+
+ ASSERT(pvDFUInstance != 0);
+
+ //
+ // Which type of class descriptor are we being asked for? We only support
+ // 1 type - the DFU functional descriptor.
+ //
+ if(((psUSBRequest->wValue >> 8) == USB_DFU_FUNC_DESCRIPTOR_TYPE) &&
+ ((psUSBRequest->wValue & 0xFF) == 0))
+ {
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if((uint16_t)g_pui8DFUFunctionalDesc[0] > psUSBRequest->wLength)
+ {
+ ui32Size = (uint32_t)psUSBRequest->wLength;
+ }
+ else
+ {
+ ui32Size = (uint32_t)g_pui8DFUFunctionalDesc[0];
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0, g_pui8DFUFunctionalDesc, ui32Size);
+ }
+ else
+ {
+ //
+ // This was an unknown or invalid request so stall.
+ //
+ USBDCDStallEP0(0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvDFUInstance is the instance data for this HID device.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure. Assuming the request is
+// understood, it is handled and any required response generated. If the
+// request cannot be handled by this device class, endpoint zero is stalled to
+// indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleRequest(void *pvDFUInstance, tUSBRequest *psUSBRequest)
+{
+ tDFUInstance *psInst;
+ tUSBDDFUDevice *psDevice;
+
+ ASSERT(pvDFUInstance != 0);
+
+ //
+ // Get a pointer to the DFU device structure
+ //
+ psDevice = pvDFUInstance;
+
+ //
+ // Get a pointer to the DFU device instance data pointer
+ //
+ psInst = &psDevice->sPrivateData;
+
+ //
+ // Make sure the request was for this interface.
+ //
+ if(psUSBRequest->wIndex != psInst->ui8Interface)
+ {
+ return;
+ }
+
+ //
+ // Determine the type of request.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // We have been asked to detach. In this case, we call back to the
+ // application telling it to tidy up and re-enter the boot loader. We
+ // rely upon it doing this on our behalf since this must be done from a
+ // non-interrupt context and this call is most likely in interrupt
+ // context.
+ //
+ case USBD_DFU_REQUEST_DETACH:
+ {
+ //
+ // Tell the application it's time to reenter the boot loader.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData, USBD_DFU_EVENT_DETACH,
+ 0, (void *)0);
+ break;
+ }
+
+ //
+ // This request was not recognized so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes DFU device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for DFU runtime device operation.
+//! \param psDFUDevice points to a structure containing parameters customizing
+//! the operation of the DFU device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! The \e psCompEntry should point to the composite device entry to
+//! initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB DFU APIs.
+//
+//*****************************************************************************
+void *
+USBDDFUCompositeInit(uint32_t ui32Index, tUSBDDFUDevice *psDFUDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tDFUInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDFUDevice);
+ ASSERT(psCompEntry != 0);
+
+ //
+ // Get a pointer to the DFU device instance data pointer
+ //
+ psInst = &psDFUDevice->sPrivateData;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psDFUDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sDFUHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8DFUDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppsDFUConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->bConnected = false;
+ psInst->ui8Interface = 0;
+
+ //
+ // Initialize the device info structure for the DFU device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDFUDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the DFU device.
+//!
+//! \param pvDFUInstance is the pointer to the device instance structure as
+//! returned by USBDDFUCompositeInit().
+//!
+//! This function terminates DFU operation for the instance supplied and
+//! removes the device from the USB bus.
+//!
+//! Following this call, the \e pvDFUInstance instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDDFUCompositeTerm(void *pvDFUInstance)
+{
+ tDFUInstance *psInst;
+
+ ASSERT(pvDFUInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &((tUSBDDFUDevice *)pvDFUInstance)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(0);
+
+ psInst->ui32USBBase = 0;
+}
+
+//*****************************************************************************
+//
+//! Removes the current USB device from the bus and transfers control to the
+//! DFU boot loader.
+//!
+//! This function should be called from the application's main loop (i.e. not
+//! in interrupt context) following a callback to the USB DFU callback function
+//! notifying the application of a DETACH request from the host. The function
+//! will prepare the system to switch to DFU mode and transfer control to the
+//! boot loader in preparation for a firmware upgrade from the host.
+//!
+//! The application must ensure that it has completed all necessary shutdown
+//! activities (saved any required data, etc.) before making this call since
+//! the function will not return.
+//!
+//! \return This function does not return.
+//
+//*****************************************************************************
+void
+USBDDFUUpdateBegin(void)
+{
+ //
+ // Terminate the USB device and take us off the bus.
+ //
+ USBDCDTerm(0);
+
+ //
+ // Disable all interrupts.
+ //
+ MAP_IntMasterDisable();
+
+ //
+ // We must make sure we turn off SysTick and its interrupt
+ // before entering the boot loader!
+ //
+ MAP_SysTickIntDisable();
+ MAP_SysTickDisable();
+
+ //
+ // Disable all processor interrupts. Instead of disabling them
+ // one at a time, a direct write to NVIC is done to disable all
+ // peripheral interrupts.
+ //
+ HWREG(NVIC_DIS0) = 0xffffffff;
+ HWREG(NVIC_DIS1) = 0xffffffff;
+
+ //
+ // Reset the USB peripheral
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+ MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Wait for about a second.
+ //
+ MAP_SysCtlDelay(MAP_SysCtlClockGet() / 3);
+
+ //
+ // Re-enable interrupts at the NVIC level.
+ //
+ MAP_IntMasterEnable();
+
+ //
+ // Return control to the boot loader. This is a call to the SVC
+ // handler in the boot loader.
+ //
+ (*((void (*)(void))(*(uint32_t *)0x2c)))();
+
+ //
+ // Should never get here, but just in case.
+ //
+ while(1)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbddfu-rt.h b/usblib/device/usbddfu-rt.h new file mode 100644 index 0000000..c344207 --- /dev/null +++ b/usblib/device/usbddfu-rt.h @@ -0,0 +1,184 @@ +//*****************************************************************************
+//
+// usbddfu-rt.h - Definitions used by runtime DFU class devices.
+//
+// Copyright (c) 2010-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.
+//
+//*****************************************************************************
+
+#ifndef __USBDDFURT_H__
+#define __USBDDFURT_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup dfu_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8DFUInterface array in bytes.
+//
+//*****************************************************************************
+#define DFUINTERFACE_SIZE (9)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8DFUFunctionalDesc array in bytes.
+//
+//*****************************************************************************
+#define DFUFUNCTIONALDESC_SIZE (9)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the DFU runtime device. This does not
+//! include the configuration descriptor which is automatically ignored by the
+//! composite device class.
+//!
+//! This label is used to compute the value which will be passed to the
+//! USBDCompositeInit function in the ui32Size parameter.
+//
+//*****************************************************************************
+#define COMPOSITE_DDFU_SIZE (DFUINTERFACE_SIZE + DFUFUNCTIONALDESC_SIZE)
+
+//*****************************************************************************
+//
+//! This value is passed to the client via the callback function provided in
+//! the tUSBDDFUDevice structure and indicates that the host has sent a DETACH
+//! request to the DFU interface. This request indicates that the device detach
+//! from the USB bus and reattach in DFU mode in preparation for a firmware
+//! upgrade. Currently, this is the only event that the DFU runtime class
+//! reports to the client.
+//!
+//! When this event is received, the client should call USBDDFUUpdateBegin()
+//! from a non-interrupt context at its earliest opportunity.
+//
+//*****************************************************************************
+#define USBD_DFU_EVENT_DETACH (USBD_DFU_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for
+// DFU devices. The memory for this structure is included in the
+// sPrivateData field in the tUSBDDFUDevice structure passed in the
+// USBDDFUCompositeInit() function.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The DFU class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+
+ //
+ // The connection status of the device.
+ //
+ bool bConnected;
+}
+tDFUInstance;
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the DFU device. Note that, unlike all other devices, this structure does
+//! not contain any fields which configure the device descriptor sent back to
+//! the host. The DFU runtime device class must be used as part of a composite
+//! device since all it provides is the capability to signal the device to
+//! switch into DFU mode in preparation for a firmware upgrade. Creating a
+//! device with nothing but DFU runtime mode capability is rather pointless
+//! so this is not supported.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of DETACH requests.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the pfnCallback function.
+ //
+ void * const pvCBData;
+
+ //
+ //! The private instance data for this device class. This
+ //! memory must remain accessible for as long as the DFU device is in use
+ //! and must not be modified by any code outside the DFU class driver.
+ //
+ tDFUInstance sPrivateData;
+}
+tUSBDDFUDevice;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDDFUCompositeInit(uint32_t ui32Index,
+ tUSBDDFUDevice *psDFUDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDDFUCompositeTerm(void *pvDFUInstance);
+extern void USBDDFUUpdateBegin(void);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDDFURT_H__
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.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdevice.h b/usblib/device/usbdevice.h new file mode 100644 index 0000000..d4df6a6 --- /dev/null +++ b/usblib/device/usbdevice.h @@ -0,0 +1,232 @@ +//*****************************************************************************
+//
+// usbdevice.h - types and definitions used during USB enumeration.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDEVICE_H__
+#define __USBDEVICE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The maximum number of independent interfaces that any single device
+//! implementation can support. Independent interfaces means interface
+//! descriptors with different \e bInterfaceNumber values - several interface
+//! descriptors offering different alternative settings but the same interface
+//! number count as a single interface.
+//
+//*****************************************************************************
+#define USB_MAX_INTERFACES_PER_DEVICE 8
+
+#include "usbdevicepriv.h"
+
+//*****************************************************************************
+//
+//! This structure is passed to the USB library on a call to USBDCDInit and
+//! provides the library with information about the device that the
+//! application is implementing. It contains functions pointers for the
+//! various USB event handlers and pointers to each of the standard device
+//! descriptors.
+//
+//*****************************************************************************
+struct tDeviceInfo
+{
+ //
+ //! A pointer to a structure containing pointers to event handler functions
+ //! provided by the client to support the operation of this device.
+ //
+ const tCustomHandlers * psCallbacks;
+
+ //
+ //! A pointer to the device descriptor for this device.
+ //
+ const uint8_t *pui8DeviceDescriptor;
+
+ //
+ //! A pointer to an array of configuration descriptor pointers. Each entry
+ //! in the array corresponds to one configuration that the device may be
+ //! set to use by the USB host. The number of entries in the array must
+ //! match the bNumConfigurations value in the device descriptor
+ //! array, \e pui8DeviceDescriptor.
+ //
+ const tConfigHeader * const *ppsConfigDescriptors;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must be arranged as follows:
+ //!
+ //! [0] - Standard descriptor containing supported language codes.
+ //!
+ //! [1] - String 1 for the first language listed in descriptor 0.
+ //!
+ //! [2] - String 2 for the first language listed in descriptor 0.
+ //!
+ //! ...
+ //!
+ //! [n] - String n for the first language listed in descriptor 0.
+ //!
+ //! [n+1] - String 1 for the second language listed in descriptor 0.
+ //!
+ //! ...
+ //!
+ //! [2n] - String n for the second language listed in descriptor 0.
+ //!
+ //! [2n+1]- String 1 for the third language listed in descriptor 0.
+ //!
+ //! ...
+ //!
+ //! [3n] - String n for the third language listed in descriptor 0.
+ //!
+ //! and so on.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The total number of descriptors provided in the ppStringDescriptors
+ //! array.
+ //
+ uint32_t ui32NumStringDescriptors;
+};
+
+//*****************************************************************************
+//
+//! This type is used by an application to describe and instance of a device
+//! and an instance data pointer for that class. The psDevice pointer should
+//! be a pointer to a valid device class to include in the composite device.
+//! The pvInstance pointer should be a pointer to an instance pointer for the
+//! device in the psDevice pointer.
+//!
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This is the top level device information structure.
+ //
+ const tDeviceInfo *psDevInfo;
+
+ //
+ //! This is the instance data for the device structure.
+ //
+ void *pvInstance;
+
+ //
+ //! A per-device workspace used by the composite device.
+ //
+ uint32_t ui32DeviceWorkspace;
+}
+tCompositeEntry;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public APIs offered by the USB library device control driver.
+//
+//*****************************************************************************
+extern void USBDCDInit(uint32_t ui32Index, tDeviceInfo *psDevice,
+ void *pvDCDCBData);
+extern void USBDCDTerm(uint32_t ui32Index);
+extern void USBDCDStallEP0(uint32_t ui32Index);
+extern void USBDCDRequestDataEP0(uint32_t ui32Index, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern void USBDCDSendDataEP0(uint32_t ui32Index, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern void USBDCDSetDefaultConfiguration(uint32_t ui32Index,
+ uint32_t ui32DefaultConfig);
+extern uint32_t USBDCDConfigDescGetSize(const tConfigHeader *psConfig);
+extern uint32_t USBDCDConfigDescGetNum(const tConfigHeader *psConfig,
+ uint32_t ui32Type);
+extern tDescriptorHeader *USBDCDConfigDescGet(const tConfigHeader *psConfig,
+ uint32_t ui32Type,
+ uint32_t ui32Index,
+ uint32_t *pui32Section);
+extern uint32_t
+ USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNumber);
+extern tInterfaceDescriptor *
+ USBDCDConfigGetInterface(const tConfigHeader *psConfig,
+ uint32_t ui32Index, uint32_t ui32AltCfg,
+ uint32_t *pui32Section);
+extern tEndpointDescriptor *
+ USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig,
+ uint32_t ui32InterfaceNumber,
+ uint32_t ui32AltCfg,
+ uint32_t ui32Index);
+extern bool USBDCDRemoteWakeupRequest(uint32_t ui32Index);
+extern bool USBDCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature);
+extern bool USBDCDRemoteWakeLPM(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// Device mode interrupt handler for controller index 0.
+//
+//*****************************************************************************
+extern void USB0DeviceIntHandler(void);
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+
+//
+// Use USBDCDFeatureSet() or USBHCDFeatureSet() with \b USBLIB_FEATURE_POWER
+// configuration option.
+//
+extern void USBDCDPowerStatusSet(uint32_t ui32Index, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBENUM_H__
diff --git a/usblib/device/usbdevicepriv.h b/usblib/device/usbdevicepriv.h new file mode 100644 index 0000000..4eef230 --- /dev/null +++ b/usblib/device/usbdevicepriv.h @@ -0,0 +1,248 @@ +//*****************************************************************************
+//
+// usbdevicepriv.h - Private header file used to share internal variables and
+// function prototypes between the various device-related
+// modules in the USB library. This header MUST NOT be
+// used by application code.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDEVICEPRIV_H__
+#define __USBDEVICEPRIV_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The states for endpoint zero during enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The USB device is waiting on a request from the host controller on
+ // endpoint zero.
+ //
+ eUSBStateIdle,
+
+ //
+ // The USB device is sending data back to the host due to an IN request.
+ //
+ eUSBStateTx,
+
+ //
+ // The USB device is sending the configuration descriptor back to the host
+ // due to an IN request.
+ //
+ eUSBStateTxConfig,
+
+ //
+ // The USB device is receiving data from the host due to an OUT
+ // request from the host.
+ //
+ eUSBStateRx,
+
+ //
+ // 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.
+ //
+ eUSBStateStatus,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ eUSBStateStall
+}
+tEP0State;
+
+typedef struct tDeviceInfo tDeviceInfo;
+
+//*****************************************************************************
+//
+// The USB controller device information.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The current state of endpoint zero.
+ //
+ volatile tEP0State iEP0State;
+
+ //
+ // 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 configuration id that will take effect after a reset.
+ //
+ uint32_t ui32DefaultConfiguration;
+
+ //
+ // This holds the current alternate interface for this device.
+ //
+ uint8_t pui8AltSetting[USB_MAX_INTERFACES_PER_DEVICE];
+
+ //
+ // 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;
+
+ //
+ // Holds the endpoint status for the HALT condition. This array is sized
+ // to hold halt status for all IN and OUT endpoints.
+ //
+ uint8_t ppui8Halt[2][USBLIB_NUM_EP - 1];
+
+ //
+ // Holds the configuration descriptor section number currently being sent
+ // to the host.
+ //
+ uint8_t ui8ConfigSection;
+
+ //
+ // Holds the offset within the configuration descriptor section currently
+ // being sent to the host.
+ //
+ uint16_t ui16SectionOffset;
+
+ //
+ // Holds the index of the configuration that we are currently sending back
+ // to the host.
+ //
+ uint8_t ui8ConfigIndex;
+
+ //
+ // This flag is set to true if the client has called USBDPowerStatusSet()
+ // and tells the USB library not to try to determine the current power
+ // status from the configuration descriptor.
+ //
+ bool bPwrSrcSet;
+
+ //
+ // This flag indicates whether or not remote wake up signaling is in
+ // progress.
+ //
+ bool bRemoteWakeup;
+
+ //
+ // During remote wake up signaling, this counter is used to track the
+ // number of milliseconds since the signaling was initiated.
+ //
+ uint8_t ui8RemoteWakeupCount;
+
+ //
+ // The DMA instance information for this USB controller.
+ //
+ tUSBDMAInstance *psDMAInstance;
+
+ //
+ // The interrupt number for this instance.
+ //
+ uint32_t ui32IntNum;
+
+ //
+ // Pointer to the device supplied call back data.
+ //
+ void *pvCBData;
+
+ //
+ // This holds the state of the LPM support for the device.
+ //
+ uint32_t ui32LPMState;
+
+ //
+ // Device feature flags.
+ //
+ uint32_t ui32Features;
+}
+tDCDInstance;
+
+extern tDCDInstance g_psDCDInst[];
+extern tDeviceInfo *g_ppsDevInfo[];
+
+//*****************************************************************************
+//
+// Device enumeration functions provided by device/usbenum.c and called from
+// the interrupt handler in device/usbhandler.c
+//
+//*****************************************************************************
+extern bool USBDeviceConfig(tDCDInstance *psDevInst,
+ const tConfigHeader *psConfig);
+extern bool USBDeviceConfigAlternate(tDCDInstance *psDevInst,
+ const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting);
+
+extern void USBDCDDeviceInfoInit(uint32_t ui32Index, tDeviceInfo *psDevice);
+
+//*****************************************************************************
+//
+// Macro access function to device information.
+//
+//*****************************************************************************
+#define DCDGetDMAInstance(psDevInfo) (&(psDevInfo->psDCDInst->sDMAInstance))
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDEVICEPRIV_H__
diff --git a/usblib/device/usbdhandler.c b/usblib/device/usbdhandler.c new file mode 100644 index 0000000..751cc44 --- /dev/null +++ b/usblib/device/usbdhandler.c @@ -0,0 +1,85 @@ +//*****************************************************************************
+//
+// usbhandler.c - General USB handling routines.
+//
+// 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_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The USB device interrupt handler.
+//!
+//! This the main USB interrupt handler entry point for use in USB device
+//! applications. This top-level handler will branch the interrupt off to the
+//! appropriate application or stack handlers depending on the current status
+//! of the USB controller.
+//!
+//! Applications which operate purely as USB devices (rather than dual mode
+//! applications which can operate in either device or host mode at different
+//! times) must ensure that a pointer to this function is installed in the
+//! interrupt vector table entry for the USB0 interrupt. For dual mode
+//! operation, the vector should be set to point to \e USB0DualModeIntHandler()
+//! instead.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USB0DeviceIntHandler(void)
+{
+ uint32_t ui32Status;
+
+ //
+ // Get the controller interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusControl(USB0_BASE);
+
+ //
+ // Call the internal handler.
+ //
+ USBDeviceIntHandlerInternal(0, ui32Status);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhid.c b/usblib/device/usbdhid.c new file mode 100644 index 0000000..c708f62 --- /dev/null +++ b/usblib/device/usbdhid.c @@ -0,0 +1,2502 @@ +//*****************************************************************************
+//
+// usbdhid.c - USB HID device class driver.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// Marker used to indicate that a given HID descriptor cannot be found in the
+// client-supplied list.
+//
+//*****************************************************************************
+#define HID_NOT_FOUND 0xFFFFFFFF
+
+//*****************************************************************************
+//
+// Flags that may appear in ui16DeferredOpFlags to indicate some operation that
+// has been requested but could not be processed at the time it was received.
+// Each deferred operation is defined as the bit number that should be set in
+// tHIDInstance->ui16DeferredOpFlags to indicate that the operation is pending.
+//
+//*****************************************************************************
+#define HID_DO_PACKET_RX 5
+#define HID_DO_SEND_IDLE_REPORT 6
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define INT_IN_ENDPOINT USB_EP_3
+#define INT_OUT_ENDPOINT USB_EP_3
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8HIDDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_DEVICE, // USB Device Class
+ 0, // USB Device Sub-class
+ USB_HID_PROTOCOL_NONE, // USB Device protocol
+ USBDHID_MAX_PACKET, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (VID).
+ USBShort(0), // Product ID (PID).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleGetDescriptor(void *pvHIDInstance, tUSBRequest *psUSBRequest);
+static void HandleRequest(void *pvHIDInstance, tUSBRequest *psUSBRequest);
+static void HandleConfigChange(void *pvHIDInstance, uint32_t ui32Info);
+static void HandleEP0DataReceived(void *pvHIDInstance, uint32_t ui32Info);
+static void HandleEP0DataSent(void *pvHIDInstance, uint32_t ui32Info);
+static void HandleReset(void *pvHIDInstance);
+static void HandleSuspend(void *pvHIDInstance);
+static void HandleResume(void *pvHIDInstance);
+static void HandleDisconnect(void *pvHIDInstance);
+static void HandleEndpoints(void *pvHIDInstance, uint32_t ui32Status);
+static void HandleDevice(void *pvHIDInstance, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB HID devices.
+//
+//*****************************************************************************
+const tCustomHandlers g_sHIDHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ HandleGetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequest,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ HandleConfigChange,
+
+ //
+ // DataReceived
+ //
+ HandleEP0DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ HandleEP0DataSent,
+
+ //
+ // ResetHandler
+ //
+ HandleReset,
+
+ //
+ // SuspendHandler
+ //
+ HandleSuspend,
+
+ //
+ // ResumeHandler
+ //
+ HandleResume,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler.
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pui16DeferredOp points to the flags variable which is to be modified.
+// \param ui16Bit indicates which bit number is to be set or cleared.
+// \param bSet indicates the state that the flag must be set to. If \b true,
+// the flag is set, if \b false, the flag is cleared.
+//
+// This function safely sets or clears a bit in a flag variable. The operation
+// makes use of bitbanding to ensure that the operation is atomic (no read-
+// modify-write is required).
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
+ bool bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// This function is called to clear the counter used to keep track of the time
+// elapsed since a given report was last sent.
+//
+// \param psHIDDevice points to the HID device structure whose report timer is
+// to be cleared.
+// \param ui8ReportID is the first byte of the report to be sent. If this
+// device offers more than one input report, this value is used to find the
+// relevant report timer structure in the psHIDDevice structure.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ClearReportTimer(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8ReportID)
+{
+ uint32_t ui32Loop;
+
+ if(psHIDDevice->ui8NumInputReports > 1)
+ {
+ //
+ // We have more than 1 input report so the report must begin with a
+ // byte containing the report ID. Scan the table we were provided
+ // when the device was initialized to find the entry for this report.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports;
+ ui32Loop++)
+ {
+ if(psHIDDevice->psReportIdle[ui32Loop].ui8ReportID == ui8ReportID)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ ui32Loop = 0;
+ }
+
+ //
+ // If we drop out of the loop with an index less than ui8NumInputReports,
+ // we found the relevant report so clear its timer.
+ //
+ if(ui32Loop < psHIDDevice->ui8NumInputReports)
+ {
+ psHIDDevice->psReportIdle[ui32Loop].ui32TimeSinceReportmS = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called to clear the idle period timers for each input
+// report supported by the device.
+//
+// \param psHIDDevice points to the HID device structure whose timers are to be
+// cleared.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ClearIdleTimers(const tUSBDHIDDevice *psHIDDevice)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Clear the "time till next report" counters for each input report.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS =
+ psHIDDevice->psReportIdle[ui32Loop].ui8Duration4mS * 4;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called periodically to allow us to process the report idle
+// timers.
+//
+// \param psHIDDevice points to the HID device structure whose timers are to be
+// updated.
+// \param ui32ElapsedmS indicates the number of milliseconds that have elapsed
+// since the last call to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ProcessIdleTimers(const tUSBDHIDDevice *psHIDDevice, uint32_t ui32ElapsedmS)
+{
+ uint32_t ui32Loop, ui32SizeReport;
+ void *pvReport;
+ tHIDInstance *psInst;
+ bool bDeferred;
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)psHIDDevice)->sPrivateData;
+
+ //
+ // We have not had to defer any report transmissions yet.
+ //
+ bDeferred = false;
+
+ //
+ // Look at each of the input report idle timers in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ //
+ // Update the time since the last report was sent.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui32TimeSinceReportmS +=
+ ui32ElapsedmS;
+
+ //
+ // Is this timer running?
+ //
+ if(psHIDDevice->psReportIdle[ui32Loop].ui8Duration4mS)
+ {
+ //
+ // Yes - is it about to expire?
+ //
+ if(psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS <=
+ ui32ElapsedmS)
+ {
+ //
+ // The timer is about to expire. Can we send a report right
+ // now?
+ //
+ if((psInst->iHIDTxState == eHIDStateIdle) &&
+ (psInst->bSendInProgress == false))
+ {
+ //
+ // We can send a report so send a message to the
+ // application to retrieve its latest report for
+ // transmission to the host.
+ //
+ ui32SizeReport = psHIDDevice->pfnRxCallback(
+ psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_IDLE_TIMEOUT,
+ psHIDDevice->psReportIdle[ui32Loop].ui8ReportID,
+ &pvReport);
+
+ //
+ // Schedule the report for transmission.
+ //
+ USBDHIDReportWrite((void *)psHIDDevice, pvReport,
+ ui32SizeReport, true);
+
+ //
+ // Reload the timer for the next period.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS =
+ psHIDDevice->psReportIdle[ui32Loop].ui8Duration4mS * 4;
+ }
+ else
+ {
+ //
+ // We can't send the report straight away so flag it for
+ // transmission as soon as the previous transmission ends.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS = 0;
+ bDeferred = true;
+ }
+ }
+ else
+ {
+ //
+ // The timer is not about to expire. Update the time till the
+ // next report transmission.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS -=
+ ui32ElapsedmS;
+ }
+ }
+ }
+
+ //
+ // If we had to defer transmission of any report, remember this so that we
+ // will process it as soon as possible.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, HID_DO_SEND_IDLE_REPORT,
+ bDeferred);
+}
+
+static void
+SetIdleTimeout(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8ReportID,
+ uint8_t ui8Timeout4mS)
+{
+ uint32_t ui32Loop;
+ bool bReportNeeded;
+ tHIDReportIdle *psIdle;
+
+ //
+ // Remember that we have not found any report that needs to be sent
+ // immediately.
+ //
+ bReportNeeded = false;
+
+ //
+ // Search through all the input reports looking for ones that fit the
+ // requirements.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ psIdle = &psHIDDevice->psReportIdle[ui32Loop];
+
+ //
+ // If the report ID passed matches the report ID in the idle timer
+ // control structure or we were passed a report ID of zero, which
+ // indicates that all timers are to be set...
+ //
+ if(!ui8ReportID || (ui8ReportID == psIdle->ui8ReportID))
+ {
+ //
+ // Save the new duration for the idle timer.
+ //
+ psIdle->ui8Duration4mS = ui8Timeout4mS;
+
+ //
+ // Are we enabling the idle timer? If so, fix up the time until it
+ // needs to fire.
+ //
+ if(ui8Timeout4mS)
+ {
+ //
+ // Determine what the timeout is for this report given the time
+ // since the last report of this type was sent.
+ //
+ if(psIdle->ui32TimeSinceReportmS >=
+ ((uint32_t)ui8Timeout4mS * 4))
+ {
+ psIdle->ui16TimeTillNextmS = 0;
+ bReportNeeded = true;
+ }
+ else
+ {
+ psIdle->ui16TimeTillNextmS =
+ (((uint16_t)ui8Timeout4mS * 4) -
+ psIdle->ui32TimeSinceReportmS);
+ }
+ }
+ }
+ }
+
+ //
+ // If we get to here and bReportNeeded is true, this means we need to
+ // send back at least one of the input reports as soon as possible. Try
+ // to do this immediately.
+ //
+ if(bReportNeeded)
+ {
+ ProcessIdleTimers(psHIDDevice, 0);
+ }
+}
+
+//*****************************************************************************
+//
+// Find the idle timeout for a given HID input report.
+//
+// \param psHIDDevice points to the HID device whose report idle timeout is to
+// be found.
+// \param ui8ReportID identifies the report whose timeout is requested. If 0,
+// the timeout for the first report is returns, regardless of its ID (or
+// whether it has one).
+//
+// This function returns the current idle timeout for a given HID input report.
+// The value returned is expressed in terms of 4mS intervals. Convert to
+// milliseconds by multiplying by 4. If the return value is 0, this indicates
+// that an infinite timeout is currently set and the device will not send the
+// report unless a state change occurs.
+//
+// \return Returns the current idle timeout for the given report.
+//
+//*****************************************************************************
+static uint32_t
+GetIdleTimeout(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8ReportID)
+{
+ uint32_t ui32Loop;
+ tHIDReportIdle *psIdle;
+
+ //
+ // Search through all the input reports looking for ones that fit the
+ // requirements.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ psIdle = &psHIDDevice->psReportIdle[ui32Loop];
+
+ //
+ // If the report ID passed matches the report ID in the idle timer
+ // control structure or we were passed a report ID of zero, which
+ // indicates that all timers are to be set...
+ //
+ if(!ui8ReportID || (ui8ReportID == psIdle->ui8ReportID))
+ {
+ //
+ // We found a report matching the required ID or we were not passed
+ // an ID and we are looking at the first report information.
+ //
+ return((uint32_t)psIdle->ui8Duration4mS);
+ }
+ }
+
+ //
+ // If we drop out, the report could not be found so we need to indicate
+ // an error.
+ //
+ return(HID_NOT_FOUND);
+}
+
+//*****************************************************************************
+//
+// Find the n-th HID class descriptor of a given type in the client-provided
+// descriptor table.
+//
+// \param psHIDDevice points to the HID device which is to be searched for the
+// required class descriptor.
+// \param ui8Type is the type of class descriptor being requested. This will
+// be either USB_HID_DTYPE_REPORT or USB_HID_DTYPE_PHYSICAL.
+// \param ui32Index is the zero-based index of the descriptor that is being
+// requested.
+//
+// This function parses the supplied HID descriptor to find the index into the
+// sClassDescriptor array that corresponds to the requested descriptor. If
+// a descriptor with the requested index does not exist, HID_NOT_FOUND will be
+// returned unless the request is for a physical descriptor and at least one
+// such descriptor exists. In this case, the index returned will be for the
+// last physical descriptor (as required by the HID spec 7.1.1).
+//
+// \return Returns the index of the descriptor within the sClassDescriptor
+// of the tHIDDevice structure if found or HID_NOT_FOUND otherwise.
+//
+//*****************************************************************************
+static uint32_t
+FindHIDDescriptor(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8Type,
+ uint32_t ui32Index, uint32_t *pui32Len)
+{
+ bool bFoundType;
+ uint32_t ui32Loop, ui32Count, ui32LastFound;
+ const tHIDClassDescriptorInfo *psDesc;
+
+ //
+ // Remember that we have not found any descriptor with a matching type yet.
+ //
+ bFoundType = false;
+ ui32Count = 0;
+ ui32LastFound = 0;
+
+ //
+ // Walk through all the class descriptors looking for the one which
+ // matches the requested index and type.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->psHIDDescriptor->bNumDescriptors;
+ ui32Loop++)
+ {
+ psDesc = &(psHIDDevice->psHIDDescriptor->sClassDescriptor[ui32Loop]);
+ if(psDesc->bDescriptorType == ui8Type)
+ {
+ //
+ // We found a descriptor of the correct type. Is this the
+ // correct index?
+ //
+ bFoundType = true;
+
+ //
+ // Is this the descriptor we are looking for?
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Yes - we found it so return the index and size to the
+ // caller.
+ //
+ *pui32Len = (uint32_t)psDesc->wDescriptorLength;
+ return(ui32Loop);
+ }
+ else
+ {
+ //
+ // Update our count and keep looking. Remember where we were
+ // when we found this descriptor in case we need to return the
+ // last physical descriptor.
+ //
+ ui32Count++;
+ ui32LastFound = ui32Loop;
+ }
+ }
+ }
+
+ //
+ // If we drop out, we did not find the requested descriptor. Now handle
+ // the special case of a physical descriptor - if we found any physical
+ // descriptors, return the last one.
+ //
+ if((ui8Type == USB_HID_DTYPE_PHYSICAL) && bFoundType)
+ {
+ //
+ // Get the length of the last descriptor we found.
+ //
+ psDesc =
+ &(psHIDDevice->psHIDDescriptor->sClassDescriptor[ui32LastFound]);
+ *pui32Len = (uint32_t)psDesc->wDescriptorLength;
+
+ //
+ // Return the index to the caller.
+ //
+ return(ui32LastFound);
+ }
+ else
+ {
+ //
+ // We could not find the descriptor so return an appropriate error.
+ //
+ return(HID_NOT_FOUND);
+ }
+}
+
+//*****************************************************************************
+//
+// Schedule transmission of the next packet forming part of an input report.
+//
+// \param psHIDInst points to the HID device instance whose input report is to
+// be sent.
+//
+// This function is called to transmit the next packet of an input report
+// passed to the driver via a call to USBDHIDReportWrite. If any data remains
+// to be sent, a USB packet is written to the FIFO and scheduled for
+// transmission to the host. The function ensures that reports are sent as
+// a sequence of full packets followed by either a single int16_t packet or a
+// packet with no data to indicate the end of the transaction.
+//
+//*****************************************************************************
+static int32_t
+ScheduleReportTransmission(tHIDInstance *psHIDInst)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+ int32_t i32Retcode;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = (uint32_t)(psHIDInst->ui16InReportSize -
+ psHIDInst->ui16InReportIndex);
+
+ //
+ // Limit individual transfers to the maximum packet size for the endpoint.
+ //
+ if(ui32NumBytes > USBDHID_MAX_PACKET)
+ {
+ ui32NumBytes = USBDHID_MAX_PACKET;
+ }
+
+ //
+ // Where are we sending this data from?
+ //
+ pui8Data = psHIDInst->pui8InReportData + psHIDInst->ui16InReportIndex;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psHIDInst->ui32USBBase,
+ psHIDInst->ui8INEndpoint,
+ pui8Data, ui32NumBytes);
+
+ if(i32Retcode != -1)
+ {
+ //
+ // Update the count and index ready for the next time round.
+ //
+ psHIDInst->ui16InReportIndex += ui32NumBytes;
+
+ //
+ // Send out the current data.
+ //
+ i32Retcode = MAP_USBEndpointDataSend(psHIDInst->ui32USBBase,
+ psHIDInst->ui8INEndpoint,
+ USB_TRANS_IN);
+ }
+
+ //
+ // Tell the caller how we got on.
+ //
+ return(i32Retcode);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psHIDDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts signaling
+// the arrival of data on the interrupt OUT endpoint (in other words, whenever
+// the host has sent us a packet of data). We inform the client that a packet
+// is available and, on return, check to see if the packet has been read. If
+// not, we schedule another notification to the client for a later time.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataFromHost(tUSBDHIDDevice *psHIDDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tHIDInstance *psInst;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Set the flag we use to indicate that a packet read is pending. This
+ // will be cleared if the packet is read. If the client does not read
+ // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
+ // the event will be signaled later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, HID_DO_PACKET_RX,
+ true);
+
+ //
+ // How big is the packet we have just been sent?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // The receive channel is not blocked so let the caller know
+ // that a packet is waiting. The parameters are set to indicate
+ // that the packet has not been read from the hardware FIFO yet.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ui32EPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ui32EPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psHIDDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the interrupt IN endpoint (in other words, whenever data has been
+// transmitted to the USB host). We examine the cause of the interrupt and,
+// if due to completion of a transmission, notify the client.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataToHost(tUSBDHIDDevice *psHIDDevice, uint32_t ui32Status)
+{
+ tHIDInstance *psInst;
+ uint32_t ui32EPStatus;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8INEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase, psInst->ui8INEndpoint,
+ ui32EPStatus);
+
+ //
+ // Our last packet was transmitted successfully. Is there any more data to
+ // send or have we finished sending the whole report? We know we finished
+ // if the ui16InReportIndex has reached the ui16InReportSize value.
+ //
+ if(psInst->ui16InReportSize == psInst->ui16InReportIndex)
+ {
+ //
+ // We finished sending the last report so are idle once again.
+ //
+ psInst->iHIDTxState = eHIDStateIdle;
+
+ //
+ // Notify the client that the report transmission completed.
+ //
+ psHIDDevice->pfnTxCallback(psHIDDevice->pvTxCBData,
+ USB_EVENT_TX_COMPLETE,
+ psInst->ui16InReportSize, (void *)0);
+
+ //
+ // Do we have any reports to send as a result of idle timer timeouts?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << HID_DO_SEND_IDLE_REPORT))
+ {
+ //
+ // Yes - send reports for any timers that expired recently.
+ //
+ ProcessIdleTimers(psHIDDevice, 0);
+ }
+ }
+ else
+ {
+ //
+ // There must be more data or a zero length packet waiting to be sent
+ // so go ahead and do this.
+ //
+ ScheduleReportTransmission(psInst);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack for any activity involving one of our endpoints
+// other than EP0. This function is a fan out that merely directs the call to
+// the correct handler depending upon the endpoint and transaction direction
+// signaled in ui32Status.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvHIDInstance, uint32_t ui32Status)
+{
+ tUSBDHIDDevice *psHIDInst;
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ui32Index is different in both cases.
+ //
+ psHIDInst = (tUSBDHIDDevice *)pvHIDInstance;
+ psInst = &psHIDInst->sPrivateData;
+
+ //
+ // Handler for the interrupt OUT data endpoint.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(pvHIDInstance, ui32Status);
+ }
+
+ //
+ // Handler for the interrupt IN data endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint)))
+ {
+ ProcessDataToHost(pvHIDInstance, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvHIDInstance, uint32_t ui32Info)
+{
+ tHIDInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->iHIDRxState = eHIDStateIdle;
+ psInst->iHIDTxState = eHIDStateIdle;
+
+ //
+ // If we are not currently connected let the client know we are open for
+ // business.
+ //
+ if(!psInst->bConnected)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Clear the idle timers for each input report.
+ //
+ ClearIdleTimers(psHIDDevice);
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvHIDInstance, uint32_t ui32Request, void *pvRequestData)
+{
+ tHIDInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDHIDDevice *psHIDDevice;
+
+ psHIDDevice = (tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Create the int8_t array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psHIDDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_LPM_RESUME, 0, (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psHIDDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_LPM_SLEEP, 0, (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psHIDDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_LPM_ERROR, 0, (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvHIDInstance)
+{
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(psHIDDevice->sPrivateData.bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psHIDDevice->sPrivateData.bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a request for a
+// non-standard descriptor is received.
+//
+// \param pvHIDInstance is the instance data for this request.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure and determines which
+// descriptor is being requested. Assuming the descriptor can be found, it is
+// scheduled for transmission via endpoint zero. If the descriptor cannot be
+// found, the endpoint is stalled to indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleGetDescriptor(void *pvHIDInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Size, ui32Desc;
+ const tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Which type of class descriptor are we being asked for?
+ //
+ switch(psUSBRequest->wValue >> 8)
+ {
+ //
+ // This is a request for a HID report or physical descriptor.
+ //
+ case USB_HID_DTYPE_REPORT:
+ case USB_HID_DTYPE_PHYSICAL:
+ {
+ //
+ // Find the index to the descriptor that is being queried.
+ //
+ ui32Size = 0;
+ ui32Desc = FindHIDDescriptor(psHIDDevice,
+ psUSBRequest->wValue >> 8,
+ psUSBRequest->wValue & 0xFF,
+ &ui32Size);
+
+ //
+ // Did we find the descriptor?
+ //
+ if(ui32Desc == HID_NOT_FOUND)
+ {
+ //
+ // No - stall the endpoint and return.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if(ui32Size > psUSBRequest->wLength)
+ {
+ ui32Size = psUSBRequest->wLength;
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)psHIDDevice->ppui8ClassDescriptors[ui32Desc],
+ ui32Size);
+
+ break;
+ }
+
+ //
+ // This is a request for the HID descriptor (as found in the
+ // configuration descriptor following the relevant interface).
+ //
+ case USB_HID_DTYPE_HID:
+ {
+ //
+ // How big is the HID descriptor?
+ //
+ ui32Size = (uint32_t)psHIDDevice->psHIDDescriptor->bLength;
+
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if(ui32Size > psUSBRequest->wLength)
+ {
+ ui32Size = psUSBRequest->wLength;
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)psHIDDevice->psHIDDescriptor,
+ ui32Size);
+ break;
+ }
+
+ //
+ // This was an unknown request so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvHIDInstance is the instance data for this HID device.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure. Assuming the request is
+// understood, it is handled and any required response generated. If the
+// request cannot be handled by this device class, endpoint zero is stalled to
+// indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleRequest(void *pvHIDInstance, tUSBRequest *psUSBRequest)
+{
+ tHIDInstance *psInst;
+ uint8_t ui8Protocol;
+ uint32_t ui32Size, ui32Timeout;
+ uint8_t *pui8Report;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Make sure the request was for this interface.
+ //
+ if(psUSBRequest->wIndex != psInst->ui8Interface)
+ {
+ return;
+ }
+
+ //
+ // Determine the type of request.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // A Set Report request is received from the host when it sends an
+ // Output report via endpoint 0.
+ //
+ case USBREQ_SET_REPORT:
+ {
+ //
+ // Ask the application for a buffer large enough to hold the
+ // report we are to be sent.
+ //
+ psInst->ui16OutReportSize = psUSBRequest->wLength;
+ psInst->pui8OutReportData =
+ (uint8_t *)psHIDDevice->pfnRxCallback(
+ psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_GET_REPORT_BUFFER,
+ psUSBRequest->wValue,
+ (void *)(uint32_t)(psUSBRequest->wLength));
+
+ //
+ // Did the client provide us a buffer?
+ //
+ if(!psInst->pui8OutReportData)
+ {
+ //
+ // The application could not provide us a buffer so stall the
+ // request.
+ //
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // The client provided us a buffer to read the report into
+ // so request the data from the host.
+ //
+
+ //
+ // Set the state to indicate we are waiting for data.
+ //
+ psInst->iHIDRxState = eHIDStateWaitData;
+
+ //
+ // Now read the payload of the request. We handle the actual
+ // operation in the data callback once this data is received.
+ //
+ USBDCDRequestDataEP0(0, psInst->pui8OutReportData,
+ (uint32_t)psUSBRequest->wLength);
+
+ //
+ // Need to ACK the data on end point 0 in this case. Do this
+ // after requesting the data to prevent race conditions that
+ // occur if you acknowledge before setting up to receive the
+ // request data.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+ }
+
+ break;
+ }
+
+ //
+ // A Get Report request is used by the host to poll a device for its
+ // current state.
+ //
+ case USBREQ_GET_REPORT:
+ {
+ //
+ // Get the latest report from the application.
+ //
+ ui32Size = psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_GET_REPORT,
+ psUSBRequest->wValue, &pui8Report);
+
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // ..then send back the requested report.
+ //
+ psInst->bGetRequestPending = true;
+ USBDCDSendDataEP0(0, pui8Report, ui32Size);
+
+ break;
+ }
+
+ //
+ // A set IDLE request has been made. This indicates to us how often a
+ // given report should be sent back to the host in the absence of any
+ // change in state of the device.
+ //
+ case USBREQ_SET_IDLE:
+ {
+ //
+ // Set the idle timeout for the requested report(s).
+ //
+ SetIdleTimeout(psHIDDevice, psUSBRequest->wValue & 0xFF,
+ (psUSBRequest->wValue >> 8) & 0xFF);
+
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ break;
+ }
+
+ //
+ // A get IDLE request has been made. This request queries the current
+ // idle timeout for a given report.
+ //
+ case USBREQ_GET_IDLE:
+ {
+ //
+ // Determine the timeout for the requested report.
+ //
+ ui32Timeout = GetIdleTimeout(psHIDDevice, psUSBRequest->wValue);
+
+ if(ui32Timeout != HID_NOT_FOUND)
+ {
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui32Timeout, 1);
+ }
+ else
+ {
+ //
+ // The report ID was not found so stall the endpoint.
+ //
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // Set either boot or report protocol for reports sent from the device.
+ // This is only supported by devices in the boot subclass.
+ //
+ case USBREQ_SET_PROTOCOL:
+ {
+ if(psHIDDevice->ui8Subclass == USB_HID_SCLASS_BOOT)
+ {
+ //
+ // We need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // We are a boot subclass device so pass this on to the
+ // application.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_SET_PROTOCOL,
+ psUSBRequest->wValue,
+ (void *)0);
+ }
+ else
+ {
+ //
+ // This is not a boot subclass device so stall the endpoint to
+ // show that we don't support this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // Inform the host of the protocol, boot or report, that is currently
+ // in use. This is only supported by devices in the boot subclass.
+ //
+ case USBREQ_GET_PROTOCOL:
+ {
+ if(psHIDDevice->ui8Subclass == USB_HID_SCLASS_BOOT)
+ {
+ //
+ // We need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // We are a boot subclass device so pass this on to the
+ // application callback to get the answer.
+ //
+ ui8Protocol = (uint8_t)psHIDDevice->pfnRxCallback(
+ psHIDDevice->pvRxCBData, USBD_HID_EVENT_GET_PROTOCOL, 0,
+ (void *)0);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui8Protocol, 1);
+ }
+ else
+ {
+ //
+ // This is not a boot subclass device so stall the endpoint to
+ // show that we don't support this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // This request was not recognized so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the data requested
+// on endpoint zero is received.
+//
+//*****************************************************************************
+static void
+HandleEP0DataReceived(void *pvHIDInstance, uint32_t ui32DataSize)
+{
+ tHIDInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // If we were not passed any data, just return.
+ //
+ if(ui32DataSize == 0)
+ {
+ return;
+ }
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Make sure we are actually expecting something.
+ //
+ if(psInst->iHIDRxState != eHIDStateWaitData)
+ {
+ return;
+ }
+
+ //
+ // Change the endpoint state back to idle now that we have been passed
+ // the data we were waiting for.
+ //
+ psInst->iHIDRxState = eHIDStateIdle;
+
+ //
+ // The only things we ever request via endpoint zero are reports sent to
+ // us via a Set_Report request. Pass the newly received report on to
+ // the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_SET_REPORT,
+ psInst->ui16OutReportSize,
+ psInst->pui8OutReportData);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the data sent on
+// endpoint zero is received and acknowledged by the host.
+//
+//*****************************************************************************
+static void
+HandleEP0DataSent(void *pvHIDInstance, uint32_t ui32Info)
+{
+ tHIDInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // If we just sent a report in response to a Get_Report request, send an
+ // event to the application telling it that the transmission completed.
+ //
+ if(psInst->bGetRequestPending)
+ {
+ //
+ // Clear the flag now that we are sending the application callback.
+ //
+ psInst->bGetRequestPending = false;
+
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_REPORT_SENT, 0, (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// reset. If we are currently connected, send a disconnect event at this
+// point.
+//
+//*****************************************************************************
+static void
+HandleReset(void *pvHIDInstance)
+{
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Merely call the disconnect handler. This causes a disconnect message to
+ // be sent to the client if we think we are currently connected.
+ //
+ HandleDisconnect(pvHIDInstance);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvHIDInstance)
+{
+ const tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (const tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Pass the event on to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData, USB_EVENT_SUSPEND, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is taken
+// out of suspend state.
+//
+//*****************************************************************************
+static void
+HandleResume(void *pvHIDInstance)
+{
+ const tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (const tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Pass the event on to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData, USB_EVENT_RESUME, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called periodically and provides us with a time reference
+// and method of implementing delayed or time-dependent operations.
+//
+// \param pvHIDInstance is the instance data for this request.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HIDTickHandler(void *pvHIDInstance, uint32_t ui32TimemS)
+{
+ tHIDInstance *psInst;
+ uint32_t ui32Size;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // If we are connected, process our idle timers.
+ //
+ if(psInst->bConnected)
+ {
+ ProcessIdleTimers(psHIDDevice, ui32TimemS);
+ }
+
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << HID_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Tell the client that there is a packet waiting for it.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes HID device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID device operation.
+//! \param psHIDDevice points to a structure containing parameters customizing
+//! the operation of the HID device.
+//!
+//! An application wishing to offer a USB HID interface to a host system
+//! must call this function to initialize the USB controller and attach the
+//! device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function will return the \e psHIDDevice
+//! pointer passed to it. This must be passed on all future calls from the
+//! application to the HID device class driver.
+//!
+//! The USB HID device class API offers the application a report-based transmit
+//! interface for Input reports. Output reports may be received via the
+//! control endpoint or via a dedicated Interrupt OUT endpoint. If using the
+//! dedicated endpoint, report data is delivered to the application packet-by-
+//! packet. If the application uses reports longer than \b USBDHID_MAX_PACKET
+//! bytes and would rather receive full reports, it may use a USB buffer above
+//! the receive channel to allow full reports to be read.
+//!
+//! Transmit Operation:
+//!
+//! Calls to USBDHIDReportWrite() pass complete reports to the driver for
+//! transmission. These will be transmitted to the host using as many USB
+//! packets as are necessary to complete the transmission.
+//!
+//! Once a full Input report has been acknowledged by the USB host, a
+//! \b USB_EVENT_TX_COMPLETE event is sent to the application transmit callback
+//! to inform it that another report may be transmitted.
+//!
+//! Receive Operation (when using a dedicated interrupt OUT endpoint):
+//!
+//! An incoming USB data packet will result in a call to the application
+//! callback with event \b USB_EVENT_RX_AVAILABLE. The application must then
+//! call USBDHIDPacketRead(), passing a buffer capable of holding the received
+//! packet. The size of the packet may be determined by calling function
+//! USBDHIDRxPacketAvailable() prior to reading the packet.
+//!
+//! Receive Operation (when not using a dedicated OUT endpoint):
+//!
+//! If no dedicated OUT endpoint is used, Output and Feature reports are sent
+//! from the host using the control endpoint, endpoint zero. When such a
+//! report is received, \b USBD_HID_EVENT_GET_REPORT_BUFFER is sent to the
+//! application which must respond with a buffer large enough to hold the
+//! report. The device class driver will then copy the received report into
+//! the supplied buffer before sending \b USBD_HID_EVENT_SET_REPORT to indicate
+//! that the report is now available.
+//!
+//! \note The application must not make any calls to the low level USB device
+//! interface if interacting with USB via the USB HID device class API. Doing
+//! so will cause unpredictable (though almost certainly unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the \e psHIDDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDInit(uint32_t ui32Index, tUSBDHIDDevice *psHIDDevice)
+{
+ tDeviceDescriptor *pi16DevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psHIDDevice);
+ ASSERT(psHIDDevice->ppui8StringDescriptors);
+ ASSERT(psHIDDevice->pfnRxCallback);
+ ASSERT(psHIDDevice->pfnTxCallback);
+ ASSERT(psHIDDevice->ppui8ClassDescriptors);
+ ASSERT(psHIDDevice->psHIDDescriptor);
+ ASSERT((psHIDDevice->ui8NumInputReports == 0) || psHIDDevice->psReportIdle);
+
+ USBDHIDCompositeInit(ui32Index, psHIDDevice, 0);
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ pi16DevDesc = (tDeviceDescriptor *)psHIDDevice->sPrivateData.sDevInfo.pui8DeviceDescriptor;
+ pi16DevDesc->idVendor = psHIDDevice->ui16VID;
+ pi16DevDesc->idProduct = psHIDDevice->ui16PID;
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the HID device on the bus.
+ //
+ USBDCDInit(ui32Index, &psHIDDevice->sPrivateData.sDevInfo,
+ (void *)psHIDDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID device operation.
+//! \param psHIDDevice points to a structure containing parameters customizing
+//! the operation of the HID device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! USB HID device classes call this function to initialize the lower level
+//! HID interface in the USB controller. If this HID device device is part of
+//! a composite device, then the \e psCompEntry should point to the composite
+//! device entry to initialize. This is part of the array that is passed to
+//! the USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDCompositeInit(uint32_t ui32Index, tUSBDHIDDevice *psHIDDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tHIDInstance *psInst;
+ tEndpointDescriptor *psEndpoint;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psHIDDevice);
+ ASSERT(psHIDDevice->ppsConfigDescriptor);
+ ASSERT(psHIDDevice->ppui8StringDescriptors);
+ ASSERT(psHIDDevice->pfnRxCallback);
+ ASSERT(psHIDDevice->pfnTxCallback);
+ ASSERT(psHIDDevice->ppui8ClassDescriptors);
+ ASSERT(psHIDDevice->psHIDDescriptor);
+ ASSERT((psHIDDevice->ui8NumInputReports == 0) || psHIDDevice->psReportIdle);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sHIDHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8HIDDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = psHIDDevice->ppsConfigDescriptor;
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psHIDDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psHIDDevice->ui32NumStringDescriptors;
+
+ //
+ // Default the endpoints zero before looking for them in the configuration
+ // descriptor.
+ //
+ psInst->ui8Interface = 0;
+ psInst->ui8INEndpoint = 0;
+ psInst->ui8OUTEndpoint = 0;
+
+ //
+ // Get the first endpoint descriptor on interface 0.
+ //
+ psEndpoint =
+ USBDCDConfigGetInterfaceEndpoint(psHIDDevice->ppsConfigDescriptor[0],
+ psInst->ui8Interface, 0, 0);
+
+ if(psEndpoint)
+ {
+ if(psEndpoint->bEndpointAddress & 0x80)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ else
+ {
+ psInst->ui8OUTEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ }
+
+ //
+ // Get the second endpoint descriptor on interface 0.
+ //
+ psEndpoint =
+ USBDCDConfigGetInterfaceEndpoint(psHIDDevice->ppsConfigDescriptor[0],
+ psInst->ui8Interface, 0, 1);
+ if(psEndpoint)
+ {
+ if(psEndpoint->bEndpointAddress & 0x80)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ else
+ {
+ psInst->ui8OUTEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ }
+
+ //
+ // Must have at least an IN endpoint.
+ //
+ if(psInst->ui8INEndpoint == 0)
+ {
+ return((void *)0);
+ }
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psHIDDevice;
+ }
+
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->iHIDRxState = eHIDStateUnconfigured;
+ psInst->iHIDTxState = eHIDStateUnconfigured;
+ psInst->ui16DeferredOpFlags = 0;
+ psInst->bConnected = false;
+ psInst->bGetRequestPending = false;
+ psInst->bSendInProgress = false;
+ psInst->ui16InReportIndex = 0;
+ psInst->ui16InReportSize = 0;
+ psInst->pui8InReportData = (uint8_t *)0;
+ psInst->ui16OutReportSize = 0;
+ psInst->pui8OutReportData = (uint8_t *)0;
+
+ //
+ // Initialize the device info structure for the HID device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Initialize the input report idle timers if any input reports exist.
+ //
+ ClearIdleTimers(psHIDDevice);
+
+ //
+ // Initialize the USB tick module, this will prevent it from being
+ // initialized later in the call to USBDCDInit();
+ //
+ InternalUSBTickInit();
+
+ //
+ // Register our tick handler (this must be done after USBDCDInit).
+ //
+ InternalUSBRegisterTickHandler(HIDTickHandler, (void *)psHIDDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID device.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//!
+//! This function terminates HID operation for the instance supplied and
+//! removes the device from the USB bus. This function should not be called
+//! if the HID device is part of a composite device and instead the
+//! USBDCompositeTerm() function should be called for the full composite
+//! device.
+//!
+//! Following this call, the \e pvHIDInstance instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDTerm(void *pvHIDInstance)
+{
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase));
+
+ psInst->ui32USBBase = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the receive channel
+//! callback.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the receive channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnRxCallback function
+//! passed on USBDHIDInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the pvHIDInstance structure passed to USBDHIDInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's receive callback.
+//
+//*****************************************************************************
+void *
+USBDHIDSetRxCBData(void *pvHIDInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDHIDDevice *)pvHIDInstance)->pvRxCBData;
+ ((tUSBDHIDDevice *)pvHIDInstance)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data pointer for the transmit callback.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the transmit channel callback function.
+//!
+//! The client uses this function to change the callback data pointer passed in
+//! the first parameter on all callbacks to the \e pfnTxCallback function
+//! passed on USBDHIDInit().
+//!
+//! If a client wants to make runtime changes in the callback data, it must
+//! ensure that the pvHIDInstance structure passed to USBDHIDInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback data pointer that was being used for
+//! this instance's transmit callback.
+//
+//*****************************************************************************
+void *
+USBDHIDSetTxCBData(void *pvHIDInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Set the callback data for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDHIDDevice *)pvHIDInstance)->pvTxCBData;
+ ((tUSBDHIDDevice *)pvHIDInstance)->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a HID device report to the USB host via the HID interrupt IN
+//! endpoint.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pi8Data points to the first byte of data which is to be transmitted.
+//! \param ui32Length is the number of bytes of data to transmit.
+//! \param bLast is ignored in this implementation. This parameter is required
+//! to ensure compatibility with other device class drivers and USB buffers.
+//!
+//! This function schedules the supplied data for transmission to the USB
+//! host in a single USB transaction using as many packets as it takes to send
+//! all the data in the report. If no transmission is currently ongoing,
+//! the first packet of data is immediately copied to the relevant USB endpoint
+//! FIFO for transmission. Whenever all the report data has been acknowledged
+//! by the host, a \b USB_EVENT_TX_COMPLETE event will be sent to the
+//! application transmit callback indicating that another report can now be
+//! transmitted.
+//!
+//! The caller must ensure that the data pointed to by \e pui8Data remains
+//! accessible and unaltered until the \b USB_EVENT_TX_COMPLETE is received.
+//!
+//! \return Returns the number of bytes actually scheduled for transmission.
+//! At this level, this will either be the number of bytes passed or 0 to
+//! indicate a failure.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDReportWrite(void *pvHIDInstance, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ tHIDInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Set a flag indicating that we are currently in the process of sending
+ // a packet.
+ //
+ psInst->bSendInProgress = true;
+
+ //
+ // Can we send the data provided?
+ //
+ if(psInst->iHIDTxState != eHIDStateIdle)
+ {
+ //
+ // We are in the middle of sending another report. Return 0 to
+ // indicate that we can't send this report until the previous one
+ // finishes.
+ //
+ psInst->bSendInProgress = false;
+ return(0);
+ }
+
+ //
+ // Clear the elapsed time since this report was last sent.
+ //
+ if(ui32Length)
+ {
+ ClearReportTimer(pvHIDInstance, *pi8Data);
+ }
+
+ //
+ // Keep track of the whereabouts of the report so that we can send it in
+ // multiple packets if necessary.
+ //
+ psInst->pui8InReportData = pi8Data;
+ psInst->ui16InReportIndex = 0;
+ psInst->ui16InReportSize = ui32Length;
+
+ //
+ // Schedule transmission of the first packet of the report.
+ //
+ psInst->iHIDTxState = eHIDStateWaitData;
+ i32Retcode = ScheduleReportTransmission(psInst);
+
+ //
+ // Clear the flag we use to indicate that we are in the midst of sending
+ // a packet.
+ //
+ psInst->bSendInProgress = false;
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ui32Length);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we could not send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the interrupt OUT
+//! endpoint (if in use).
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pi8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by pi8Data.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to \e ui32Length bytes of data received from the USB
+//! host into the supplied application buffer. If the driver detects that the
+//! entire packet has been read, it is acknowledged to the host.
+//!
+//! The \e bLast parameter is ignored in this implementation since the end of
+//! a packet can be determined without relying upon the client to provide
+//! this information.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDPacketRead(void *pvHIDInstance, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ uint32_t ui32EPStatus, ui32Count, ui32Pkt;
+ tHIDInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // How many bytes are available for us to receive?
+ //
+ ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ui32Count = ui32Length;
+ i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ pi8Data, &ui32Count);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ui32Count == ui32Pkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint, true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ HID_DO_PACKET_RX, false);
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(i32Retcode != -1)
+ {
+ return(ui32Count);
+ }
+ }
+
+ //
+ // No packet was available or an error occurred while reading so tell
+ // the caller no bytes were returned.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the transmit buffer.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//!
+//! This function indicates to the caller whether or not it is safe to send a
+//! new report using a call to USBDHIDReportWrite(). The value returned will
+//! be the maximum USB packet size (\b USBDHID_MAX_PACKET) if no transmission
+//! is currently outstanding or 0 if a transmission is in progress. Since the
+//! function USBDHIDReportWrite() can accept full reports longer than a single
+//! USB packet, the caller should be aware that the returned value from this
+//! class driver, unlike others, does not indicate the maximum size of report
+//! that can be written but is merely an indication that another report can be
+//! written.
+//!
+//! \return Returns 0 if an outgoing report is still being transmitted or
+//! \b USBDHID_MAX_PACKET if no transmission is currently in progress.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDTxPacketAvailable(void *pvHIDInstance)
+{
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->iHIDTxState != eHIDStateIdle)
+ {
+ //
+ // We are not ready to receive a new packet so return 0.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // We can receive a packet so return the max packet size for the
+ // relevant endpoint.
+ //
+ return(USBDHID_MAX_PACKET);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//!
+//! This function may be used to determine if a received packet remains to be
+//! read and allows the application to determine the buffer size needed to
+//! read the data.
+//!
+//! \return Returns 0 if no received packet remains unprocessed or the
+//! size of the packet if a packet is waiting to be read.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDRxPacketAvailable(void *pvHIDInstance)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvHIDInstance is the pointer to the HID device instance structure.
+//! \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 USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDPowerStatusSet(void *pvHIDInstance, uint8_t ui8Power)
+{
+ ASSERT(pvHIDInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvHIDInstance is the pointer to the HID device instance structure.
+//!
+//! 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
+USBDHIDRemoteWakeupRequest(void *pvHIDInstance)
+{
+ ASSERT(pvHIDInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDCDRemoteWakeupRequest(0));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhid.h b/usblib/device/usbdhid.h new file mode 100644 index 0000000..14830fa --- /dev/null +++ b/usblib/device/usbdhid.h @@ -0,0 +1,1102 @@ +//*****************************************************************************
+//
+// usbdhid.h - Definitions used by HID class devices.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHID_H__
+#define __USBDHID_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8HIDInterface array in bytes.
+//
+//*****************************************************************************
+#define HIDINTERFACE_SIZE (9)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8HIDInEndpoint array in bytes.
+//
+//*****************************************************************************
+#define HIDINENDPOINT_SIZE (7)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8HIDOutEndpoint array in bytes.
+//
+//*****************************************************************************
+#define HIDOUTENDPOINT_SIZE (7)
+
+//*****************************************************************************
+//
+// This is the size of the tHIDDescriptor in bytes.
+//
+//*****************************************************************************
+#define HIDDESCRIPTOR_SIZE (9)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB HID Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DHID_SIZE (HIDINTERFACE_SIZE + HIDINENDPOINT_SIZE + \
+ HIDOUTENDPOINT_SIZE + HIDDESCRIPTOR_SIZE)
+
+//*****************************************************************************
+//
+// Macros used to create the static Report Descriptors.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Page entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the Usage Page value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Page entry
+//! into a HID report structure. These are defined by the USB HID
+//! specification.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsagePage(ui8Value) 0x05, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Page entries in HID report
+//! descriptors when a vendor-specific value is to be used.
+//!
+//! \param ui16Value is the Usage Page value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Page entry
+//! into a HID report structure. These are defined by the USB HID
+//! specification. Vendor-specific values must lie in the range 0xFF00 to
+//! 0xFFFF inclusive.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsagePageVendor(ui16Value) 0x06, ((ui16Value) & 0xFF), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage entries in HID report descriptors.
+//!
+//! \param ui8Value is the Usage value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage entry into
+//! a HID report structure. These are defined by the USB HID specification.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Usage(ui8Value) 0x09, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding vendor-specific Usage entries in HID
+//! report descriptors.
+//!
+//! \param ui16Value is the vendor-specific Usage value in the range 0xFF00 to
+//! 0xFFFF.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage entry into
+//! a HID report structure. These are defined by the USB HID specification.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsageVendor(ui16Value) 0x0A, ((ui16Value) & 0xFF), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Minimum entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the Usage Minimum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Minimum
+//! entry into a HID report structure. This is the first or minimum value
+//! associated with a usage value.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsageMinimum(ui8Value) 0x19, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Maximum entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the Usage Maximum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Maximum
+//! entry into a HID report structure. This is the last or maximum value
+//! associated with a usage value.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsageMaximum(ui8Value) 0x29, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Logical Minimum entries in HID report
+//! descriptors.
+//!
+//! \param i8Value is the Logical Minimum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Logical Minimum
+//! entry into a HID report structure. This is the actual minimum value for a
+//! range of values associated with a field.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define LogicalMinimum(i8Value) 0x15, ((i8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Logical Maximum entries in HID report
+//! descriptors.
+//!
+//! \param i8Value is the Logical Maximum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Logical Maximum
+//! entry into a HID report structure. This is the actual maximum value for a
+//! range of values associated with a field.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define LogicalMaximum(i8Value) 0x25, ((i8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Physical Minimum entries in HID report
+//! descriptors.
+//!
+//! \param i16Value is the Physical Minimum value. It is a signed, 16 bit
+//! number.
+//!
+//! This macro takes a value and prepares it to be placed as a Physical Minimum
+//! entry into a HID report structure. This is value is used in conversion of
+//! the control logical value, as returned to the host in the relevant report,
+//! to a physical measurement in the appropriate units.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define PhysicalMinimum(i16Value) \
+ 0x36, ((i16Value) & 0xFF), \
+ (((i16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Physical Maximum entries in HID report
+//! descriptors.
+//!
+//! \param i16Value is the Physical Maximum value. It is a signed, 16 bit
+//! number.
+//!
+//! This macro takes a value and prepares it to be placed as a Physical Maximum
+//! entry into a HID report structure. This is value is used in conversion of
+//! the control logical value, as returned to the host in the relevant report,
+//! to a physical measurement in the appropriate units.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define PhysicalMaximum(i16Value) \
+ 0x46, ((i16Value) & 0xFF), \
+ (((i16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Collection entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the type of Collection.
+//!
+//! This macro takes a value and prepares it to be placed as a Collection
+//! entry into a HID report structure. This is the type of values that are
+//! being grouped together, for instance input, output or features can be
+//! grouped together as a collection.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Collection(ui8Value) 0xa1, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding End Collection entries in HID report
+//! descriptors.
+//!
+//! This macro can be used to place an End Collection entry into a HID report
+//! structure. This is a tag to indicate that a collection of entries has
+//! ended in the HID report structure. This terminates a previous Collection()
+//! entry.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define EndCollection 0xc0
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report Count entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the number of items in a report item.
+//!
+//! This macro takes a value and prepares it to be placed as a Report Count
+//! entry into a HID report structure. This is number of entries of Report
+//! Size for a given item.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define ReportCount(ui8Value) 0x95, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report ID entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the identifier prefix for the current report.
+//!
+//! This macro takes a value and prepares it to be placed as a Report ID
+//! entry into a HID report structure. This value is used as a 1 byte prefix
+//! for the report it is contained within.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define ReportID(ui8Value) 0x85, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report Size entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the size, in bits, of items in a report item.
+//!
+//! This macro takes a value and prepares it to be placed as a Report Size
+//! entry into a HID report structure. This is size in bits of the entries of
+//! of a report entry. The Report Count specifies how many entries of Report
+//! Size are in a given item. These can be individual bits or bit fields.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define ReportSize(ui8Value) 0x75, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Input entries in HID report descriptors.
+//!
+//! \param ui8Value is bit mask to specify the type of a set of input report
+//! items. Note that if the USB_HID_INPUT_BITF flag is required, the Input2
+//! macro (which uses a 2 byte version of the Input item tag) must be used
+//! instead of this macro.
+//!
+//! This macro takes a value and prepares it to be placed as an Input entry
+//! into a HID report structure. This specifies the type of an input item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of input for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Input(ui8Value) 0x81, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Input entries in HID report descriptors.
+//!
+//! \param ui16Value is bit mask to specify the type of a set of input report
+//! items. Note that this macro uses a version of the Input item tag with a
+//! two byte payload and allows any of the 8 possible data bits for the tag to
+//! be used. If USB_HID_INPUT_BITF (bit 8) is not required, the Input macro
+//! may be used instead.
+//!
+//! This macro takes a value and prepares it to be placed as an Input entry
+//! into a HID report structure. This specifies the type of an input item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of input for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Input2(ui16Value) 0x82, ((ui16Value) & 0xff), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Feature entries in HID report descriptors.
+//!
+//! \param ui8Value is bit mask to specify the type of a set of feature report
+//! items. Note that if the \b USB_HID_FEATURE_BITF flag is required, the
+//! Feature2 macro (which uses a 2 byte version of the Feature item tag) must
+//! be used instead of this macro.
+//!
+//! This macro takes a value and prepares it to be placed as a Feature entry
+//! into a HID report structure. This specifies the type of a feature item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of feature for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Feature(ui8Value) 0xB1, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Feature entries in HID report descriptors.
+//!
+//! \param ui16Value is bit mask to specify the type of a set of feature report
+//! items. Note that this macro uses a version of the Feature item tag with a
+//! two byte payload and allows any of the 8 possible data bits for the tag to
+//! be used. If \b USB_HID_FEATURE_BITF (bit 8) is not required, the Feature
+//! macro may be used instead.
+//!
+//! This macro takes a value and prepares it to be placed as a Feature entry
+//! into a HID report structure. This specifies the type of a feature item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of feature for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Feature2(ui16Value) 0xB2, ((ui16Value) & 0xff), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Output entries in HID report descriptors.
+//!
+//! \param ui8Value is bit mask to specify the type of a set of output report
+//! items. Note that if the \b USB_HID_OUTPUT_BITF flag is required, the
+//! Output2 macro (which uses a 2 byte version of the Output item tag) must be
+//! used instead of this macro.
+//!
+//! This macro takes a value and prepares it to be placed as an Output entry
+//! into a HID report structure. This specifies the type of an output item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of output for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Output(ui8Value) 0x91, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Output entries in HID report descriptors.
+//!
+//! \param ui16Value is bit mask to specify the type of a set of output report
+//! items. Note that this macro uses a version of the Output item tag with a
+//! two byte payload and allows any of the 8 possible data bits for the tag to
+//! be used. If \b USB_HID_OUTPUT_BITF is not required, the Output macro
+//! may be used instead.
+//!
+//! This macro takes a value and prepares it to be placed as an Output entry
+//! into a HID report structure. This specifies the type of an output item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of output for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Output2(ui16Value) 0x92, ((ui16Value) & 0xff), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Unit Exponent entries in HID report
+//! descriptors.
+//!
+//! \param i8Value is the required exponent in the range [-8, 7].
+//!
+//! This macro takes a value and prepares it to be placed as a Unit Exponent
+//! entry into a HID report structure. This is the exponent applied to
+//! PhysicalMinimum and PhysicalMaximum when scaling and converting control
+//! values to "real" units.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UnitExponent(i8Value) 0x55, ((i8Value) & 0x0f)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Unit entries for uncommon units in HID
+//! report descriptors.
+//!
+//! \param ui32Value is the definition of the unit required as defined in
+//! section 6.2.2.7 of the USB HID device class definition document.
+//!
+//! This macro takes a value and prepares it to be placed as a Unit entry into
+//! a HID report structure. Note that individual macros are defined for common
+//! units and this macro is intended for use when a complex or uncommon unit
+//! is needed. It allows entry of a 5 nibble unit definition into the report
+//! descriptor.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Unit(ui32Value) 0x67, (ui32Value) & 0x0f), \
+ (((ui32Value) >> 8) & 0xFF), \
+ (((ui32Value) >> 16) & 0xFF), \
+ (((ui32Value) >> 24) & 0xFF)
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for centimeters into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitDistance_cm 0x66, 0x11, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for inches into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitDistance_i 0x66, 0x13, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for degrees into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitRotation_deg 0x66, 0x14, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for radians into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitRotation_rad 0x66, 0x12, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for grams into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitMass_g 0x66, 0x01, 0x01
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for seconds into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitTime_s 0x66, 0x01, 0x10
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for temperature in Kelvin into a report
+//! descriptor.
+//!
+//*****************************************************************************
+#define UnitTemp_K 0x67, 0x01, 0x00, 0x01, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for temperature in Fahrenheit into a report
+//! descriptor.
+//!
+//*****************************************************************************
+#define UnitTemp_F 0x67, 0x03, 0x00, 0x01, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for velocity in cm/s into a report
+//! descriptor.
+//!
+//*****************************************************************************
+#define UnitVelocitySI 0x66, 0x11, 0xF0
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for momentum in (grams * cm)/s into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitMomentumSI 0x66, 0x11, 0xF1
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for acceleration in cm/s**2 into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitAccelerationSI 0x66, 0x11, 0xE0
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for force in (cm * grams)/s**2 into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitForceSI 0x66, 0x11, 0xE1
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for energy in (grams * cm^2)/(s^2) into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitEnergySI 0x66, 0x21, 0xE1
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for angular acceleration in degrees/(s^2)
+//! into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitAngAccelerationSI 0x66, 0x12, 0xE0
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for voltage into a a report descriptor.
+//!
+//*****************************************************************************
+#define UnitVoltage 0x67, 0x21, 0xD1, 0xF0, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for voltage into a a report descriptor.
+//!
+//*****************************************************************************
+#define UnitCurrent_A 0x67, 0x01, 0x00, 0x10, 0x00
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB HID code and are here only to help with the application
+// allocating the correct amount of memory for the HID device code.
+//
+//*****************************************************************************
+#define USBDHID_MAX_PACKET 64
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ eHIDStateUnconfigured,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ eHIDStateIdle,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ eHIDStateWaitData
+}
+tHIDState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for
+// HID devices. The memory for this structure is included in the
+// sPrivateData field in the tUSBDHIDDevice structure passed in the
+// USBDHIDInit() function.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The state of the HID receive channel.
+ //
+ volatile tHIDState iHIDRxState;
+
+ //
+ // The state of the HID transmit channel.
+ //
+ volatile tHIDState iHIDTxState;
+
+ //
+ // State of any pending operations that could not be handled immediately
+ // upon receipt.
+ //
+ volatile uint16_t ui16DeferredOpFlags;
+
+ //
+ // Size of the HID IN report.
+ //
+ uint16_t ui16InReportSize;
+
+ //
+ // .
+ //
+ uint16_t ui16InReportIndex;
+
+ //
+ // Size of the HID OUT report.
+ //
+ uint16_t ui16OutReportSize;
+
+ //
+ // Pointer to the current HID IN report data.
+ //
+ uint8_t *pui8InReportData;
+
+ //
+ // Pointer to the current HID OUT report data.
+ //
+ uint8_t *pui8OutReportData;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // Whether an IN transaction is in process.
+ //
+ volatile bool bSendInProgress;
+
+ //
+ // An HID request transaction is in process(Endpoint 0).
+ //
+ bool bGetRequestPending;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8INEndpoint;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The bulk class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+}
+tHIDInstance;
+
+//*****************************************************************************
+//
+//! The structure used to track idle time for reports. An array of these
+//! structures is passed to the HID device class driver during USBDHIDInit and
+//! is used to track automatic resending of each report (if not disabled by
+//! the host).
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The idle duration for the report expressed in units of 4mS. 0
+ //! indicates infinite and informs the class driver not to send the report
+ //! unless a state change occurs.
+ //
+ uint8_t ui8Duration4mS;
+
+ //
+ //! The ID of the report which this structure applies to. This is the
+ //! report ID as specified using a ReportID tag in the report descriptor
+ //! rather than the index of the report in the HID class descriptor array.
+ //! If only a single Input report is supported and, thus, no ReportID tag
+ //! is present, this field should be set to 0.
+ //
+ uint8_t ui8ReportID;
+
+ //
+ //! The number of milliseconds before we need to send a copy of a given
+ //! report back to the host. This field is updated by the HID driver and
+ //! used to time sending of \b USBD_HID_EVENT_IDLE_TIMEOUT.
+ //
+ uint16_t ui16TimeTillNextmS;
+
+ //
+ //! The number of milliseconds that have passed since the last time this
+ //! report was sent. The HID class driver needs to track this since
+ //! Set_Idle requests are required to take effect as if issued immediately
+ //! after the last transmission of the report to which they refer.
+ //
+ uint32_t ui32TimeSinceReportmS;
+}
+tHIDReportIdle;
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the HID device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ uint8_t ui8PwrAttributes;
+
+ //
+ //! The interface subclass to publish to the server for this HID device.
+ //
+ uint8_t ui8Subclass;
+
+ //
+ //! The interface protocol to publish to the server for this HID device.
+ //
+ uint8_t ui8Protocol;
+
+ //
+ //! The number of Input reports that this device supports. This field
+ //! must equal the number of reports published in the HID class descriptors
+ //! for the device and also the number of entries in the array whose first
+ //! element is pointed to by field \e pi16ReportIdle below.
+ //
+ uint8_t ui8NumInputReports;
+
+ //
+ //! A pointer to the first element in an array of structures used to track
+ //! idle time for each Input report. When USBDHIDInit() is called, the
+ //! ui8Duration4mS and ui8ReportID fields of each of these array members
+ //! should be initialized to indicate the default idle timeout for each
+ //! input report. This array must be in RAM since the HID device class
+ //! driver updates values in it in response to requests from the host
+ //! and to track elapsed time. The number of elements in the array must
+ //! match the number supplied in the ui8NumInputReports field above.
+ //
+ tHIDReportIdle *psReportIdle;
+
+ //! A pointer to the callback function which is called to notify
+ //! the application of general events, events related to report transfers
+ //! on endpoint zero and events related to reception of Output and Feature
+ //! reports via the (optional) interrupt OUT endpoint.
+ //
+ tUSBCallback pfnRxCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the receive channel callback,
+ //! pfnRxCallback.
+ //
+ void *pvRxCBData;
+
+ //
+ //! A pointer to the callback function which is called to notify
+ //! the application of events related to transmission of Input reports
+ //! via the interrupt IN endpoint.
+ //
+ tUSBCallback pfnTxCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the transmit channel callback,
+ //! pfnTxCallback.
+ //
+ void *pvTxCBData;
+
+ //
+ //! If set to true, this field indicates that the device should use a
+ //! dedicated interrupt OUT endpoint to receive reports from the host. In
+ //! this case, reports from the host are passed to the application via the
+ //! receive callback using \b USB_EVENT_RX_AVAILABLE events. If false,
+ //! reports from the host are received via endpoint zero and passed to the
+ //! application via \b USBD_HID_EVENT_REPORT_SENT events.
+ //
+ bool bUseOutEndpoint;
+
+ //
+ //! The HID descriptor that the device is to publish (following the
+ //! standard interface descriptor and prior to the endpoint descriptors for
+ //! the interface).
+ //
+ const tHIDDescriptor *psHIDDescriptor;
+
+ //
+ //! The HID class descriptors offered by the device are defined in an
+ //! array of byte pointers and this field points to that array. The
+ //! order and number of elements in the array must match the associated
+ //! information provided in the HID descriptor in field by
+ //! \e pi16HIDDescriptor.
+ //
+ const uint8_t * const *ppui8ClassDescriptors;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1), (optionally) First HID device-specific string
+ //! (language 1), (optionally) Second HID device-specific string (language
+ //! 1), etc.
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //! The number of HID device-specific strings is dependent upon the content
+ //! of the report descriptor passed to the interface and is, thus,
+ //! application controlled.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the \e ppStringDescriptors
+ //! array. This must be 1 + ((5 + (num HID strings)) * (num languages)).
+ //
+ uint32_t ui32NumStringDescriptors;
+
+ //
+ // ! The configuration descriptor for this HID device.
+ //
+ const tConfigHeader * const *ppsConfigDescriptor;
+
+ //
+ //! The private instance data for this device instance. This
+ //! memory must remain accessible for as long as the HID device is in
+ //! use and must not be modified by any code outside the HID class driver.
+ //
+ tHIDInstance sPrivateData;
+}
+tUSBDHIDDevice;
+
+//*****************************************************************************
+//
+// HID-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the host is requesting a particular report be
+//! returned via endpoint 0, the control endpoint. The ui32MsgValue parameter
+//! contains the requested report type in the high byte and report ID in the
+//! low byte (as passed in the wValue field of the USB request structure).
+//! The pvMsgData parameter contains a pointer which must be written with the
+//! address of the first byte of the requested report. The callback must
+//! return the size in bytes of the report pointed to by *pvMsgData. The
+//! memory returned in response to this event must remain unaltered until
+//! \b USBD_HID_EVENT_REPORT_SENT is sent.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_GET_REPORT \
+ (USBD_HID_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This event indicates that a report previously requested via a
+//! \b USBD_HID_EVENT_GET_REPORT has been successfully transmitted to the host.
+//! The application may now free or reuse the report memory passed on the
+//! previous event. Although this would seem to be an event that would be
+//! passed to the transmit channel callback, it is actually passed to the
+//! receive channel callback. This ensures that all events related to the
+//! request and transmission of reports via endpoint zero can be handled in
+//! a single function.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_REPORT_SENT \
+ (USBD_HID_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+//! This event indicates that the host has sent a Set_Report request to
+//! the device and requests that the device provide a buffer into which the
+//! report can be written. The ui32MsgValue parameter contains the received
+//! report type in the high byte and report ID in the low byte (as passed in
+//! the wValue field of the USB request structure). The pvMsgData parameter
+//! contains the length of buffer requested. Note that this is the actual
+//! length value cast to a "void *" type and not a pointer in this case.
+//! The callback must return a pointer to a suitable buffer (cast to the
+//! standard "uint32_t" return type for the callback).
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_GET_REPORT_BUFFER \
+ (USBD_HID_EVENT_BASE + 2)
+
+//*****************************************************************************
+//
+//! This event indicates that the host has sent the device a report via
+//! endpoint 0, the control endpoint. The ui32MsgValue field indicates the
+//! size of the report and pvMsgData points to the first byte of the report.
+//! The report buffer was previously returned in response to an
+//! earlier \b USBD_HID_EVENT_GET_REPORT_BUFFER callback. The HID device class
+//! driver does not access the memory pointed to by pvMsgData after this
+//! callback is made so the application is free to reuse or free it at this
+//! point.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_SET_REPORT \
+ (USBD_HID_EVENT_BASE + 3)
+
+//*****************************************************************************
+//
+//! This event is sent in response to a Get_Protocol request from the host.
+//! The callback should provide the current protocol via the return code,
+//! \b USB_HID_PROTOCOL_BOOT or \b USB_HID_PROTOCOL_REPORT.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_GET_PROTOCOL \
+ (USBD_HID_EVENT_BASE + 4)
+
+//*****************************************************************************
+//
+//! This event is sent in response to a Set_Protocol request from the host.
+//! The ui32MsgData value contains the requested protocol,
+//! \b USB_HID_PROTOCOL_BOOT or \b USB_HID_PROTOCOL_REPORT.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_SET_PROTOCOL \
+ (USBD_HID_EVENT_BASE + 5)
+
+//*****************************************************************************
+//
+//! This event indicates to an application that a report idle timeout has
+//! occurred and requests a pointer to the report that must be sent back to
+//! the host. The ui32MsgData value contains the requested report ID and
+//! pvMsgData contains a pointer that must be written with a pointer to the
+//! report data that is to be sent. The callback must return the number of
+//! bytes in the report pointed to by *pvMsgData.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_IDLE_TIMEOUT \
+ (USBD_HID_EVENT_BASE + 6)
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDInit(uint32_t ui32Index, tUSBDHIDDevice *psHIDDevice);
+extern void *USBDHIDCompositeInit(uint32_t ui32Index,
+ tUSBDHIDDevice *psDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDTerm(void *pvHIDInstance);
+extern void *USBDHIDSetRxCBData(void *pvHIDInstance, void *pvCBData);
+extern void *USBDHIDSetTxCBData(void *pvHIDInstance, void *pvCBData);
+extern uint32_t USBDHIDReportWrite(void *pvHIDInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDHIDPacketRead(void *pvHIDInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDHIDTxPacketAvailable(void *pvHIDInstance);
+extern uint32_t USBDHIDRxPacketAvailable(void *pvHIDInstance);
+extern bool USBDHIDRemoteWakeupRequest(void *pvHIDInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+
+//
+// Use USBDCDFeatureSet() or USBHCDFeatureSet() with \b USBLIB_FEATURE_POWER
+// configuration option.
+//
+extern void USBDHIDPowerStatusSet(void *pvHIDInstance, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHID_H__
diff --git a/usblib/device/usbdhidgamepad.c b/usblib/device/usbdhidgamepad.c new file mode 100644 index 0000000..a0945cc --- /dev/null +++ b/usblib/device/usbdhidgamepad.c @@ -0,0 +1,845 @@ +//*****************************************************************************
+//
+// usbdhidgame.c - USB HID Gamepad device class driver
+//
+// Copyright (c) 2013-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_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/device/usbdhidgamepad.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_gamepad_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+//*****************************************************************************
+static uint8_t g_pui8GameDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(24), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Self Powered.
+ 0, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// This is the HID interface descriptor for the gamepad device.
+//
+//*****************************************************************************
+static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
+{
+ //
+ // HID Device Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_HID, // The interface class
+ 0, // The interface sub-class.
+ 0, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+};
+
+//*****************************************************************************
+//
+// This is the HID IN endpoint descriptor for the gamepad device.
+//
+//*****************************************************************************
+static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 1, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The following is the HID report structure definition that is passed back
+// to the host.
+//
+//*****************************************************************************
+static const uint8_t g_pui8GameReportDescriptor[] =
+{
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_JOYSTICK),
+ Collection(USB_HID_APPLICATION),
+ //
+ // The axis for the controller.
+ //
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage (USB_HID_POINTER),
+ Collection (USB_HID_PHYSICAL),
+
+ //
+ // The X, Y and Z values which are specified as 8-bit absolute
+ // position values.
+ //
+ Usage (USB_HID_X),
+ Usage (USB_HID_Y),
+ Usage (USB_HID_Z),
+
+ //
+ // 3 8-bit absolute values.
+ //
+ ReportSize(8),
+ ReportCount(3),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_ABS),
+
+ //
+ // The 8 buttons.
+ //
+ UsagePage(USB_HID_BUTTONS),
+ UsageMinimum(1),
+ UsageMaximum(8),
+ LogicalMinimum(0),
+ LogicalMaximum(1),
+ PhysicalMinimum(0),
+ PhysicalMaximum(1),
+
+ //
+ // 8 - 1 bit values for the buttons.
+ //
+ ReportSize(1),
+ ReportCount(8),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_ABS),
+
+ EndCollection,
+ EndCollection
+};
+
+//*****************************************************************************
+//
+// The HID descriptor for the gamepad device.
+//
+//*****************************************************************************
+static tHIDDescriptor g_sGameHIDDescriptor =
+{
+ 9, // bLength
+ USB_HID_DTYPE_HID, // bDescriptorType
+ 0x111, // bcdHID (version 1.11 compliant)
+ 0, // bCountryCode (not localized)
+ 1, // bNumDescriptors
+ {
+ {
+ USB_HID_DTYPE_REPORT, // Report descriptor
+ sizeof(g_pui8GameReportDescriptor)
+ // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// The HID configuration descriptor is defined as four sections.
+// These sections are:
+//
+// 1. The 9 byte configuration descriptor.
+// 2. The interface descriptor.
+// 3. The HID report and physical descriptors, provided by the application
+// or the default can be used.
+// 4. The mandatory interrupt IN endpoint descriptor.
+//
+//*****************************************************************************
+static const tConfigSection g_sHIDConfigSection =
+{
+ sizeof(g_pui8GameDescriptor),
+ g_pui8GameDescriptor
+};
+
+static const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pui8HIDInterface),
+ g_pui8HIDInterface
+};
+
+static const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pui8HIDInEndpoint),
+ g_pui8HIDInEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+static tConfigSection g_sHIDDescriptorSection =
+{
+ sizeof(g_sGameHIDDescriptor),
+ (const uint8_t *)&g_sGameHIDDescriptor
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete HID configuration descriptor.
+//
+//*****************************************************************************
+static const tConfigSection *g_psHIDSections[] =
+{
+ &g_sHIDConfigSection,
+ &g_sHIDInterfaceSection,
+ &g_sHIDDescriptorSection,
+ &g_sHIDInEndpointSection,
+};
+
+#define NUM_HID_SECTIONS ((sizeof(g_psHIDSections) / \
+ sizeof(tConfigSection *)))
+
+//*****************************************************************************
+//
+// The header for the single configuration supported. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor. Note that this must be
+// in RAM since we need to include or exclude the final section based on
+// client supplied initialization parameters.
+//
+//*****************************************************************************
+static tConfigHeader g_sHIDConfigHeader =
+{
+ NUM_HID_SECTIONS,
+ g_psHIDSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+static const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the gamepad class there is only a
+// single report descriptor.
+//
+//*****************************************************************************
+static const uint8_t *g_ppui8GameClassDescriptors[] =
+{
+ g_pui8GameReportDescriptor
+};
+
+//*****************************************************************************
+//
+// HID gamepad transmit channel event handler function.
+//
+// \param pvGameDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to the HID gamepad device structure
+// of the type tUSBDHIDGamepadDevice.
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the lower level HID device class driver to inform
+// the application of particular asynchronous events related to report events
+// related to using the interrupt IN endpoint.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDGamepadTxHandler(void *pvGameDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDGamepadDevice *psGamepad;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvGameDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psGamepad = (tUSBDHIDGamepadDevice *)pvGameDevice;
+ psInst = &psGamepad->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // The last transmission is complete so return to the idle state.
+ //
+ psInst->iState = eHIDGamepadStateIdle;
+
+ //
+ // Pass the event on to the application.
+ //
+ psGamepad->pfnCallback(psGamepad->pvCBData, USB_EVENT_TX_COMPLETE,
+ ui32MsgData, (void *)0);
+
+ break;
+ }
+
+ //
+ // Ignore all other events related to transmission of reports via
+ // the interrupt IN endpoint.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Main HID device class event receive handler function.
+//
+// \param pvGameDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to the HID gamepad device structure
+// of the type tUSBDHIDGamepadDevice.
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the lower level HID device class driver to inform
+// the application of particular asynchronous events related to operation of
+// the gamepad HID device.
+//
+// \note This function also receive all generic events as well such as
+// \b USB_EVENT_CONNECTED and USB_EVENT_DISCONNECTED.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDGamepadRxHandler(void *pvGamepad, uint32_t ui32Event, uint32_t ui32MsgData,
+ void *pvMsgData)
+{
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDGamepadDevice *psGamepad;
+ uint32_t ui32Ret;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvGamepad);
+
+ //
+ // Return zero by default.
+ //
+ ui32Ret = 0;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psGamepad = (tUSBDHIDGamepadDevice *)pvGamepad;
+ psInst = &psGamepad->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch(ui32Event)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ //
+ // Now in the idle state.
+ //
+ psInst->iState = eHIDGamepadStateIdle;
+
+ //
+ // Pass the information on to the application.
+ //
+ psGamepad->pfnCallback(psGamepad->pvCBData, USB_EVENT_CONNECTED, 0,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->iState = eHIDGamepadStateNotConnected;
+
+ //
+ // Pass the information on to the application.
+ //
+ ui32Ret = psGamepad->pfnCallback(psGamepad->pvCBData,
+ USB_EVENT_DISCONNECTED, 0,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // This handles the Set Idle command.
+ //
+ case USBD_HID_EVENT_IDLE_TIMEOUT:
+ {
+ //
+ // Give the pointer to the idle report structure.
+ //
+ *(void **)pvMsgData = (void *)&psInst->sReportIdle;
+
+ ui32Ret = sizeof(psInst->sReportIdle);
+
+ break;
+ }
+
+ //
+ // The host is polling for a particular report and the HID driver
+ // is asking for the latest version to transmit.
+ //
+ case USBD_HID_EVENT_GET_REPORT:
+ {
+ //
+ // If this is an IN request then pass the request on to the
+ // application. All other requests are ignored.
+ //
+ if(ui32MsgData == USB_HID_REPORT_IN)
+ {
+ ui32Ret = psGamepad->pfnCallback(psGamepad->pvCBData,
+ USBD_HID_EVENT_GET_REPORT, 0,
+ pvMsgData);
+ }
+
+ break;
+ }
+
+ //
+ // The device class driver has completed sending a report to the
+ // host in response to a Get_Report request.
+ //
+ case USBD_HID_EVENT_REPORT_SENT:
+ {
+ //
+ // We have nothing to do here.
+ //
+ break;
+ }
+
+ //
+ // Pass these events to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ case USB_EVENT_LPM_RESUME:
+ case USB_EVENT_LPM_SLEEP:
+ case USB_EVENT_LPM_ERROR:
+ {
+ ui32Ret = psGamepad->pfnCallback(psGamepad->pvCBData, ui32Event,
+ ui32MsgData, pvMsgData);
+
+ break;
+ }
+
+ //
+ // This event is sent in response to a host Set_Report request which
+ // is not supported for gamepads.
+ //
+ case USBD_HID_EVENT_GET_REPORT_BUFFER:
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID gamepad device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller that is to be
+//! initialized for HID gamepad device operation.
+//! \param psGamepad points to a structure containing parameters
+//! customizing the operation of the HID gamepad device.
+//!
+//! An application that enables a USB HID gamepad interface to a USB host
+//! must call this function to initialize the USB controller and attach the
+//! gamepad device to the USB bus. This function performs all required USB
+//! initialization, and the device is ready for operation on the function
+//! return.
+//!
+//! On successful completion, this function returns the modified \e psGamepad
+//! pointer passed to it or returns a NULL pointer if there was a problem.
+//! This pointer must be passed on all future calls to the HID gamepad device
+//! driver.
+//!
+//! When a host connects and configures the device, the application callback
+//! receives \b USB_EVENT_CONNECTED, after which calls can be made to
+//! USBDHIDGamepadSendReport() to report changes to the gamepad interface to
+//! the USB host when it requests them.
+//!
+//! \note The application must not make any calls to the lower level USB device
+//! interfaces if interacting with USB via the USB HID gamepad device class
+//! API.
+//!
+//! \return Returns NULL on failure or the \e psGamepad pointer on success.
+//
+//*****************************************************************************
+tUSBDHIDGamepadDevice *
+USBDHIDGamepadInit(uint32_t ui32Index, tUSBDHIDGamepadDevice *psGamepad)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+ tConfigDescriptor *pConfigDesc;
+
+ //
+ // Check basic parameter validity.
+ //
+ ASSERT(psGamepad);
+ ASSERT(psGamepad->ppui8StringDescriptors);
+ ASSERT(psGamepad->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psGamepad->sPrivateData.sHIDDevice;
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDGamepadCompositeInit(ui32Index, psGamepad, 0);
+
+ pConfigDesc = (tConfigDescriptor *)g_pui8GameDescriptor;
+ pConfigDesc->bmAttributes = psGamepad->ui8PwrAttributes;
+ pConfigDesc->bMaxPower = (uint8_t)(psGamepad->ui16MaxPowermA / 2);
+
+ //
+ // If we initialized the HID layer successfully, pass our device pointer
+ // back as the return code, otherwise return NULL to indicate an error.
+ //
+ if(pvRetcode)
+ {
+ //
+ // Initialize the lower layer HID driver and pass it the various
+ // structures and descriptors necessary to declare that we are a
+ // gamepad.
+ //
+ pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
+
+ return(psGamepad);
+ }
+ else
+ {
+ return((tUSBDHIDGamepadDevice *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID gamepad device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller that is to be
+//! initialized for HID gamepad device operation.
+//! \param psGamepad points to a structure containing parameters
+//! customizing the operation of the HID gamepad device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDHIDGamepadInit() except that it is used
+//! for initializing an instance of the HID gamepad device for use in a
+//! composite device. If this HID gamepad is part of a composite device, then
+//! the \e psCompEntry should point to the composite device entry to
+//! initialize. This entry is part of the array that is passed to the
+//! USBDCompositeInit() function to start up and complete configuration of a
+//! composite USB device.
+//!
+//! \return Returns NULL on failure or the \e psGamepad value that should be
+//! used with the remaining USB HID gamepad APIs.
+//
+//*****************************************************************************
+tUSBDHIDGamepadDevice *
+USBDHIDGamepadCompositeInit(uint32_t ui32Index,
+ tUSBDHIDGamepadDevice *psGamepad,
+ tCompositeEntry *psCompEntry)
+{
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psGamepad);
+ ASSERT(psGamepad->ppui8StringDescriptors);
+ ASSERT(psGamepad->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psGamepad->sPrivateData;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->iState = eHIDGamepadStateNotConnected;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psInst->sHIDDevice;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->ui16PID = psGamepad->ui16PID;
+ psHIDDevice->ui16VID = psGamepad->ui16VID;
+ psHIDDevice->ui16MaxPowermA = psGamepad->ui16MaxPowermA;
+ psHIDDevice->ui8PwrAttributes = psGamepad->ui8PwrAttributes;
+ psHIDDevice->ui8Subclass = 0;
+ psHIDDevice->ui8Protocol = 0;
+ psHIDDevice->ui8NumInputReports = 1;
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+ psInst->sReportIdle.ui8Duration4mS = 125;
+ psInst->sReportIdle.ui8ReportID = 0;
+ psInst->sReportIdle.ui32TimeSinceReportmS = 0;
+ psInst->sReportIdle.ui16TimeTillNextmS = 0;
+ psHIDDevice->pfnTxCallback = HIDGamepadTxHandler;
+ psHIDDevice->pvRxCBData = (void *)psGamepad;
+ psHIDDevice->pfnRxCallback = HIDGamepadRxHandler;
+ psHIDDevice->pvTxCBData = (void *)psGamepad;
+ psHIDDevice->bUseOutEndpoint = false,
+ psHIDDevice->psHIDDescriptor = &g_sGameHIDDescriptor;
+ psHIDDevice->ppui8ClassDescriptors = g_ppui8GameClassDescriptors;
+ psHIDDevice->ppui8StringDescriptors = psGamepad->ppui8StringDescriptors;
+ psHIDDevice->ui32NumStringDescriptors =
+ psGamepad->ui32NumStringDescriptors;
+ psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
+
+ //
+ // If there was an override for the report descriptor then use it.
+ //
+ if(psGamepad->pui8ReportDescriptor)
+ {
+ //
+ // Save the report descriptor in the list of report descriptors.
+ //
+ g_ppui8GameClassDescriptors[0] = psGamepad->pui8ReportDescriptor;
+
+ //
+ // Override the report descriptor size.
+ //
+ g_sGameHIDDescriptor.sClassDescriptor[0].wDescriptorLength =
+ psGamepad->ui32ReportSize;
+ }
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a gamepad.
+ //
+ return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
+}
+
+//*****************************************************************************
+//
+//! Schedules a report to be sent once the host requests more data.
+//!
+//! \param psHIDGamepad is the structure pointer that is returned from the
+//! USBDHIDGamepadCompositeInit() or USBDHIDGamepadInit() functions.
+//! \param pvReport is the data to send to the host.
+//! \param ui32Size is the number of bytes in the \e pvReport buffer.
+//!
+//! This call is made by an application to schedule data to be sent to the
+//! host when the host requests an update from the device. The application
+//! must then wait for a \b USB_EVENT_TX_COMPLETE event in the function
+//! provided in the \e pfnCallback pointer in the tUSBDHIDGamepadDevice
+//! structure before being able to send more data with this function. The
+//! pointer passed in the \e pvReport can be updated once this call returns as
+//! the data has been copied from the buffer. The function returns
+//! \b USBDGAMEPAD_SUCCESS if the transmission was successfully scheduled or
+//! \b USBDGAMEPAD_TX_ERROR if the report could not be sent at this time.
+//! If the call is made before the device is connected or ready to communicate
+//! with the host, then the function can return \b USBDGAMEPAD_NOT_CONFIGURED.
+//!
+//! \return The function returns one of the \b USBDGAMEPAD_* values.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDGamepadSendReport(tUSBDHIDGamepadDevice *psHIDGamepad, void *pvReport,
+ uint32_t ui32Size)
+{
+ uint32_t ui32Retcode, ui32Count;
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDGamepad->sPrivateData.sHIDDevice;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psHIDGamepad->sPrivateData;
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(psInst->iState == eHIDGamepadStateNotConnected)
+ {
+ return(USBDGAMEPAD_NOT_CONFIGURED);
+ }
+
+ //
+ // Only send a report if the transmitter is currently free.
+ //
+ if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
+ {
+ //
+ // Send the report to the host.
+ //
+ psInst->iState = eHIDGamepadStateSending;
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice, pvReport, ui32Size,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(ui32Count == 0)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ ui32Retcode = USBDGAMEPAD_TX_ERROR;
+ }
+ else
+ {
+ ui32Retcode = USBDGAMEPAD_SUCCESS;
+ }
+ }
+ else
+ {
+ ui32Retcode = USBDGAMEPAD_TX_ERROR;
+ }
+
+ //
+ // Return the relevant error code to the caller.
+ //
+ return(ui32Retcode);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID gamepad device.
+//!
+//! \param psGamepad is the pointer to the device instance structure
+//! as returned by USBDHIDGamepadInit() or USBDHIDGamepadCompositeInit().
+//!
+//! This function terminates HID gamepad operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e psGamepad instance may not me used in any other call to the HID
+//! gamepad device other than to reinitialize by calling USBDHIDGamepadInit()
+//! or USBDHIDGamepadCompositeInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDGamepadTerm(tUSBDHIDGamepadDevice *psGamepad)
+{
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(psGamepad);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psGamepad->sPrivateData.sHIDDevice;
+
+ //
+ // Mark the device as no longer connected.
+ //
+ psGamepad->sPrivateData.iState = eHIDGamepadStateNotConnected;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhidgamepad.h b/usblib/device/usbdhidgamepad.h new file mode 100644 index 0000000..3610680 --- /dev/null +++ b/usblib/device/usbdhidgamepad.h @@ -0,0 +1,274 @@ +//*****************************************************************************
+//
+// usbdhidgame.h - The header information for using the USB libraries game pad
+// device class.
+//
+// Copyright (c) 2013-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.
+//
+//*****************************************************************************
+
+#ifndef __USBDHIDGAME_H__
+#define __USBDHIDGAME_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_gamepad_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the game pad can be in during
+// normal operation. This should not be used by applications and is only
+// here for memory allocation purposes.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Not yet configured.
+ //
+ eHIDGamepadStateNotConnected,
+
+ //
+ // Nothing to transmit and not waiting on data to be sent.
+ //
+ eHIDGamepadStateIdle,
+
+ //
+ // Waiting on data to be sent.
+ //
+ eHIDGamepadStateSending
+}
+tGamepadState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This is the structure for an instance of a USB game pad device. This should
+// not be used by applications and is only here for memory allocation purposes.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+
+ //
+ // The current state of the game pad device.
+ //
+ tGamepadState iState;
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+} tUSBDGamepadInstance;
+
+//*****************************************************************************
+//
+//! This structure is used by the application to define operating parameters
+//! for the HID game device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wake up. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function that is called to notify
+ //! the application of general events. This pointer must point to a valid
+ //! function.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer that is sent as the first parameter in all
+ //! calls made to the pfnCallback gamedevice callback function.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order:
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the \e ppStringDescriptors
+ //! array, which must be (1 + (5 * (number of languages))).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! Optional report descriptor if the application wants to use a custom
+ //! descriptor.
+ //
+ const uint8_t *pui8ReportDescriptor;
+
+ //
+ //! The size of the optional report descriptor define in
+ //! pui8ReportDescriptor.
+ //
+ const uint32_t ui32ReportSize;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! remain accessible for as long as the game device is in use and
+ //! must not be modified by any code outside the HID game device driver.
+ //
+ tUSBDGamepadInstance sPrivateData;
+}
+tUSBDHIDGamepadDevice;
+
+//*****************************************************************************
+//
+//! The USBDHIDGamepadSendReport() call successfully scheduled the report.
+//
+//*****************************************************************************
+#define USBDGAMEPAD_SUCCESS 0
+
+//*****************************************************************************
+//
+//! The USBDHIDGamepadSendReport() function could not send the report at this
+//! time.
+//
+//*****************************************************************************
+#define USBDGAMEPAD_TX_ERROR 1
+
+//*****************************************************************************
+//
+//! The device is not currently configured and cannot perform any operations.
+//
+//*****************************************************************************
+#define USBDGAMEPAD_NOT_CONFIGURED \
+ 2
+
+//*****************************************************************************
+//
+//! This structure is the default packed report structure that is sent to the
+//! host. The application can provide its own structure if the default report
+//! descriptor is overridden by the application. This structure or an
+//! application-defined structure is passed to the USBDHIDGamepadSendReport
+//! function to send gamepad updates to the host.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Signed 8-bit value (-128 to 127).
+ //
+ int8_t i8XPos;
+
+ //
+ //! Signed 8-bit value (-128 to 127).
+ //
+ int8_t i8YPos;
+
+ //
+ //! Signed 8-bit value (-128 to 127).
+ //
+ int8_t i8ZPos;
+
+ //
+ //! 8-bit button mapping with button 1 in the LSB.
+ //
+ uint8_t ui8Buttons;
+}
+PACKED tGamepadReport;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern tUSBDHIDGamepadDevice *USBDHIDGamepadInit(uint32_t ui32Index,
+ tUSBDHIDGamepadDevice *psHIDGamepad);
+extern tUSBDHIDGamepadDevice *USBDHIDGamepadCompositeInit(uint32_t ui32Index,
+ tUSBDHIDGamepadDevice *psHIDGamepad,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDGamepadTerm(tUSBDHIDGamepadDevice *psCompEntry);
+
+extern uint32_t USBDHIDGamepadSendReport(tUSBDHIDGamepadDevice *psHIDGamepad,
+ void *pvReport, uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/device/usbdhidkeyb.c b/usblib/device/usbdhidkeyb.c new file mode 100644 index 0000000..619714c --- /dev/null +++ b/usblib/device/usbdhidkeyb.c @@ -0,0 +1,1321 @@ +//*****************************************************************************
+//
+// usbdhidkeyb.c - USB HID Keyboard device class driver.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/device/usbdhidkeyb.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_keyboard_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8KeybDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(34), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
+{
+ //
+ // HID Device Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_HID, // The interface class
+ USB_HID_SCLASS_BOOT, // The interface sub-class.
+ USB_HID_PROTOCOL_KEYB, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+};
+
+static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+static const uint8_t g_pui8HIDOutEndpoint[HIDOUTENDPOINT_SIZE] =
+{
+ //
+ // Interrupt OUT endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(USB_EP_2),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The following is the HID report structure definition that is passed back
+// to the host.
+//
+//*****************************************************************************
+static const uint8_t g_pui8KeybReportDescriptor[] =
+{
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_KEYBOARD),
+ Collection(USB_HID_APPLICATION),
+
+ //
+ // Modifier keys.
+ // 8 - 1 bit values indicating the modifier keys (ctrl, shift...)
+ //
+ ReportSize(1),
+ ReportCount(8),
+ UsagePage(USB_HID_USAGE_KEYCODES),
+ UsageMinimum(224),
+ UsageMaximum(231),
+ LogicalMinimum(0),
+ LogicalMaximum(1),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS),
+
+ //
+ // One byte of rsvd data required by HID spec.
+ //
+ ReportCount(1),
+ ReportSize(8),
+ Input(USB_HID_INPUT_CONSTANT),
+
+ //
+ // Keyboard LEDs.
+ // 5 - 1 bit values.
+ //
+ ReportCount(5),
+ ReportSize(1),
+ UsagePage(USB_HID_USAGE_LEDS),
+ UsageMinimum(1),
+ UsageMaximum(5),
+ Output(USB_HID_OUTPUT_DATA | USB_HID_OUTPUT_VARIABLE |
+ USB_HID_OUTPUT_ABS),
+ //
+ // 1 - 3 bit value to pad out to a full byte.
+ //
+ ReportCount(1),
+ ReportSize(3),
+ Output(USB_HID_OUTPUT_CONSTANT), //LED report padding
+
+ //
+ // The Key buffer.
+ // 6 - 8 bit values to store the current key state.
+ //
+ ReportCount(6),
+ ReportSize(8),
+ LogicalMinimum(0),
+ LogicalMaximum(101),
+ UsagePage(USB_HID_USAGE_KEYCODES),
+ UsageMinimum (0),
+ UsageMaximum (101),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_ARRAY),
+ EndCollection
+};
+
+//*****************************************************************************
+//
+// The HID descriptor for the keyboard device.
+//
+//*****************************************************************************
+static const tHIDDescriptor g_sKeybHIDDescriptor =
+{
+ 9, // bLength
+ USB_HID_DTYPE_HID, // bDescriptorType
+ 0x111, // bcdHID (version 1.11 compliant)
+ 0, // bCountryCode (not localized)
+ 1, // bNumDescriptors
+ {
+ {
+ USB_HID_DTYPE_REPORT, // Report descriptor
+ sizeof(g_pui8KeybReportDescriptor)
+ // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// The HID configuration descriptor is defined as four or five sections
+// depending upon the client's configuration choice. These sections are:
+//
+// 1. The 9 byte configuration descriptor (RAM).
+// 2. The interface descriptor (RAM).
+// 3. The HID report and physical descriptors (provided by the client)
+// (FLASH).
+// 4. The mandatory interrupt IN endpoint descriptor (FLASH).
+// 5. The optional interrupt OUT endpoint descriptor (FLASH).
+//
+//*****************************************************************************
+static const tConfigSection g_sHIDConfigSection =
+{
+ sizeof(g_pui8KeybDescriptor),
+ g_pui8KeybDescriptor
+};
+
+static const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pui8HIDInterface),
+ g_pui8HIDInterface
+};
+
+static const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pui8HIDInEndpoint),
+ g_pui8HIDInEndpoint
+};
+
+static const tConfigSection g_sHIDOutEndpointSection =
+{
+ sizeof(g_pui8HIDOutEndpoint),
+ g_pui8HIDOutEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+static tConfigSection g_sHIDDescriptorSection =
+{
+ sizeof(g_sKeybHIDDescriptor),
+ (const uint8_t *)&g_sKeybHIDDescriptor
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete HID configuration descriptor.
+//
+//*****************************************************************************
+static const tConfigSection *g_psHIDSections[] =
+{
+ &g_sHIDConfigSection,
+ &g_sHIDInterfaceSection,
+ &g_sHIDDescriptorSection,
+ &g_sHIDInEndpointSection,
+ &g_sHIDOutEndpointSection
+};
+
+#define NUM_HID_SECTIONS ((sizeof(g_psHIDSections) / \
+ sizeof(g_psHIDSections[0])) - 1)
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor. Note that this must be
+// in RAM since we need to include or exclude the final section based on
+// client supplied initialization parameters.
+//
+//*****************************************************************************
+static tConfigHeader g_sHIDConfigHeader =
+{
+ NUM_HID_SECTIONS,
+ g_psHIDSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+static const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the keyboard class, we have only a
+// single report descriptor.
+//
+//*****************************************************************************
+static const uint8_t * const g_pui8KeybClassDescriptors[] =
+{
+ g_pui8KeybReportDescriptor
+};
+
+//*****************************************************************************
+//
+// Forward references for keyboard device callback functions.
+//
+//*****************************************************************************
+static uint32_t HIDKeyboardRxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+static uint32_t HIDKeyboardTxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+
+//*****************************************************************************
+//
+// Main HID device class event handler function.
+//
+// \param pvKeyboardDevice is the event callback pointer provided during
+// USBDHIDInit().This is a pointer to our HID device structure
+// (&g_sHIDKeybDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to operation of the
+// keyboard HID device.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDKeyboardRxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psKeyboardDevice;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psKeyboardDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+ psInst = &psKeyboardDevice->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ psInst->ui8USBConfigured = true;
+
+ //
+ // Pass the information on to the client.
+ //
+ psKeyboardDevice->pfnCallback(psKeyboardDevice->pvCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->ui8USBConfigured = false;
+
+ //
+ // Pass the information on to the client.
+ //
+ psKeyboardDevice->pfnCallback(psKeyboardDevice->pvCBData,
+ USB_EVENT_DISCONNECTED, 0,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // The host is polling us for a particular report and the HID driver
+ // is asking for the latest version to transmit.
+ //
+ case USBD_HID_EVENT_IDLE_TIMEOUT:
+ case USBD_HID_EVENT_GET_REPORT:
+ {
+ //
+ // We only support a single input report so we don't need to check
+ // the ui32MsgValue parameter in this case. Set the report pointer
+ // in *pvMsgData and return the length of the report in bytes.
+ //
+ *(uint8_t **)pvMsgData = psInst->pui8Report;
+ return(KEYB_IN_REPORT_SIZE);
+ }
+
+ //
+ // The device class driver has completed sending a report to the
+ // host in response to a Get_Report request.
+ //
+ case USBD_HID_EVENT_REPORT_SENT:
+ {
+ //
+ // We have nothing to do here.
+ //
+ break;
+ }
+
+ //
+ // This event is sent in response to a host Set_Report request. We
+ // must return a pointer to a buffer large enough to receive the
+ // report into.
+ //
+ case USBD_HID_EVENT_GET_REPORT_BUFFER:
+ {
+ //
+ // Are we being asked for a report that is shorter than the storage
+ // we have set aside for this? The only output report we define is
+ // 8 bits long so we really expect to see a length of 1 passed.
+ //
+ if((uint32_t)pvMsgData == KEYB_OUT_REPORT_SIZE )
+ {
+ //
+ // Yes - return our pointer.
+ //
+ return((uint32_t)psInst->pui8DataBuffer);
+ }
+ else
+ {
+ //
+ // We are being passed a report that is longer than the
+ // only report we expect so return NULL. This causes the
+ // device class driver to stall the request.
+ //
+ return(0);
+ }
+ }
+
+ //
+ // This event indicates that the host has sent us an Output or
+ // Feature report and that the report is now in the buffer we provided
+ // on the previous USBD_HID_EVENT_GET_REPORT_BUFFER callback.
+ //
+ case USBD_HID_EVENT_SET_REPORT:
+ {
+ //
+ // Inform the application if the keyboard LEDs have changed.
+ //
+ if(psInst->ui8LEDStates != psInst->pui8DataBuffer[0])
+ {
+ //
+ // Note the new LED states.
+ //
+ psInst->ui8LEDStates = psInst->pui8DataBuffer[0];
+
+ //
+ // Pass the information on to the client.
+ //
+ psKeyboardDevice->pfnCallback(
+ psKeyboardDevice->pvCBData,
+ USBD_HID_KEYB_EVENT_SET_LEDS,
+ psInst->pui8DataBuffer[0],
+ (void *)0);
+ }
+ break;
+ }
+
+ //
+ // The host is asking us to set either boot or report protocol (not
+ // that it makes any difference to this particular mouse).
+ //
+ case USBD_HID_EVENT_SET_PROTOCOL:
+ {
+ psInst->ui8Protocol = ui32MsgData;
+ break;
+ }
+
+ //
+ // The host is asking us to tell it which protocol we are currently
+ // using, boot or request.
+ //
+ case USBD_HID_EVENT_GET_PROTOCOL:
+ {
+ return(psInst->ui8Protocol);
+ }
+
+ //
+ // Pass ERROR, SUSPEND and RESUME to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ case USB_EVENT_LPM_RESUME:
+ case USB_EVENT_LPM_SLEEP:
+ case USB_EVENT_LPM_ERROR:
+ {
+ return(psKeyboardDevice->pfnCallback(
+ psKeyboardDevice->pvCBData,
+ ui32Event, ui32MsgData, pvMsgData));
+ }
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// HID device class transmit channel event handler function.
+//
+// \param pvKeyboardDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to our HID device structure
+// (&g_sHIDKeybDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to report
+// transmissions made using the interrupt IN endpoint.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDKeyboardTxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+ uint32_t ui32Count;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+ psInst = &psHIDKbDevice->sPrivateData;
+ psHIDDevice = &psInst->sHIDDevice;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // Do we have any pending changes needing transmitted?
+ //
+ if(psInst->bChangeMade)
+ {
+ //
+ // Yes - go ahead and send another report immediately.
+ //
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pui8Report,
+ KEYB_IN_REPORT_SIZE, true);
+
+ //
+ // If we scheduled the report for transmission, clear the
+ // change flag.
+ //
+ if(ui32Count != 0)
+ {
+ psInst->bChangeMade = false;
+ }
+ }
+ else
+ {
+ //
+ // Our last transmission is complete and we have nothing more
+ // to send.
+ //
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_IDLE;
+ }
+
+ //
+ // Pass the event on to the client.
+ //
+ psHIDKbDevice->pfnCallback(psHIDKbDevice->pvCBData,
+ USB_EVENT_TX_COMPLETE, ui32MsgData,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // We ignore all other events related to transmission of reports via
+ // the interrupt IN endpoint.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Add the supplied usage code to the list of keys currently in the pressed
+// state.
+//
+// \param ui8UsageCode is the HID usage code of the newly pressed key.
+//
+// This function adds the supplied usage code to the global list of keys which
+// are currently pressed (assuming it is not already noted as pressed and that
+// there is space in the list to hold the new information). The return code
+// indicates success if the list did not overflow and failure if the list
+// already contains as many pressed keys as can be reported.
+//
+// \return Returns \b true if the usage code was successfully added to the
+// list or \b false if there was insufficient space to hold the new key
+// press (in which case the caller should report a roll over error to the
+// host).
+//
+//*****************************************************************************
+static bool
+AddKeyToPressedList(tHIDKeyboardInstance *psInst, uint8_t ui8UsageCode)
+{
+ uint32_t ui32Loop;
+ bool bRetcode;
+
+ //
+ // Assume all is well until we determine otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Look through the list of existing pressed keys to see if the new one
+ // is already there.
+ //
+ for(ui32Loop = 0; ui32Loop < (uint32_t)psInst->ui8KeyCount; ui32Loop++)
+ {
+ //
+ // Is this key already included in the list of keys in the pressed
+ // state?
+ //
+ if(ui8UsageCode == psInst->pui8KeysPressed[ui32Loop])
+ {
+ //
+ // Yes - drop out.
+ //
+ break;
+ }
+ }
+
+ //
+ // If we exited the loop at the end of the existing key presses, this
+ // key does not exist already so add it if space exists.
+ //
+ if(ui32Loop >= psInst->ui8KeyCount)
+ {
+ if(psInst->ui8KeyCount < KEYB_MAX_CHARS_PER_REPORT)
+ {
+ //
+ // We have room so store the new key press in the list.
+ //
+ psInst->pui8KeysPressed[psInst->ui8KeyCount] = ui8UsageCode;
+ psInst->ui8KeyCount++;
+ bRetcode = true;
+ }
+ else
+ {
+ //
+ // We have no room for the new key - declare a rollover error.
+ //
+ bRetcode = false;
+ }
+ }
+
+ return(bRetcode);
+}
+
+//*****************************************************************************
+//
+// Remove the supplied usage code from the list of keys currently in the
+// pressed state.
+//
+// \param ui8UsageCode is the HID usage code of the newly released key.
+//
+// This function removes the supplied usage code from the global list of keys
+// which are currently pressed. The return code indicates whether the key was
+// found in the list. On exit, the list has been cleaned up to ensure
+// that all key presses are contiguous starting at the first entry.
+//
+// \return Returns \b true if the usage code was found and removed from the
+// list or \b false if the code was not found. The caller need not pass a new
+// report to the host if \b false is returned since the key list has not
+// changed.
+//
+//*****************************************************************************
+static bool
+RemoveKeyFromPressedList(tHIDKeyboardInstance *psInst,
+ uint8_t ui8UsageCode)
+{
+ uint32_t ui32Loop;
+ uint32_t ui32Pos;
+
+ //
+ // Keep the compiler happy by setting ui32Pos to something.
+ //
+ ui32Pos = 0;
+
+ //
+ // Find the usage code in the current list.
+ //
+ for(ui32Loop = 0; ui32Loop < KEYB_MAX_CHARS_PER_REPORT; ui32Loop++)
+ {
+ if(psInst->pui8KeysPressed[ui32Loop] == ui8UsageCode)
+ {
+ ui32Pos = ui32Loop;
+ break;
+ }
+ }
+
+ //
+ // If we dropped out at the end of the loop, we could not find the code so
+ // just return false.
+ //
+ if(ui32Loop == KEYB_MAX_CHARS_PER_REPORT)
+ {
+ return(false);
+ }
+
+ //
+ // Now shuffle all the values to the right of the usage code we found
+ // down one position to fill the gap left by removing it.
+ //
+ for(ui32Loop = (ui32Pos + 1); ui32Loop < KEYB_MAX_CHARS_PER_REPORT;
+ ui32Loop++)
+ {
+ psInst->pui8KeysPressed[ui32Loop - 1] =
+ psInst->pui8KeysPressed[ui32Loop];
+ }
+
+ //
+ // Clear the last entry in the array and adjust the number of keys in the
+ // array.
+ //
+ psInst->pui8KeysPressed[KEYB_MAX_CHARS_PER_REPORT - 1] =
+ HID_KEYB_USAGE_RESERVED;
+ psInst->ui8KeyCount--;
+
+ //
+ // Tell the caller we were successful.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID keyboard device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID keyboard device operation.
+//! \param psHIDKbDevice points to a structure containing parameters
+//! customizing the operation of the HID keyboard device.
+//!
+//! An application wishing to offer a USB HID keyboard interface to a USB host
+//! must call this function to initialize the USB controller and attach the
+//! keyboard device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function returns the \e psHIDKbDevice
+//! pointer passed to it. This must be passed on all future calls to the HID
+//! keyboard device driver.
+//!
+//! When a host connects and configures the device, the application callback
+//! receives \b USB_EVENT_CONNECTED after which calls can be made to
+//! USBDHIDKeyboardKeyStateChange() to report key presses and releases to the
+//! USB host.
+//!
+//! \note The application must not make any calls to the lower level USB device
+//! interfaces if interacting with USB via the USB HID keyboard device class
+//! API. Doing so causes unpredictable (though almost certainly
+//! unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the \e psHIDKbDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardInit(uint32_t ui32Index, tUSBDHIDKeyboardDevice *psHIDKbDevice)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+ tConfigDescriptor *pConfigDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psHIDKbDevice);
+ ASSERT(psHIDKbDevice->ppui8StringDescriptors);
+ ASSERT(psHIDKbDevice->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDKeyboardCompositeInit(ui32Index, psHIDKbDevice, 0);
+
+ pConfigDesc = (tConfigDescriptor *)g_pui8KeybDescriptor;
+ pConfigDesc->bmAttributes = psHIDKbDevice->ui8PwrAttributes;
+ pConfigDesc->bMaxPower = (uint8_t)(psHIDKbDevice->ui16MaxPowermA / 2);
+
+ //
+ // If we initialized the HID layer successfully, pass our device pointer
+ // back as the return code, otherwise return NULL to indicate an error.
+ //
+ if(pvRetcode)
+ {
+ //
+ // Initialize the lower layer HID driver and pass it the various
+ // structures and descriptors necessary to declare that we are a
+ // keyboard.
+ //
+ pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
+
+ return((void *)psHIDKbDevice);
+ }
+ else
+ {
+ return((void *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID keyboard device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID keyboard device operation.
+//! \param psHIDKbDevice points to a structure containing parameters
+//! customizing the operation of the HID keyboard device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDHIDKeyboardInit() except that it is used
+//! for initializing an instance of the HID keyboard device for use in a
+//! composite device. If this HID keyboard is part of a composite device, then
+//! the \e psCompEntry should point to the composite device entry to
+//! initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID Keyboard APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardCompositeInit(uint32_t ui32Index,
+ tUSBDHIDKeyboardDevice *psHIDKbDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tHIDKeyboardInstance *psInst;
+ uint32_t ui32Loop;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psHIDKbDevice);
+ ASSERT(psHIDKbDevice->ppui8StringDescriptors);
+ ASSERT(psHIDKbDevice->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psHIDKbDevice->sPrivateData;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->ui8USBConfigured = 0;
+ psInst->ui8Protocol = USB_HID_PROTOCOL_REPORT;
+ psInst->sReportIdle.ui8Duration4mS = 125;
+ psInst->sReportIdle.ui8ReportID = 0;
+ psInst->sReportIdle.ui32TimeSinceReportmS = 0;
+ psInst->sReportIdle.ui16TimeTillNextmS = 0;
+ psInst->ui8LEDStates = 0;
+ psInst->ui8KeyCount = 0;
+ for(ui32Loop = 0; ui32Loop < KEYB_MAX_CHARS_PER_REPORT; ui32Loop++)
+ {
+ psInst->pui8KeysPressed[ui32Loop] = HID_KEYB_USAGE_RESERVED;
+ }
+
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_UNCONFIGURED;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psInst->sHIDDevice;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->ui16PID = psHIDKbDevice->ui16PID;
+ psHIDDevice->ui16VID = psHIDKbDevice->ui16VID;
+ psHIDDevice->ui16MaxPowermA = psHIDKbDevice->ui16MaxPowermA;
+ psHIDDevice->ui8PwrAttributes = psHIDKbDevice->ui8PwrAttributes;
+ psHIDDevice->ui8Subclass = USB_HID_SCLASS_BOOT;
+ psHIDDevice->ui8Protocol = USB_HID_PROTOCOL_KEYB;
+ psHIDDevice->ui8NumInputReports = 1;
+ psHIDDevice->psReportIdle = 0;
+ psHIDDevice->pfnRxCallback = HIDKeyboardRxHandler;
+ psHIDDevice->pvRxCBData = (void *)psHIDKbDevice;
+ psHIDDevice->pfnTxCallback = HIDKeyboardTxHandler;
+ psHIDDevice->pvTxCBData = (void *)psHIDKbDevice;
+ psHIDDevice->bUseOutEndpoint = false,
+
+ psHIDDevice->psHIDDescriptor = &g_sKeybHIDDescriptor;
+ psHIDDevice->ppui8ClassDescriptors = g_pui8KeybClassDescriptors;
+ psHIDDevice->ppui8StringDescriptors =
+ psHIDKbDevice->ppui8StringDescriptors;
+ psHIDDevice->ui32NumStringDescriptors =
+ psHIDKbDevice->ui32NumStringDescriptors;
+ psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
+
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a keyboard.
+ //
+ return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID keyboard device.
+//!
+//! \param pvKeyboardDevice is the pointer to the device instance structure
+//! as returned by USBDHIDKeyboardInit().
+//!
+//! This function terminates HID keyboard operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e pvKeyboardDevice instance may not me used in any other call to the HID
+//! keyboard device other than USBDHIDKeyboardInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDKeyboardTerm(void *pvKeyboardDevice)
+{
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to the device.
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Mark the device as no longer configured.
+ //
+ psHIDKbDevice->sPrivateData.ui8USBConfigured = 0;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the keyboard callback.
+//!
+//! \param pvKeyboardDevice is the pointer to the device instance structure
+//! as returned by USBDHIDKeyboardInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the keyboard callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnCallback function
+//! passed on USBDHIDKeyboardInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the \e pvKeyboardDevice structure passed to
+//! USBDHIDKeyboardInit() resides in RAM. If this structure is in flash,
+//! callback data changes is not possible.
+//!
+//! \return Returns the previous callback pointer that was set for this
+//! instance.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardSetCBData(void *pvKeyboardDevice, void *pvCBData)
+{
+ void *pvOldCBData;
+ tUSBDHIDKeyboardDevice *psKeyboard;
+
+ //
+ // Check for a NULL pointer in the device parameter.
+ //
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to our keyboard device.
+ //
+ psKeyboard = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Save the old callback pointer and replace it with the new value.
+ //
+ pvOldCBData = psKeyboard->pvCBData;
+ psKeyboard->pvCBData = pvCBData;
+
+ //
+ // Pass the old callback pointer back to the caller.
+ //
+ return(pvOldCBData);
+}
+
+//*****************************************************************************
+//
+//! Reports a key state change to the USB host.
+//!
+//! \param pvKeyboardDevice is the pointer to the device instance structure
+//! as returned by USBDHIDKeyboardInit().
+//! \param ui8Modifiers contains the states of each of the keyboard modifiers
+//! (left/right shift, ctrl, alt or GUI keys). Valid values are logical OR
+//! combinations of the labels \b HID_KEYB_LEFT_CTRL, \b HID_KEYB_LEFT_SHIFT,
+//! \b HID_KEYB_LEFT_ALT, \b HID_KEYB_LEFT_GUI, \b HID_KEYB_RIGHT_CTRL, \b
+//! HID_KEYB_RIGHT_SHIFT, \b HID_KEYB_RIGHT_ALT and \b HID_KEYB_RIGHT_GUI.
+//! Presence of one of these bit flags indicates that the relevant modifier
+//! key is pressed and absence indicates that it is released.
+//! \param ui8UsageCode is the usage code of the key whose state has changed.
+//! If only modifier keys have changed, \b HID_KEYB_USAGE_RESERVED should be
+//! passed in this parameter.
+//! \param bPress is \b true if the key has been pressed or \b false if it has
+//! been released. If only modifier keys have changed state, this parameter is
+//! ignored.
+//!
+//! This function adds or removes a key usage code from the list of keys
+//! currently pressed and schedules a report transmission to the host to
+//! inform it of the new keyboard state. If the maximum number of simultaneous
+//! key presses are already recorded, the report to the host contains the
+//! rollover error code, \b HID_KEYB_USAGE_ROLLOVER instead of key usage codes
+//! and the caller receives return code \b KEYB_ERR_TOO_MANY_KEYS.
+//!
+//! \return Returns \b KEYB_SUCCESS if the key usage code was added to or
+//! removed from the current list successfully. \b KEYB_ERR_TOO_MANY_KEYS is
+//! returned if an attempt is made to press a 7th key (the BIOS keyboard
+//! protocol can report no more than 6 simultaneously pressed keys). If called
+//! before the USB host has configured the device, \b KEYB_ERR_NOT_CONFIGURED
+//! is returned and, if an error is reported while attempting to transmit the
+//! report, \b KEYB_ERR_TX_ERROR is returned. If an attempt is made to remove
+//! a key from the pressed list (by setting parameter \e bPressed to \b false)
+//! but the key usage code is not found, \b KEYB_ERR_NOT_FOUND is returned.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDKeyboardKeyStateChange(void *pvKeyboardDevice, uint8_t ui8Modifiers,
+ uint8_t ui8UsageCode, bool bPress)
+{
+ bool bRetcode;
+ uint32_t ui32Loop, ui32Count;
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Assume all is well until we determine otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psHIDKbDevice->sPrivateData;
+
+ //
+ // Update the global keyboard report with the information passed.
+ //
+ psInst->pui8Report[0] = ui8Modifiers;
+ psInst->pui8Report[1] = 0;
+
+ //
+ // Were we passed a usage code for a new key press or release or was
+ // this call just telling us about a modifier change?
+ //
+ if(ui8UsageCode != HID_KEYB_USAGE_RESERVED)
+ {
+ //
+ // Has a key been pressed or released?
+ //
+ if(bPress)
+ {
+ //
+ // A key has been pressed - add it to the list if there is space an
+ // and the key is not already in the list.
+ //
+ bRetcode = AddKeyToPressedList(psInst, ui8UsageCode);
+ }
+ else
+ {
+ //
+ // A key has been released - remove it from the list.
+ //
+ bRetcode = RemoveKeyFromPressedList(psInst, ui8UsageCode);
+
+ //
+ // The return code here indicates whether the key was found. If it
+ // wasn't, the list has not changes so merely exit at this point
+ // without sending anything to the host.
+ //
+ if(!bRetcode)
+ {
+ return(KEYB_ERR_NOT_FOUND);
+ }
+ }
+
+ //
+ // Build the report from the current list of keys. If we added a key
+ // and got a bad return code indicating a roll over error, we need to
+ // send a roll over report
+ //
+ for(ui32Loop = 0; ui32Loop < KEYB_MAX_CHARS_PER_REPORT; ui32Loop++)
+ {
+ psInst->pui8Report[2 + ui32Loop] = (bRetcode ?
+ psInst->pui8KeysPressed[ui32Loop] : HID_KEYB_USAGE_ROLLOVER);
+ }
+ }
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(!psInst->ui8USBConfigured)
+ {
+ return(KEYB_ERR_NOT_CONFIGURED);
+ }
+
+ //
+ // Only send a report if the transmitter is currently free.
+ //
+ if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
+ {
+ //
+ // Send the report to the host.
+ //
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_SEND;
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pui8Report, KEYB_IN_REPORT_SIZE,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(!ui32Count)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ return(KEYB_ERR_TX_ERROR);
+ }
+ }
+ else
+ {
+ //
+ // We can't send the report immediately so mark the instance so that
+ // it is sent next time the transmitter is free.
+ //
+ psInst->bChangeMade = true;
+ }
+
+ //
+ // If we get this far, the key information was sent successfully. Are
+ // too many keys currently pressed, though?
+ //
+ return(bRetcode ? KEYB_SUCCESS : KEYB_ERR_TOO_MANY_KEYS);
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus or self powered) to the USB library.
+//!
+//! \param pvKeyboardDevice is the pointer to the keyboard device instance
+//! structure.
+//! \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 USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDKeyboardPowerStatusSet(void *pvKeyboardDevice, uint8_t ui8Power)
+{
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDHIDPowerStatusSet((void *)psHIDDevice, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvKeyboardDevice is the pointer to the keyboard device instance
+//! structure.
+//!
+//! 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 causes the bus
+//! to resume operation within 20mS. 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 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
+USBDHIDKeyboardRemoteWakeupRequest(void *pvKeyboardDevice)
+{
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDHIDRemoteWakeupRequest((void *)psHIDDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhidkeyb.h b/usblib/device/usbdhidkeyb.h new file mode 100644 index 0000000..c509b9f --- /dev/null +++ b/usblib/device/usbdhidkeyb.h @@ -0,0 +1,365 @@ +//*****************************************************************************
+//
+// usbdhidkeyb.h - Definitions used by HID keyboard class devices.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHIDKEYB_H__
+#define __USBDHIDKEYB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_keyboard_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The maximum number of simultaneously-pressed, non-modifier keys that the
+//! HID BIOS keyboard protocol can send at once. Attempts to send more pressed
+//! keys than this results in a rollover error being reported to the host
+//! and KEYB_ERR_TOO_MANY_KEYS being returned from
+//! USBDHIDKeyboardKeyStateChange().
+//
+//*****************************************************************************
+#define KEYB_MAX_CHARS_PER_REPORT \
+ 6
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB HID keyboard code and are here only to help with the application
+// allocating the correct amount of memory for the USB HID Keyboard device
+// code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the keyboard can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ HID_KEYBOARD_STATE_UNCONFIGURED,
+
+ //
+ // No keys to send and not waiting on data.
+ //
+ HID_KEYBOARD_STATE_IDLE,
+
+ //
+ // Waiting on report data from the host.
+ //
+ HID_KEYBOARD_STATE_WAIT_DATA,
+
+ //
+ // Waiting on data to be sent out.
+ //
+ HID_KEYBOARD_STATE_SEND
+}
+tKeyboardState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The size of the keyboard input and output reports.
+//
+//*****************************************************************************
+#define KEYB_IN_REPORT_SIZE 8
+#define KEYB_OUT_REPORT_SIZE 1
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data structure for the USB HID
+// keyboard device. This structure forms the RAM workspace used by each
+// instance of the keyboard.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The USB configuration number set by the host or 0 of the device is
+ // currently unconfigured.
+ //
+ uint8_t ui8USBConfigured;
+
+ //
+ // The protocol requested by the host, USB_HID_PROTOCOL_BOOT or
+ // USB_HID_PROTOCOL_REPORT.
+ //
+ uint8_t ui8Protocol;
+
+ //
+ // The current states that the keyboard LEDs are to be set to.
+ //
+ volatile uint8_t ui8LEDStates;
+
+ //
+ // The total number of keys currently pressed. This indicates the number
+ // of key press entries in the pui8KeysPressed array.
+ //
+ uint8_t ui8KeyCount;
+
+ //
+ // The current state of the keyboard interrupt IN endpoint.
+ //
+ volatile tKeyboardState eKeyboardState;
+
+ //
+ // A flag to indicate that the application pressed or released a key
+ // but that we couldn't send the report immediately.
+ //
+ volatile bool bChangeMade;
+
+ //
+ // A buffer used to receive output reports from the host.
+ //
+ uint8_t pui8DataBuffer[KEYB_OUT_REPORT_SIZE];
+
+ //
+ // A buffer used to hold the last input report sent to the host.
+ //
+ uint8_t pui8Report[KEYB_IN_REPORT_SIZE];
+
+ //
+ // A buffer containing the usage codes of all non-modifier keys currently
+ // in the pressed state.
+ //
+ uint8_t pui8KeysPressed[KEYB_MAX_CHARS_PER_REPORT];
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+}
+tHIDKeyboardInstance;
+
+//*****************************************************************************
+//
+//! This structure is used by the application to define operating parameters
+//! for the HID keyboard device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //! A pointer to the callback function which is called to notify
+ //! the application of general events and those related to reception of
+ //! Output and Feature reports via the (optional) interrupt OUT endpoint.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the keyboard callback,
+ //! pfnCallback.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be (1 + (5 * (num languages))).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! remain accessible for as long as the keyboard device is in use and
+ //! must not be modified by any code outside the HID keyboard driver.
+ //
+ tHIDKeyboardInstance sPrivateData;
+}
+tUSBDHIDKeyboardDevice;
+
+//*****************************************************************************
+//
+// Keyboard-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the keyboard LED states are to be set. The
+//! ui32MsgValue parameter contains the requested state for each of the LEDs
+//! defined as a collection of ORed bits where a 1 indicates that the LED is
+//! to be turned on and a 0 indicates that it should be turned off. The
+//! individual LED bits are defined using labels \b HID_KEYB_NUM_LOCK,
+//! \b HID_KEYB_CAPS_LOCK, \b HID_KEYB_SCROLL_LOCK, \b HID_KEYB_COMPOSE and
+//! \b HID_KEYB_KANA.
+//
+//*****************************************************************************
+#define USBD_HID_KEYB_EVENT_SET_LEDS \
+ USBD_HID_KEYB_EVENT_BASE
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDKeyboardKeyStateChange() indicates success.
+//
+//*****************************************************************************
+#define KEYB_SUCCESS 0
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDKeyboardKeyStateChange() indicates that an
+//! attempt has been made to record more than 6 simultaneously pressed,
+//! non-modifier keys. The USB HID BIOS keyboard protocol allows no more than
+//! 6 pressed keys to be reported at one time. Until at least one key is
+//! released, the device reports a roll over error to the host each time it
+//! is asked for the keyboard input report.
+//
+//*****************************************************************************
+#define KEYB_ERR_TOO_MANY_KEYS 1
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDKeyboardKeyStateChange() indicates that an
+//! error was reported while attempting to send a report to the host. A client
+//! should assume that the host has disconnected if this return code is seen.
+//
+//*****************************************************************************
+#define KEYB_ERR_TX_ERROR 2
+
+//*****************************************************************************
+//
+//! USBDHIDKeyboardKeyStateChange() returns this value if it is called with the
+//! bPress parameter set to false but with a ui8UsageCode parameter which does
+//! does not indicate a key that is currently recorded as being pressed. This
+//! may occur if an attempt was previously made to report more than 6 pressed
+//! keys and the earlier pressed keys are released before the later ones. This
+//! condition is benign and should not be used to indicate a host disconnection
+//! or serious error.
+//
+//*****************************************************************************
+#define KEYB_ERR_NOT_FOUND 3
+
+//*****************************************************************************
+//
+//! USBDHIDKeyboardKeyStateChange() returns this value if it is called before
+//! the USB host has connected and configured the device. Any key usage code
+//! passed is stored and passed to the host once configuration completes.
+//
+//*****************************************************************************
+#define KEYB_ERR_NOT_CONFIGURED 4
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDKeyboardInit(uint32_t ui32Index,
+ tUSBDHIDKeyboardDevice *psHIDKbDevice);
+extern void *USBDHIDKeyboardCompositeInit(uint32_t ui32Index,
+ tUSBDHIDKeyboardDevice *psHIDKbDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDKeyboardTerm(void *pvKeyboardInstance);
+extern void *USBDHIDKeyboardSetCBData(void *pvKeyboardInstance,
+ void *pvCBData);
+extern uint32_t USBDHIDKeyboardKeyStateChange(void *pvKeyboardInstance,
+ uint8_t ui8Modifiers,
+ uint8_t ui8UsageCode,
+ bool bPressed);
+extern void USBDHIDKeyboardPowerStatusSet(void *pvKeyboardInstance,
+ uint8_t ui8Power);
+extern bool USBDHIDKeyboardRemoteWakeupRequest(void *pvKeyboardInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHIDKEYB_H__
diff --git a/usblib/device/usbdhidmouse.c b/usblib/device/usbdhidmouse.c new file mode 100644 index 0000000..8b8a95a --- /dev/null +++ b/usblib/device/usbdhidmouse.c @@ -0,0 +1,1008 @@ +//*****************************************************************************
+//
+// usbdhidmouse.c - USB HID Mouse device class driver.
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/device/usbdhidmouse.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_mouse_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8MouseDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(34), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
+{
+ //
+ // HID Device Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_HID, // The interface class
+ USB_HID_SCLASS_BOOT, // The interface sub-class.
+ USB_HID_PROTOCOL_MOUSE, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+};
+
+const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The report descriptor for the mouse class device.
+//
+//*****************************************************************************
+static const uint8_t g_pui8MouseReportDescriptor[] =
+{
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_MOUSE),
+ Collection(USB_HID_APPLICATION),
+ Usage(USB_HID_POINTER),
+ Collection(USB_HID_PHYSICAL),
+
+ //
+ // The buttons.
+ //
+ UsagePage(USB_HID_BUTTONS),
+ UsageMinimum(1),
+ UsageMaximum(3),
+ LogicalMinimum(0),
+ LogicalMaximum(1),
+
+ //
+ // 3 - 1 bit values for the buttons.
+ //
+ ReportSize(1),
+ ReportCount(3),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_ABS),
+
+ //
+ // 1 - 5 bit unused constant value to fill the 8 bits.
+ //
+ ReportSize(5),
+ ReportCount(1),
+ Input(USB_HID_INPUT_CONSTANT | USB_HID_INPUT_ARRAY |
+ USB_HID_INPUT_ABS),
+
+ //
+ // The X and Y axis.
+ //
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_X),
+ Usage(USB_HID_Y),
+ LogicalMinimum(-127),
+ LogicalMaximum(127),
+
+ //
+ // 2 - 8 bit Values for x and y.
+ //
+ ReportSize(8),
+ ReportCount(2),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_RELATIVE),
+
+ EndCollection,
+ EndCollection,
+};
+
+//*****************************************************************************
+//
+// The HID descriptor for the mouse device.
+//
+//*****************************************************************************
+static const tHIDDescriptor g_sMouseHIDDescriptor =
+{
+ 9, // bLength
+ USB_HID_DTYPE_HID, // bDescriptorType
+ 0x111, // bcdHID (version 1.11 compliant)
+ 0, // bCountryCode (not localized)
+ 1, // bNumDescriptors
+ {
+ {
+ USB_HID_DTYPE_REPORT, // Report descriptor
+ sizeof(g_pui8MouseReportDescriptor)
+ // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// The HID configuration descriptor is defined as four or five sections
+// depending upon the client's configuration choice. These sections are:
+//
+// 1. The 9 byte configuration descriptor (RAM).
+// 2. The interface descriptor (RAM).
+// 3. The HID report and physical descriptors (provided by the client)
+// (FLASH).
+// 4. The mandatory interrupt IN endpoint descriptor (FLASH).
+// 5. The optional interrupt OUT endpoint descriptor (FLASH).
+//
+//*****************************************************************************
+const tConfigSection g_sHIDConfigSection =
+{
+ sizeof(g_pui8MouseDescriptor),
+ g_pui8MouseDescriptor
+};
+
+const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pui8HIDInterface),
+ g_pui8HIDInterface
+};
+
+const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pui8HIDInEndpoint),
+ g_pui8HIDInEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+tConfigSection g_sHIDDescriptorSection =
+{
+ sizeof(g_sMouseHIDDescriptor),
+ (const uint8_t *)&g_sMouseHIDDescriptor
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete HID configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psHIDSections[] =
+{
+ &g_sHIDConfigSection,
+ &g_sHIDInterfaceSection,
+ &g_sHIDDescriptorSection,
+ &g_sHIDInEndpointSection,
+};
+
+#define NUM_HID_SECTIONS (sizeof(g_psHIDSections) / \
+ sizeof(g_psHIDSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor. Note that this must be
+// in RAM since we need to include or exclude the final section based on
+// client supplied initialization parameters.
+//
+//*****************************************************************************
+tConfigHeader g_sHIDConfigHeader =
+{
+ NUM_HID_SECTIONS,
+ g_psHIDSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the mouse class, we have only a single
+// report descriptor.
+//
+//*****************************************************************************
+static const uint8_t * const g_pui8MouseClassDescriptors[] =
+{
+ g_pui8MouseReportDescriptor
+};
+
+//*****************************************************************************
+//
+// Forward references for mouse device callback functions.
+//
+//*****************************************************************************
+static uint32_t HIDMouseRxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+static uint32_t HIDMouseTxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+
+//*****************************************************************************
+//
+// The HID mouse report offsets for this mouse application.
+//
+//*****************************************************************************
+#define HID_REPORT_BUTTONS 0
+#define HID_REPORT_X 1
+#define HID_REPORT_Y 2
+
+//*****************************************************************************
+//
+// Main HID device class event handler function.
+//
+// \param pvMouseDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to our HID device structure
+// (&g_sHIDMouseDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to operation of the
+// mouse HID device.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDMouseRxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psMouseDevice;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch(ui32Event)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ psInst->ui8USBConfigured = true;
+
+ //
+ // Pass the information on to the client.
+ //
+ psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->ui8USBConfigured = false;
+
+ //
+ // Pass the information on to the client.
+ //
+ psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host is polling us for a particular report and the HID driver
+ // is asking for the latest version to transmit.
+ //
+ case USBD_HID_EVENT_IDLE_TIMEOUT:
+ case USBD_HID_EVENT_GET_REPORT:
+ {
+ //
+ // We only support a single input report so we don't need to check
+ // the ui32MsgValue parameter in this case. Set the report pointer
+ // in *pvMsgData and return the length of the report in bytes.
+ //
+ *(uint8_t **)pvMsgData = psInst->pui8Report;
+ return(8);
+ }
+
+ //
+ // The device class driver has completed sending a report to the
+ // host in response to a Get_Report request.
+ //
+ case USBD_HID_EVENT_REPORT_SENT:
+ {
+ //
+ // We have nothing to do here.
+ //
+ break;
+ }
+
+ //
+ // This event is sent in response to a host Set_Report request. The
+ // mouse device has no output reports so we return a NULL pointer and
+ // zero length to cause this request to be stalled.
+ //
+ case USBD_HID_EVENT_GET_REPORT_BUFFER:
+ {
+ //
+ // We are being asked for a report that does not exist for
+ // this device. Return 0 to indicate that we are not providing
+ // a buffer.
+ //
+ return(0);
+ }
+
+ //
+ // The host is asking us to set either boot or report protocol (not
+ // that it makes any difference to this particular mouse).
+ //
+ case USBD_HID_EVENT_SET_PROTOCOL:
+ {
+ psInst->ui8Protocol = ui32MsgData;
+ break;
+ }
+
+ //
+ // The host is asking us to tell it which protocol we are currently
+ // using, boot or request.
+ //
+ case USBD_HID_EVENT_GET_PROTOCOL:
+ {
+ return(psInst->ui8Protocol);
+ }
+
+ //
+ // Pass ERROR, SUSPEND and RESUME to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ case USB_EVENT_LPM_RESUME:
+ case USB_EVENT_LPM_SLEEP:
+ case USB_EVENT_LPM_ERROR:
+ {
+ return(psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ ui32Event, ui32MsgData,
+ pvMsgData));
+ }
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// HID device class transmit channel event handler function.
+//
+// \param pvMouseDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to our HID device structure
+// (&g_sHIDMouseDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to report
+// transmissions made using the interrupt IN endpoint.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDMouseTxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psMouseDevice;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // Our last transmission is complete.
+ //
+ psInst->iMouseState = eHIDMouseStateIdle;
+
+ //
+ // Pass the event on to the client.
+ //
+ psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ USB_EVENT_TX_COMPLETE, ui32MsgData,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // We ignore all other events related to transmission of reports via
+ // the interrupt IN endpoint.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID mouse device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID mouse device operation.
+//! \param psMouseDevice points to a structure containing parameters
+//! customizing the operation of the HID mouse device.
+//!
+//! An application wishing to offer a USB HID mouse interface to a USB host
+//! must call this function to initialize the USB controller and attach the
+//! mouse device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function returns the \e psMouseDevice
+//! pointer passed to it. This must be passed on all future calls to the HID
+//! mouse device driver.
+//!
+//! When a host connects and configures the device, the application callback
+//! receives \b USB_EVENT_CONNECTED after which calls can be made to
+//! USBDHIDMouseStateChange() to report pointer movement and button presses
+//! to the host.
+//!
+//! \note The application must not make any calls to the lower level USB device
+//! interfaces if interacting with USB via the USB HID mouse device API.
+//! Doing so causes unpredictable (though almost certainly unpleasant)
+//! behavior.
+//!
+//! \return Returns NULL on failure or the psMouseDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseInit(uint32_t ui32Index, tUSBDHIDMouseDevice *psMouseDevice)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+ tConfigDescriptor *pConfigDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psMouseDevice);
+ ASSERT(psMouseDevice->ppui8StringDescriptors);
+ ASSERT(psMouseDevice->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ pConfigDesc = (tConfigDescriptor *)g_pui8MouseDescriptor;
+ pConfigDesc->bmAttributes = psMouseDevice->ui8PwrAttributes;
+ pConfigDesc->bMaxPower = (uint8_t)(psMouseDevice->ui16MaxPowermA / 2);
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDMouseCompositeInit(ui32Index, psMouseDevice, 0);
+
+ //
+ // If we initialized the HID layer successfully, pass our device pointer
+ // back as the return code, otherwise return NULL to indicate an error.
+ //
+ if(pvRetcode)
+ {
+ //
+ // Initialize the lower layer HID driver and pass it the various
+ // structures and descriptors necessary to declare that we are a
+ // keyboard.
+ //
+ pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
+
+ return((void *)psMouseDevice);
+ }
+ else
+ {
+ return((void *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID mouse device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID mouse device operation.
+//! \param psMouseDevice points to a structure containing parameters
+//! customizing the operation of the HID mouse device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDHIDMouseInit() except that it is used for
+//! initializing an instance of the HID mouse device for use in a composite
+//! device. If this HID mouse is part of a composite device, then the
+//! \e psCompEntry should point to the composite device entry to initialize.
+//! This is part of the array that is passed to the USBDCompositeInit()
+//! function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID Mouse APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseCompositeInit(uint32_t ui32Index,
+ tUSBDHIDMouseDevice *psMouseDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psMouseDevice);
+ ASSERT(psMouseDevice->ppui8StringDescriptors);
+ ASSERT(psMouseDevice->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->ui8USBConfigured = 0;
+ psInst->ui8Protocol = USB_HID_PROTOCOL_REPORT;
+ psInst->sReportIdle.ui8Duration4mS = 0;
+ psInst->sReportIdle.ui8ReportID = 0;
+ psInst->sReportIdle.ui32TimeSinceReportmS = 0;
+ psInst->sReportIdle.ui16TimeTillNextmS = 0;
+ psInst->iMouseState = eHIDMouseStateUnconfigured;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->ui16PID = psMouseDevice->ui16PID;
+ psHIDDevice->ui16VID = psMouseDevice->ui16VID;
+ psHIDDevice->ui16MaxPowermA = psMouseDevice->ui16MaxPowermA;
+ psHIDDevice->ui8PwrAttributes = psMouseDevice->ui8PwrAttributes;
+ psHIDDevice->ui8Subclass = USB_HID_SCLASS_BOOT;
+ psHIDDevice->ui8Protocol = USB_HID_PROTOCOL_MOUSE;
+ psHIDDevice->ui8NumInputReports = 1;
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+ psHIDDevice->pfnRxCallback = HIDMouseRxHandler;
+ psHIDDevice->pvRxCBData = (void *)psMouseDevice;
+ psHIDDevice->pfnTxCallback = HIDMouseTxHandler;
+ psHIDDevice->pvTxCBData = (void *)psMouseDevice;
+ psHIDDevice->bUseOutEndpoint = false;
+ psHIDDevice->psHIDDescriptor = &g_sMouseHIDDescriptor;
+ psHIDDevice->ppui8ClassDescriptors = g_pui8MouseClassDescriptors;
+ psHIDDevice->ppui8StringDescriptors =
+ psMouseDevice->ppui8StringDescriptors;
+ psHIDDevice->ui32NumStringDescriptors =
+ psMouseDevice->ui32NumStringDescriptors;
+ psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a keyboard.
+ //
+ return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID mouse device.
+//!
+//! \param pvMouseDevice is the pointer to the device instance structure.
+//!
+//! This function terminates HID mouse operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e pvMouseDevice instance may not me used in any other call to the HID
+//! mouse device other than USBDHIDMouseInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDMouseTerm(void *pvMouseDevice)
+{
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to the device.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Mark our device as no longer configured.
+ //
+ psMouseDevice->sPrivateData.ui8USBConfigured = 0;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the mouse callback.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//! \param pvCBData is the pointer that client wishes to be provided on
+//! each event sent to the mouse callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnCallback function
+//! passed on USBDHIDMouseInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the pvMouseDevice structure passed to USBDHIDMouseInit()
+//! resides in RAM. If this structure is in flash, callback data changes are
+//! not possible.
+//!
+//! \return Returns the previous callback pointer that was set for this
+//! instance.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseSetCBData(void *pvMouseDevice, void *pvCBData)
+{
+ void *pvOldCBData;
+ tUSBDHIDMouseDevice *psMouse;
+
+ //
+ // Check for a NULL pointer in the device parameter.
+ //
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to our mouse device.
+ //
+ psMouse = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Save the old callback pointer and replace it with the new value.
+ //
+ pvOldCBData = psMouse->pvCBData;
+ psMouse->pvCBData = pvCBData;
+
+ //
+ // Pass the old callback pointer back to the caller.
+ //
+ return(pvOldCBData);
+}
+
+//*****************************************************************************
+//
+//! Reports a mouse state change, pointer movement or button press, to the USB
+//! host.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//! \param i8DeltaX is the relative horizontal pointer movement that the
+//! application wishes to report. Valid values are in the range [-127, 127]
+//! with positive values indicating movement to the right.
+//! \param i8DeltaY is the relative vertical pointer movement that the
+//! application wishes to report. Valid values are in the range [-127, 127]
+//! with positive values indicating downward movement.
+//! \param ui8Buttons is a bit mask indicating which (if any) of the three
+//! mouse buttons is pressed. Valid values are logical OR combinations of
+//! \b MOUSE_REPORT_BUTTON_1, \b MOUSE_REPORT_BUTTON_2 and
+//! \b MOUSE_REPORT_BUTTON_3.
+//!
+//! This function is called to report changes in the mouse state to the USB
+//! host. These changes can be movement of the pointer, reported relative to
+//! its previous position, or changes in the states of up to 3 buttons that
+//! the mouse may support. The return code indicates whether or not the
+//! mouse report could be sent to the host. In cases where a previous
+//! report is still being transmitted, \b MOUSE_ERR_TX_ERROR is returned
+//! and the state change is ignored.
+//!
+//! \return Returns \b MOUSE_SUCCESS on success, \b MOUSE_ERR_TX_ERROR if an
+//! error occurred while attempting to schedule transmission of the mouse
+//! report to the host (typically due to a previous report which has not yet
+//! completed transmission or due to disconnection of the host) or \b
+//! MOUSE_ERR_NOT_CONFIGURED if called before a host has connected to and
+//! configured the device.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDMouseStateChange(void *pvMouseDevice, int8_t i8DeltaX, int8_t i8DeltaY,
+ uint8_t ui8Buttons)
+{
+ uint32_t ui32Retcode, ui32Count;
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Get a pointer to the device.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Update the global mouse report with the information passed.
+ //
+ psInst->pui8Report[HID_REPORT_BUTTONS] = ui8Buttons;
+ psInst->pui8Report[HID_REPORT_X] = (uint8_t)i8DeltaX;
+ psInst->pui8Report[HID_REPORT_Y] = (uint8_t)i8DeltaY;
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(!psInst->ui8USBConfigured)
+ {
+ return(MOUSE_ERR_NOT_CONFIGURED);
+ }
+
+ //
+ // Only send a report if the transmitter is currently free.
+ //
+ if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
+ {
+ //
+ // Send the report to the host.
+ //
+ psInst->iMouseState = eHIDMouseStateSend;
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pui8Report, MOUSE_REPORT_SIZE,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(!ui32Count)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ ui32Retcode = MOUSE_ERR_TX_ERROR;
+ }
+ else
+ {
+ ui32Retcode = MOUSE_SUCCESS;
+ }
+ }
+ else
+ {
+ ui32Retcode = MOUSE_ERR_TX_ERROR;
+ }
+ //
+ // Return the relevant error code to the caller.
+ //
+ return(ui32Retcode);
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//! \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 USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDMousePowerStatusSet(void *pvMouseDevice, uint8_t ui8Power)
+{
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDHIDPowerStatusSet((void *)psHIDDevice, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//!
+//! 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 causes the bus
+//! to resume operation within 20mS. 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 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
+USBDHIDMouseRemoteWakeupRequest(void *pvMouseDevice)
+{
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDHIDRemoteWakeupRequest((void *)&psHIDDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhidmouse.h b/usblib/device/usbdhidmouse.h new file mode 100644 index 0000000..6978ca7 --- /dev/null +++ b/usblib/device/usbdhidmouse.h @@ -0,0 +1,299 @@ +//*****************************************************************************
+//
+// usbdhidmouse.h - Public header file for the USB HID Mouse device class
+// driver
+//
+// 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 USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHIDMOUSE_H__
+#define __USBDHIDMOUSE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_mouse_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB HID mouse code and are here only to help with the application
+// allocating the correct amount of memory for the HID mouse device code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The size of the mouse input report sent to the host.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_SIZE 3
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the mouse can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ eHIDMouseStateUnconfigured,
+
+ //
+ // No keys to send and not waiting on data.
+ //
+ eHIDMouseStateIdle,
+
+ //
+ // Waiting on report data from the host.
+ //
+ eHIDMouseStateWaitData,
+
+ //
+ // Waiting on data to be sent out.
+ //
+ eHIDMouseStateSend
+}
+tMouseState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure provides the private instance data structure for the USB
+// HID Mouse device. This structure forms the RAM workspace used by each
+// instance of the mouse.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The USB configuration number set by the host or 0 of the device is
+ // currently unconfigured.
+ //
+ uint8_t ui8USBConfigured;
+
+ //
+ // The protocol requested by the host, USB_HID_PROTOCOL_BOOT or
+ // USB_HID_PROTOCOL_REPORT.
+ //
+ uint8_t ui8Protocol;
+
+ //
+ // A buffer used to hold the last input report sent to the host.
+ //
+ uint8_t pui8Report[MOUSE_REPORT_SIZE];
+
+ //
+ // The current state of the mouse interrupt IN endpoint.
+ //
+ volatile tMouseState iMouseState;
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+}
+tHIDMouseInstance;
+
+//*****************************************************************************
+//
+//! This structure is used by the application to define operating parameters
+//! for the HID mouse device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which is called to notify
+ //! the application of events relating to the operation of the mouse.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the mouse callback, pfnCallback.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be (1 + (5 * (num languages))).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! remain accessible for as long as the mouse device is in use and must
+ //! not be modified by any code outside the HID mouse driver.
+ //
+ tHIDMouseInstance sPrivateData;
+}
+tUSBDHIDMouseDevice;
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDMouseStateChange() indicates success.
+//
+//*****************************************************************************
+#define MOUSE_SUCCESS 0
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDMouseStateChange() indicates that an error was
+//! reported while attempting to send a report to the host. A client should
+//! assume that the host has disconnected if this return code is seen.
+//
+//*****************************************************************************
+#define MOUSE_ERR_TX_ERROR 2
+
+//*****************************************************************************
+//
+//! USBDHIDMouseStateChange() returns this value if it is called before the
+//! USB host has connected and configured the device. All mouse state
+//! information passed on the call is been ignored.
+//
+//*****************************************************************************
+#define MOUSE_ERR_NOT_CONFIGURED \
+ 4
+
+//*****************************************************************************
+//
+//! Setting this bit in the ui8Buttons parameter to USBDHIDMouseStateChange()
+//! indicates to the USB host that button 1 on the mouse is pressed.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_BUTTON_1 0x01
+
+//*****************************************************************************
+//
+//! Setting this bit in the ui8Buttons parameter to USBDHIDMouseStateChange()
+//! indicates to the USB host that button 2 on the mouse is pressed.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_BUTTON_2 0x02
+
+//*****************************************************************************
+//
+//! Setting this bit in the ui8Buttons parameter to USBDHIDMouseStateChange()
+//! indicates to the USB host that button 3 on the mouse is pressed.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_BUTTON_3 0x04
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDMouseInit(uint32_t ui32Index,
+ tUSBDHIDMouseDevice *psMouseDevice);
+extern void *USBDHIDMouseCompositeInit(uint32_t ui32Index,
+ tUSBDHIDMouseDevice *psMouseDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDMouseTerm(void *pvMouseDevice);
+extern void *USBDHIDMouseSetCBData(void *pvMouseDevice, void *pvCBData);
+extern uint32_t USBDHIDMouseStateChange(void *pvMouseDevice, int8_t i8DeltaX,
+ int8_t i8DeltaY, uint8_t ui8Buttons);
+extern void USBDHIDMousePowerStatusSet(void *pvMouseDevice,
+ uint8_t ui8Power);
+extern bool USBDHIDMouseRemoteWakeupRequest(void *pvMouseDevice);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHIDMOUSE_H__
diff --git a/usblib/device/usbdmsc.c b/usblib/device/usbdmsc.c new file mode 100644 index 0000000..daea1f0 --- /dev/null +++ b/usblib/device/usbdmsc.c @@ -0,0 +1,2441 @@ +//*****************************************************************************
+//
+// usbdmsc.c - USB mass storage device class driver.
+//
+// Copyright (c) 2009-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_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbmsc.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdmsc.h"
+
+//*****************************************************************************
+//
+//! \addtogroup msc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These are the internal flags used with the ui32Flags member variable.
+//
+//*****************************************************************************
+#define USBD_FLAG_DMA_IN 0x00000001
+#define USBD_FLAG_DMA_OUT 0x00000002
+#define USBD_FLAG_ALLOW_REMOVAL 0x00000004
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// These are fields that are used by the USB descriptors for the Mass Storage
+// Class.
+//
+//*****************************************************************************
+#define USB_MSC_SUBCLASS_SCSI 0x6
+#define USB_MSC_PROTO_BULKONLY 0x50
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define DATA_IN_ENDPOINT USB_EP_1
+#define DATA_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// Maximum packet size for the bulk endpoints is 64 bytes.
+//
+//*****************************************************************************
+#define DATA_IN_EP_MAX_SIZE 64
+#define DATA_OUT_EP_MAX_SIZE 64
+
+//*****************************************************************************
+//
+// These defines control the size of USB transfers for commands.
+//
+//*****************************************************************************
+#define COMMAND_BUFFER_SIZE 64
+
+//*****************************************************************************
+//
+// The block size of a device. It defaults to DEVICE_BLOCK_SIZE
+//
+//*****************************************************************************
+static uint32_t g_pui32BlockSize = DEVICE_BLOCK_SIZE;
+
+//*****************************************************************************
+//
+// The local buffer used to read in commands and process them.
+//
+//*****************************************************************************
+static uint8_t g_pui8Command[COMMAND_BUFFER_SIZE];
+
+//*****************************************************************************
+//
+// The current transfer state is held in these variables.
+//
+//*****************************************************************************
+static tMSCCSW g_sSCSICSW;
+
+//*****************************************************************************
+//
+// The current state for the SCSI commands that are being handled and are
+// stored in the tMSCInstance.ui8SCSIState structure member.
+//
+//*****************************************************************************
+
+//
+// No command in process.
+//
+#define STATE_SCSI_IDLE 0x00
+
+//
+// Sending and reading logical blocks.
+//
+#define STATE_SCSI_SEND_BLOCKS 0x01
+
+//
+// Receiving and writing logical blocks.
+//
+#define STATE_SCSI_RECEIVE_BLOCKS 0x02
+
+//
+// Send the status once the previous transfer is complete.
+//
+#define STATE_SCSI_SEND_STATUS 0x03
+
+//
+// Status was prepared to be sent and now waiting for it to have gone out.
+//
+#define STATE_SCSI_SENT_STATUS 0x04
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8MSCDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts
+ // assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ 0, // USB Device Class (spec 5.1.1)
+ 0, // USB Device Sub-class (spec 5.1.1)
+ 0, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during
+ // USBDCDCInit).
+ USBShort(0), // Product ID (filled in during
+ // USBDCDCInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Mass storage device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8MSCDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(32), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes
+ // this configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake
+ // up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const uint8_t g_pui8MSCInterface[MSCINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 2, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_MASS_STORAGE, // The interface class
+ USB_MSC_SUBCLASS_SCSI, // The interface sub-class.
+ USB_MSC_PROTO_BULKONLY, // The interface protocol for the sub-class
+ // specified above.
+ 0, // The string index for this interface.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The mass storage configuration descriptor is defined as two sections,
+// one containing just the 9 byte USB configuration descriptor and the other
+// containing everything else that is sent to the host along with it.
+//
+//*****************************************************************************
+const tConfigSection g_sMSCConfigSection =
+{
+ sizeof(g_pui8MSCDescriptor),
+ g_pui8MSCDescriptor
+};
+
+const tConfigSection g_sMSCInterfaceSection =
+{
+ sizeof(g_pui8MSCInterface),
+ g_pui8MSCInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete bulk device configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psMSCSections[] =
+{
+ &g_sMSCConfigSection,
+ &g_sMSCInterfaceSection
+};
+
+#define NUM_MSC_SECTIONS (sizeof(g_psMSCSections) / \
+ sizeof(g_psMSCSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sMSCConfigHeader =
+{
+ NUM_MSC_SECTIONS,
+ g_psMSCSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppsMSCConfigDescriptors[] =
+{
+ &g_sMSCConfigHeader
+};
+
+//*****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//*****************************************************************************
+static void HandleDisconnect(void *pvMSCDevice);
+static void ConfigChangeHandler(void *pvMSCDevice, uint32_t ui32Value);
+static void HandleEndpoints(void *pvMSCDevice, uint32_t ui32Status);
+static void HandleRequests(void *pvMSCDevice, tUSBRequest *psUSBRequest);
+static void USBDSCSISendStatus(tUSBDMSCDevice *psMSCDevice);
+uint32_t USBDSCSICommand(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW);
+static void HandleDevice(void *pvMSCDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB MSC device.
+//
+//*****************************************************************************
+const tCustomHandlers g_sMSCHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ 0,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ 0,
+
+ //
+ // ResumeHandler
+ //
+ 0,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+//! This function is used by an application if it can detect insertion or
+//! removal of the media.
+//!
+//! \param pvMSCDevice is the mass storage device instance that had a media
+//! change.
+//! \param iMediaStatus is the updated status for the media.
+//!
+//! This function should be called by an application when it detects a change
+//! in the status of the media in use by the USB mass storage class. The
+//! \e iMediaStatus parameter will indicate the new status of the media and
+//! can also indicate that the application has no knowledge of the media state.
+//!
+//! There are currently the three following values for the \e iMediaStatus
+//! parameter:
+//! - \b eUSBDMSCMediaPresent indicates that the media is present or has been
+//! added.
+//! - \b eUSBDMSCMediaNotPresent indicates that the media is not present or was
+//! removed.
+//! - \b eUSBDMSCMediaUnknown indicates that the application has no knowledge
+//! of the media state and the USB mass storage class.
+//!
+//! It will be left up to the application to call this function whenever it
+//! detects a change or simply call it once with \b eUSBDMSCMediaUnknown and
+//! allow the mass storage class to infer the state from the remaining device
+//! APIs.
+//!
+//! \note It is recommended that the application use this function to inform
+//! the mass storage class of media state changes as it will lead to a more
+//! responsive system.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDMSCMediaChange(void *pvMSCDevice, tUSBDMSCMediaStatus iMediaStatus)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ //
+ // Create a device instance pointer.
+ //
+ psMSCDevice = pvMSCDevice;
+
+ //
+ // Save the current media status.
+ //
+ psMSCDevice->sPrivateData.iMediaStatus = iMediaStatus;
+}
+
+//*****************************************************************************
+//
+// This function is called to handle the interrupts on the Bulk endpoints for
+// the mass storage class.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvMSCDevice, uint32_t ui32Status)
+{
+ tUSBDMSCDevice *psMSCDevice;
+ tMSCInstance *psInst;
+ tMSCCBW *psSCSICBW;
+ uint32_t ui32EPStatus, ui32Size;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ui32Index is different in both cases.
+ //
+ psMSCDevice = pvMSCDevice;
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Get the endpoints status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if((ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint))) ||
+ ((psInst->ui32Flags & USBD_FLAG_DMA_IN) &&
+ (USBLibDMAChannelStatus(psInst->psDMAInstance, psInst->ui8INDMA) &
+ USBLIBSTATUS_DMA_COMPLETE)))
+ {
+ switch(psInst->ui8SCSIState)
+ {
+ //
+ // Handle the case where we are sending out data due to a read
+ // command.
+ //
+ case STATE_SCSI_SEND_BLOCKS:
+ {
+ //
+ // Decrement the number of bytes left to send.
+ //
+ psInst->ui32BytesToTransfer -= g_pui32BlockSize;
+
+ //
+ // If we are done then move on to the status phase.
+ //
+ if(psInst->ui32BytesToTransfer == 0)
+ {
+ //
+ // Set the status so that it can be sent when this
+ // response has has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // DMA has completed for the IN endpoint.
+ //
+ psInst->ui32Flags &= ~USBD_FLAG_DMA_IN;
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE,
+ 0, 0);
+ }
+
+ //
+ // Make sure that the transfer has actually finished. If
+ // it has not there will be another interrupt to send
+ // out the status.
+ //
+ if(USBEndpointStatus(USB0_BASE,psInst->ui8INEndpoint) &
+ USB_DEV_TX_TXPKTRDY)
+ {
+ //
+ // Send back the status once this transfer is complete.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+ }
+ else
+ {
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psMSCDevice);
+ }
+
+ //
+ // The transfer is complete so don't read anymore data.
+ //
+ break;
+ }
+
+ //
+ // Move on to the next Logical Block.
+ //
+ psInst->ui32CurrentLBA++;
+
+ //
+ // Read the new data and send it out.
+ //
+ if(psMSCDevice->sMediaFunctions.pfnBlockRead(psInst->pvMedia,
+ (uint8_t *)psInst->pui32Buffer,
+ psInst->ui32CurrentLBA, 1) == 0)
+ {
+ }
+
+ //
+ // Configure and enable DMA for the IN transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance,
+ psInst->ui8INDMA, psInst->pui32Buffer,
+ g_pui32BlockSize);
+
+ //
+ // Start the DMA transfer.
+ //
+ USBLibDMAChannelEnable(psInst->psDMAInstance,
+ psInst->ui8INDMA);
+
+ break;
+ }
+
+ //
+ // Handle sending status.
+ //
+ case STATE_SCSI_SEND_STATUS:
+ {
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle completing sending status.
+ //
+ case STATE_SCSI_SENT_STATUS:
+ {
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+
+ break;
+ }
+
+ //
+ // These cases should not occur as the being in the IDLE state due
+ // to an IN interrupt is invalid.
+ //
+ case STATE_SCSI_IDLE:
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if((ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint))) ||
+ ((psInst->ui32Flags & USBD_FLAG_DMA_OUT) &&
+ (USBLibDMAChannelStatus(psInst->psDMAInstance, psInst->ui8OUTDMA) &
+ USBLIBSTATUS_DMA_COMPLETE)))
+ {
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE,
+ psInst->ui8OUTEndpoint);
+
+ switch(psInst->ui8SCSIState)
+ {
+ //
+ // Receiving and writing bytes to the storage device.
+ //
+ case STATE_SCSI_RECEIVE_BLOCKS:
+ {
+ //
+ // Update the current status for the buffer.
+ //
+ psInst->ui32BytesToTransfer -= g_pui32BlockSize;
+
+ //
+ // Write the new data.
+ //
+ psMSCDevice->sMediaFunctions.pfnBlockWrite(psInst->pvMedia,
+ (uint8_t *)psInst->pui32Buffer,
+ psInst->ui32CurrentLBA, 1);
+
+ //
+ // Move on to the next Logical Block.
+ //
+ psInst->ui32CurrentLBA++;
+
+ //
+ // Check if all bytes have been received.
+ //
+ if(psInst->ui32BytesToTransfer == 0)
+ {
+ //
+ // Set the status so that it can be sent when this response
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // DMA has completed for the OUT endpoint.
+ //
+ psInst->ui32Flags &= ~USBD_FLAG_DMA_OUT;
+
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psMSCDevice);
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE,
+ psInst->ui8OUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // If there is an event callback then call it to notify
+ // that last operation has completed.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE,
+ 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Configure and enable DMA for the OUT transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance,
+ psInst->ui8OUTDMA, psInst->pui32Buffer,
+ g_pui32BlockSize);
+ }
+
+ break;
+ }
+
+ //
+ // If there is an OUT transfer in idle state then it was a new
+ // command.
+ //
+ case STATE_SCSI_IDLE:
+ {
+ //
+ // Attempt to handle the new command.
+ //
+
+ //
+ // Receive the command.
+ //
+ ui32Size = COMMAND_BUFFER_SIZE;
+ MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ g_pui8Command, &ui32Size);
+ psSCSICBW = (tMSCCBW *)g_pui8Command;
+
+ //
+ // Acknowledge the OUT data packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint, false);
+
+ //
+ // If this is a valid CBW then handle it.
+ //
+ if(psSCSICBW->dCBWSignature == CBW_SIGNATURE)
+ {
+ g_sSCSICSW.dCSWSignature = CSW_SIGNATURE;
+ g_sSCSICSW.dCSWTag = psSCSICBW->dCBWTag;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ g_sSCSICSW.bCSWStatus = 0;
+
+ USBDSCSICommand(psMSCDevice, psSCSICBW);
+ }
+ else
+ {
+ //
+ // Just return to the idle state since we are now out of
+ // sync with the host. This should not happen, but this
+ // should allow the device to synchronize with the host
+ // controller.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvMSCDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tMSCInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDMSCDevice *psMSCDevice;
+
+ psMSCDevice = (tUSBDMSCDevice *)pvMSCDevice;
+
+ //
+ // Get the instance data pointers.
+ //
+ psInst = &((tUSBDMSCDevice *)pvMSCDevice)->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB MSC
+ // class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f));
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psInst->ui8INDMA != 0)
+ {
+ USBLibDMAChannelRelease(psInst->psDMAInstance,
+ psInst->ui8INDMA);
+ }
+
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ psInst->ui8INDMA =
+ USBLibDMAChannelAllocate(psInst->psDMAInstance,
+ psInst->ui8INEndpoint, 0,
+ USB_DMA_EP_TX |
+ USB_DMA_EP_DEVICE);
+
+ //
+ // Set the DMA individual transfer size.
+ //
+ USBLibDMAUnitSizeSet(psInst->psDMAInstance, psInst->ui8INDMA,
+ 32);
+
+ //
+ // Set the DMA arbitration size.
+ //
+ USBLibDMAArbSizeSet(psInst->psDMAInstance, psInst->ui8INDMA,
+ 16);
+ }
+ else
+ {
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psInst->ui8OUTDMA != 0)
+ {
+ USBLibDMAChannelRelease(psInst->psDMAInstance,
+ psInst->ui8OUTDMA);
+ }
+
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ psInst->ui8OUTDMA =
+ USBLibDMAChannelAllocate(psInst->psDMAInstance,
+ psInst->ui8OUTEndpoint, 0,
+ USB_DMA_EP_RX |
+ USB_DMA_EP_DEVICE);
+
+ //
+ // Set the DMA individual transfer size.
+ //
+ USBLibDMAUnitSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 32);
+
+ //
+ // Set the DMA arbitration size.
+ //
+ USBLibDMAArbSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 16);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psMSCDevice->pfnEventCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psMSCDevice->pfnEventCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psMSCDevice->pfnEventCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvMSCDevice)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psMSCDevice = (tUSBDMSCDevice *)pvMSCDevice;
+
+ //
+ // Close the drive requested.
+ //
+ if(psMSCDevice->sPrivateData.pvMedia != 0)
+ {
+ psMSCDevice->sPrivateData.pvMedia = 0;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ }
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psMSCDevice->pfnEventCallback(pvMSCDevice, USB_EVENT_DISCONNECTED, 0,
+ 0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes.
+//
+//*****************************************************************************
+static void
+ConfigChangeHandler(void *pvMSCDevice, uint32_t ui32Value)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psMSCDevice = (tUSBDMSCDevice *)pvMSCDevice;
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psMSCDevice->sPrivateData.ui8OUTDMA != 0)
+ {
+ USBLibDMAChannelRelease(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTDMA);
+ }
+
+ //
+ // Configure the DMA for the OUT endpoint.
+ //
+ psMSCDevice->sPrivateData.ui8OUTDMA =
+ USBLibDMAChannelAllocate(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTEndpoint, 64,
+ USB_DMA_EP_RX | USB_DMA_EP_DEVICE);
+
+ USBLibDMAUnitSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTDMA, 32);
+
+ USBLibDMAArbSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTDMA, 16);
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psMSCDevice->sPrivateData.ui8INDMA != 0)
+ {
+ USBLibDMAChannelRelease(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INDMA);
+ }
+
+ //
+ // Configure the DMA for the IN endpoint.
+ //
+ psMSCDevice->sPrivateData.ui8INDMA =
+ USBLibDMAChannelAllocate(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INEndpoint, 64,
+ USB_DMA_EP_TX | USB_DMA_EP_DEVICE);
+
+ USBLibDMAUnitSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INDMA, 32);
+
+ USBLibDMAArbSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INDMA, 16);
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psMSCDevice->pfnEventCallback(pvMSCDevice, USB_EVENT_CONNECTED, 0, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the mass storage class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! mass storage class device operation.
+//! \param psMSCDevice points to a structure containing parameters customizing
+//! the operation of the mass storage device.
+//!
+//! In order for an application to initialize the USB device mass storage
+//! class, it must first call this function with the a valid mass storage
+//! device class structure in the \e psMSCDevice parameter. This allows this
+//! function to initialize the USB controller and device code to be prepared to
+//! enumerate and function as a USB mass storage device.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the mass storage class.
+//!
+//! See the documentation on the tUSBDMSCDevice structure for more information
+//! on how to properly fill the structure members.
+//!
+//! \return Returns 0 on failure or a non-zero void pointer on success.
+//
+//*****************************************************************************
+void *
+USBDMSCInit(uint32_t ui32Index, tUSBDMSCDevice *psMSCDevice)
+{
+ tDeviceDescriptor *psDevDesc;
+ tConfigDescriptor *pConfDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psMSCDevice);
+ ASSERT(psMSCDevice->ppui8StringDescriptors);
+
+ USBDMSCCompositeInit(ui32Index, psMSCDevice, 0);
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8MSCDeviceDescriptor;
+ psDevDesc->idVendor = psMSCDevice->ui16VID;
+ psDevDesc->idProduct = psMSCDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ pConfDesc = (tConfigDescriptor *)g_pui8MSCDescriptor;
+ pConfDesc->bmAttributes = psMSCDevice->ui8PwrAttributes;
+ pConfDesc->bMaxPower = (uint8_t)(psMSCDevice->ui16MaxPowermA / 2);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psMSCDevice->sPrivateData.sDevInfo,
+ (void *)psMSCDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the mass storage class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! mass storage class device operation.
+//! \param psMSCDevice points to a structure containing parameters customizing
+//! the operation of the mass storage device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! In order for an application to initialize the USB device mass storage
+//! class, it must first call this function with the a valid mass storage
+//! device class structure in the \e psMSCDevice parameter. This allows this
+//! function to initialize the USB controller and device code to be prepared to
+//! enumerate and function as a USB mass storage device. If this mass storage
+//! device is part of a composite device, then the \e psCompEntry should
+//! point to the composite device entry to initialize. This is part of the
+//! array that is passed to the USBDCompositeInit() function.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the mass storage class.
+//!
+//! See the documentation on the tUSBDMSCDevice structure for more information
+//! on how to properly fill the structure members.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB mass storage APIs.
+//
+//*****************************************************************************
+void *
+USBDMSCCompositeInit(uint32_t ui32Index, tUSBDMSCDevice *psMSCDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psMSCDevice);
+ ASSERT(psMSCDevice->ppui8StringDescriptors);
+ ASSERT(psCompEntry != 0);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->bConnected = false;
+ psInst->iMediaStatus = eUSBDMSCMediaUnknown;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psMSCDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sMSCHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8MSCDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppsMSCConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the mass storage device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Set the initial interface and endpoints.
+ //
+ psInst->ui8Interface = 0;
+ psInst->ui8OUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ui8INEndpoint = DATA_IN_ENDPOINT;
+
+ //
+ // Set the initial SCSI state to idle.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psMSCDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psMSCDevice->ui32NumStringDescriptors;
+
+ //
+ // Open the drive requested.
+ //
+ psInst->pvMedia = psMSCDevice->sMediaFunctions.pfnOpen(0);
+
+ if(psInst->pvMedia == 0)
+ {
+ //
+ // There is no media currently present.
+ //
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+ else
+ {
+ //
+ // Media is now ready for use.
+ //
+ psInst->ui8SenseKey = SCSI_RS_KEY_UNIT_ATTN;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOTRDY2RDY;
+ }
+
+ //
+ // Enable Clocking to the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Get the DMA instance pointer.
+ //
+ psInst->psDMAInstance = USBLibDMAInit(0);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the mass storage device.
+//!
+//! \param pvMSCDevice is the pointer to the device instance structure as
+//! returned by USBDMSCInit() or USBDMSCCompositeInit().
+//!
+//! This function terminates mass storage operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e pvMSCDevice instance may not me used in any other call to the mass
+//! storage device other than USBDMSCInit() or USBDMSCCompositeInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDMSCTerm(void *pvMSCDevice)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Cleanly exit device mode.
+ //
+ USBDCDTerm(0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psMSCDevice = pvMSCDevice;
+
+ //
+ // If the media was opened the close it out.
+ //
+ if(psMSCDevice->sPrivateData.pvMedia != 0)
+ {
+ psMSCDevice->sPrivateData.pvMedia = 0;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvMSCDevice is instance data for this request.
+// \param pUSBRequest points to the request received.
+//
+// This call parses the provided request structure to determine the command.
+// The only mass storage command supported over endpoint 0 is the Get Max LUN
+// command.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HandleRequests(void *pvMSCDevice, tUSBRequest *pUSBRequest)
+{
+ //
+ // This class only support a single LUN.
+ //
+ static const uint8_t ui8MaxLun = 0;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Determine the type of request.
+ //
+ switch(pUSBRequest->bRequest)
+ {
+ //
+ // A Set Report request is received from the host when it sends an
+ // Output report via endpoint 0.
+ //
+ case USBREQ_GET_MAX_LUN:
+ {
+ //
+ // Need to ACK the data on end point 0 with last data since there
+ // is no more data expected.
+ //
+ USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui8MaxLun, 1);
+
+ break;
+ }
+ case USBREQ_BULK_ONLY_RESET:
+ {
+ //
+ // Need to ACK the data on end point 0 with last data since there
+ // is no more data expected.
+ //
+ USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Send a null packet to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui8MaxLun, 0);
+
+ break;
+ }
+
+ //
+ // This request was not recognized so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Inquiry command when it is received
+// from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIInquiry(tUSBDMSCDevice *psMSCDevice)
+{
+ int32_t i32Idx;
+ tMSCInstance *psInst;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)g_pui8Command;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Direct Access device, Removable storage and SCSI 1 responses.
+ //
+ pui32Data[0] = SCSI_INQ_PDT_SBC | (SCSI_INQ_RMB << 8);
+
+ //
+ // Additional Length is fixed at 31 bytes.
+ //
+ pui32Data[1] = 31;
+
+ //
+ // Copy the Vendor string.
+ //
+ for(i32Idx = 0; i32Idx < 8; i32Idx++)
+ {
+ g_pui8Command[i32Idx + 8] = psMSCDevice->pui8Vendor[i32Idx];
+ }
+
+ //
+ // Copy the Product string.
+ //
+ for(i32Idx = 0; i32Idx < 16; i32Idx++)
+ {
+ g_pui8Command[i32Idx + 16] = psMSCDevice->pui8Product[i32Idx];
+ }
+
+ //
+ // Copy the Version string.
+ //
+ for(i32Idx = 0; i32Idx < 4; i32Idx++)
+ {
+ g_pui8Command[i32Idx + 32] = psMSCDevice->pui8Version[i32Idx];
+ }
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 36);
+
+ //
+ // Send the data to the host.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint, USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read Capacities command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIReadCapacities(tUSBDMSCDevice *psMSCDevice)
+{
+ uint32_t ui32Blocks;
+ tMSCInstance *psInst;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)g_pui8Command;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ if(psInst->pvMedia != 0)
+ {
+ if(psMSCDevice->sMediaFunctions.pfnBlockSize)
+ {
+ //
+ // Query the block size for the device
+ //
+ g_pui32BlockSize =
+ psMSCDevice->sMediaFunctions.pfnBlockSize(psInst->pvMedia);
+ }
+ ui32Blocks =
+ psMSCDevice->sMediaFunctions.pfnNumBlocks(psInst->pvMedia);
+
+ pui32Data[0] = 0x08000000;
+
+ //
+ // Fill in the number of blocks, the bytes endianness must be changed.
+ //
+ g_pui8Command[4] = ui32Blocks >> 24;
+ g_pui8Command[5] = 0xff & (ui32Blocks >> 16);
+ g_pui8Command[6] = 0xff & (ui32Blocks >> 8);
+ g_pui8Command[7] = 0xff & (ui32Blocks);
+
+ //
+ // Current media capacity
+ //
+ g_pui8Command[8] = 0x2;
+
+ //
+ // Fill in the block size, which is g_pui32BlockSize.
+ //
+ g_pui8Command[9] = 0xff & (g_pui32BlockSize >> 16);
+ g_pui8Command[10] = 0xff & (g_pui32BlockSize >> 8);
+ g_pui8Command[11] = 0xff & g_pui32BlockSize;
+
+ //
+ // Send out the 12 bytes that are in this response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 12);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read Capacity command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIReadCapacity(tUSBDMSCDevice *psMSCDevice)
+{
+ uint32_t ui32Blocks;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ if(psMSCDevice->sMediaFunctions.pfnBlockSize)
+ {
+ //
+ // Query the block size for the device
+ //
+ g_pui32BlockSize =
+ psMSCDevice->sMediaFunctions.pfnBlockSize(psInst->pvMedia);
+ }
+
+ ui32Blocks = psMSCDevice->sMediaFunctions.pfnNumBlocks(psInst->pvMedia);
+
+ //
+ // Only decrement if any blocks were found.
+ //
+ if(ui32Blocks != 0)
+ {
+ //
+ // One less than the maximum number is the last addressable
+ // block.
+ //
+ ui32Blocks--;
+ }
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Fill in the number of blocks, the bytes endianness must be changed.
+ //
+ g_pui8Command[0] = 0xff & (ui32Blocks >> 24);
+ g_pui8Command[1] = 0xff & (ui32Blocks >> 16);
+ g_pui8Command[2] = 0xff & (ui32Blocks >> 8);
+ g_pui8Command[3] = 0xff & (ui32Blocks);
+
+ g_pui8Command[4] = 0;
+
+ //
+ // Fill in the block size, which is g_pui32BlockSize.
+ //
+ g_pui8Command[5] = 0xff & (g_pui32BlockSize >> 16);
+ g_pui8Command[6] = 0xff & (g_pui32BlockSize >> 8);
+ g_pui8Command[7] = 0xff & g_pui32BlockSize;
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 8);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Request Sense command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIRequestSense(tUSBDMSCDevice *psMSCDevice)
+{
+ tMSCInstance *psInst;
+ int32_t i32Idx;
+
+ //
+ // Zero out the response data.
+ //
+ for(i32Idx = 0; i32Idx < 18; i32Idx++)
+ {
+ g_pui8Command[i32Idx] = 0;
+ }
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // The request sense response.
+ //
+ g_pui8Command[0] = psInst->ui8ErrorCode;
+ g_pui8Command[2] = psInst->ui8SenseKey;
+
+ //
+ // There are 10 more bytes of data.
+ //
+ g_pui8Command[7] = 10;
+
+ //
+ // Transition from not ready to ready.
+ //
+ g_pui8Command[12] = (uint8_t)psInst->ui16AddSenseCode;
+ g_pui8Command[13] = (uint8_t)(psInst->ui16AddSenseCode >> 8);
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 18);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint, USB_TRANS_IN);
+
+ //
+ // Reset the valid flag on errors.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_CUR_ERRORS;
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Move on to the status phase.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read 10 command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIRead10(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ uint16_t ui16NumBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Default the number of blocks.
+ //
+ ui16NumBlocks = 0;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Get the logical block from the CBW structure. This switching
+ // is required to convert from big to little endian.
+ //
+ psInst->ui32CurrentLBA = (psSCSICBW->CBWCB[2] << 24) |
+ (psSCSICBW->CBWCB[3] << 16) |
+ (psSCSICBW->CBWCB[4] << 8) |
+ (psSCSICBW->CBWCB[5] << 0);
+
+ //
+ // More bytes to read.
+ //
+ ui16NumBlocks = (psSCSICBW->CBWCB[7] << 8) | psSCSICBW->CBWCB[8];
+
+ //
+ // Read the next logical block from the storage device.
+ //
+ if(psMSCDevice->sMediaFunctions.pfnBlockRead(psInst->pvMedia,
+ (uint8_t *)psInst->pui32Buffer, psInst->ui32CurrentLBA, 1) == 0)
+ {
+ psInst->pvMedia = 0;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ }
+ }
+
+ //
+ // If there is media present then start transferring the data.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Configure and DMA for the IN transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance, psInst->ui8INDMA,
+ psInst->pui32Buffer, g_pui32BlockSize);
+
+ //
+ // Remember that a DMA is in progress.
+ //
+ psInst->ui32Flags |= USBD_FLAG_DMA_IN;
+
+ //
+ // Schedule the remaining bytes to send.
+ //
+ psInst->ui32BytesToTransfer = (g_pui32BlockSize * ui16NumBlocks);
+
+ //
+ // Move on and start sending blocks.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SEND_BLOCKS;
+
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_READING, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read 10 command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIWrite10(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ uint16_t ui16NumBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Get instance data pointers.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present then start transferring the data.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Get the logical block from the CBW structure. This switching
+ // is required to convert from big to little endian.
+ //
+ psInst->ui32CurrentLBA = (psSCSICBW->CBWCB[2] << 24) |
+ (psSCSICBW->CBWCB[3] << 16) |
+ (psSCSICBW->CBWCB[4] << 8) |
+ (psSCSICBW->CBWCB[5] << 0);
+
+ //
+ // More bytes to read.
+ //
+ ui16NumBlocks = (psSCSICBW->CBWCB[7] << 8) | psSCSICBW->CBWCB[8];
+
+ psInst->ui32BytesToTransfer = g_pui32BlockSize * ui16NumBlocks;
+
+ //
+ // Start sending logical blocks, these are always multiples of
+ // g_pui32BlockSize bytes.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_RECEIVE_BLOCKS;
+
+ //
+ // Configure and enable DMA for the OUT transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ psInst->pui32Buffer, g_pui32BlockSize);
+
+ //
+ // Remember that a DMA is in progress.
+ //
+ psInst->ui32Flags |= USBD_FLAG_DMA_OUT;
+
+ //
+ // Notify the application of the write event.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_WRITING, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8OUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Mode Sense 6 command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIModeSense6(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Three extra bytes in this response.
+ //
+ g_pui8Command[0] = 3;
+ g_pui8Command[1] = 0;
+ g_pui8Command[2] = 0;
+ g_pui8Command[3] = 0;
+
+ //
+ // Manually send the response back to the host.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 4);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = psSCSICBW->dCBWDataTransferLength - 4;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to send out the response data based on the current
+// status of the mass storage class.
+//
+//*****************************************************************************
+static void
+USBDSCSISendStatus(tUSBDMSCDevice *psMSCDevice)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Respond with the requested status.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint,
+ (uint8_t *)&g_sSCSICSW, 13);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint, USB_TRANS_IN);
+
+ //
+ // Move the state to status sent so that the next interrupt will move the
+ // statue to idle.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SENT_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the Prevent/Allow Medium Removal command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIPreventAllowMediumRemoval(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // See if this was an allow or prevent removal request.
+ //
+ if((psSCSICBW->CBWCB[4] & SCSI_PE_MEDRMV_M) == SCSI_PE_MEDRMV_ALLOW)
+ {
+ psInst->ui32Flags |= USBD_FLAG_ALLOW_REMOVAL;
+ }
+ else
+ {
+ psInst->ui32Flags &= ~USBD_FLAG_ALLOW_REMOVAL;
+ }
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Start/Stop Unit command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIStartStopUnit(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ switch(psSCSICBW->CBWCB[4] & (SCSI_SS_UNIT_START | SCSI_SS_UNIT_LOEJ))
+ {
+ case 0:
+ {
+ //
+ // Media state is now stopped but not ejected.
+ //
+ psInst->iMediaStatus = eUSBDMSCMediaStopped;
+
+ g_sSCSICSW.bCSWStatus = 0;
+
+ break;
+ }
+ case SCSI_SS_UNIT_START:
+ {
+ //
+ // Return to Media present.
+ //
+ psInst->iMediaStatus = eUSBDMSCMediaPresent;
+
+ g_sSCSICSW.bCSWStatus = 0;
+
+ break;
+ }
+ case SCSI_SS_UNIT_LOEJ:
+ {
+ //
+ // Only allow eject if the Prevent/Allow Medium Removal has
+ // been sent and enabled medium removal.
+ //
+ if(psInst->ui32Flags & USBD_FLAG_ALLOW_REMOVAL)
+ {
+ psInst->iMediaStatus = eUSBDMSCMediaNotPresent;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ psMSCDevice->sPrivateData.pvMedia = 0;
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else
+ {
+ g_sSCSICSW.bCSWStatus = 1;
+ }
+
+ break;
+ }
+ case SCSI_SS_UNIT_START | SCSI_SS_UNIT_LOEJ:
+ {
+ //
+ // Since there was no media, check for media here.
+ //
+ psInst->pvMedia = psMSCDevice->sMediaFunctions.pfnOpen(0);
+
+ //
+ // If it is still not present then fail this command.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else
+ {
+ g_sSCSICSW.bCSWStatus = 1;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // There is no further data to send.
+ //
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle all SCSI commands.
+//
+//*****************************************************************************
+uint32_t
+USBDSCSICommand(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ uint32_t ui32RetCode, ui32TransferLength;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Initialize the return code.
+ //
+ ui32RetCode = 1;
+
+ //
+ // Save the transfer length because it may be overwritten by some calls.
+ //
+ ui32TransferLength = psSCSICBW->dCBWDataTransferLength;
+
+ switch(psSCSICBW->CBWCB[0])
+ {
+ //
+ // Respond to the SCSI Inquiry command.
+ //
+ case SCSI_INQUIRY_CMD:
+ {
+ USBDSCSIInquiry(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Respond to the test unit ready command.
+ //
+ case SCSI_TEST_UNIT_READY:
+ {
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Set the status to success for now, this could be different
+ // if there is no media present.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else if(psInst->iMediaStatus == eUSBDMSCMediaNotPresent)
+ {
+ //
+ // Set the status to success for now, this could be different
+ // if there is no media present.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+ else
+ {
+ //
+ // Since there was no media, check for media here.
+ //
+ psInst->pvMedia = psMSCDevice->sMediaFunctions.pfnOpen(0);
+
+ //
+ // If it is still not present then fail this command.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else
+ {
+ g_sSCSICSW.bCSWStatus = 1;
+ }
+ }
+ break;
+ }
+
+ //
+ // Handle the Read Capacities command.
+ //
+ case SCSI_READ_CAPACITIES:
+ {
+ USBDSCSIReadCapacities(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Read Capacity command.
+ //
+ case SCSI_READ_CAPACITY:
+ {
+ USBDSCSIReadCapacity(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Request Sense command.
+ //
+ case SCSI_REQUEST_SENSE:
+ {
+ USBDSCSIRequestSense(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Read 10 command.
+ //
+ case SCSI_READ_10:
+ {
+ USBDSCSIRead10(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Write 10 command.
+ //
+ case SCSI_WRITE_10:
+ {
+ USBDSCSIWrite10(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Mode Sense 6 command.
+ //
+ case SCSI_MODE_SENSE_6:
+ {
+ USBDSCSIModeSense6(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Prevent/Allow Medium Removal command.
+ //
+ case SCSI_MEDIUM_REMOVAL:
+ {
+ USBDSCSIPreventAllowMediumRemoval(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Prevent/Allow Medium Removal command.
+ //
+ case SCSI_START_STOP_UNIT:
+ {
+ USBDSCSIStartStopUnit(psMSCDevice, psSCSICBW);
+ break;
+ }
+
+ default:
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = psSCSICBW->dCBWDataTransferLength;
+
+ //
+ // If there is data then there is more work to do.
+ //
+ if(psSCSICBW->dCBWDataTransferLength != 0)
+ {
+ if(psSCSICBW->bmCBWFlags & CBWFLAGS_DIR_IN)
+ {
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+ }
+ else
+ {
+ //
+ // Stall the OUT endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8OUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ }
+
+ //
+ // Go back to the idle state and wait for the host to clear
+ // the stall later.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+ }
+
+ //
+ // Set the sense codes.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_ILGL_RQST;
+ psInst->ui16AddSenseCode = SCSI_RS_PV_INVALID;
+
+ break;
+ }
+ }
+
+ //
+ // If there is no data then send out the current status.
+ //
+ if(ui32TransferLength == 0)
+ {
+ USBDSCSISendStatus(psMSCDevice);
+ }
+ return(ui32RetCode);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdmsc.h b/usblib/device/usbdmsc.h new file mode 100644 index 0000000..9f33e4c --- /dev/null +++ b/usblib/device/usbdmsc.h @@ -0,0 +1,420 @@ +//*****************************************************************************
+//
+// usbdmsc.h - USB mass storage device class driver.
+//
+// Copyright (c) 2009-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.
+//
+//*****************************************************************************
+
+#ifndef __USBDMSC_H__
+#define __USBDMSC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup msc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Media Access functions.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This function is used to initialize and open the physical drive number
+ //! associated with the parameter \e ui32Drive. The function returns
+ //! zero if the drive could not be opened for some reason. In the case of
+ //! removable device like an SD card this function must return zero if
+ //! the SD card is not present.
+ //! The function returns a pointer to data that should be passed to other
+ //! APIs or returns 0 if no drive was found.
+ //
+ void *(*pfnOpen)(uint32_t ui32Drive);
+
+ //*************************************************************************
+ //
+ //! This function closes the drive number in use by the mass storage class
+ //! device. The \e pvDrive is the pointer that was returned from a call to
+ //! \e pfnOpen. This function is used to close the physical drive
+ //! number associated with the parameter \e pvDrive. This function
+ //! returns 0 if the drive was closed successfully and any other value
+ //! indicates a failure.
+ //
+ //*************************************************************************
+ void (*pfnClose)(void *pvDrive);
+
+ //*************************************************************************
+ //
+ //! This function reads a block of data from a device opened by the
+ //! \e pfnOpen call. The \e pvDrive parameter is the pointer that was
+ //! returned from the original call to \e pfnOpen. The \e pui8Data
+ //! parameter is the buffer that data will be written into. The data area
+ //! pointed to by \e pui8Data must be at least \e ui32NumBlocks * Block
+ //! Size bytes to prevent overwriting data. The \e ui32Sector is the block
+ //! address to read and \e ui32NumBlocks is the number of blocks to read.
+ //! This function returns the number of bytes that were read from the
+ //! and placed into the \e pui8Data buffer..
+ //
+ //*************************************************************************
+ uint32_t (*pfnBlockRead)(void *pvDrive, uint8_t *pui8Data,
+ uint32_t ui32Sector, uint32_t ui32NumBlocks);
+
+ //*************************************************************************
+ //
+ //! This function is use to write blocks to a physical device from the
+ //! buffer pointed to by the \e pui8Data buffer. The \e pvDrive parameter
+ //! is the pointer that was returned from the original call to \e pfnOpen.
+ //! The \e pui8Data is the pointer to the data to write to the storage
+ //! device and \e ui32NumBlocks is the number of blocks to write. The
+ //! \e ui32Sector parameter is the sector number used to write the block.
+ //! If the number of blocks is greater than one then the block address
+ //! increments and writes to the next block until
+ //! \e ui32NumBlocks * Block Size bytes are written. This function returns
+ //! the number of bytes that were written to the device.
+ //
+ //*************************************************************************
+ uint32_t (*pfnBlockWrite)(void *pvDrive, uint8_t *pui8Data,
+ uint32_t ui32Sector, uint32_t ui32NumBlocks);
+
+ //*************************************************************************
+ //
+ //! This function returns the total number of blocks on a physical device
+ //! based on the \e pvDrive parameter. The \e pvDrive parameter
+ //! is the pointer that was returned from the original call to \e pfnOpen.
+ //
+ //*************************************************************************
+ uint32_t (*pfnNumBlocks)(void *pvDrive);
+
+ //*************************************************************************
+ //
+ //! This function returns the block size for a physical device based on the
+ //! \e pvDrive parameter. The \e pvDrive parameter is the pointer
+ //! that was returned from the original call to \e pfnOpen.
+ //
+ //*************************************************************************
+ uint32_t (*pfnBlockSize)(void *pvDrive);
+
+}
+tMSCDMedia;
+
+//*****************************************************************************
+//
+// These defines control the default sizes of USB transfers for data and
+// commands.
+//
+//*****************************************************************************
+#define DEVICE_BLOCK_SIZE 512
+
+//*****************************************************************************
+//
+// USBDMSCMediaChange() tUSBDMSCMediaStatus values.
+//
+//*****************************************************************************
+typedef enum
+{
+ eUSBDMSCMediaPresent,
+ eUSBDMSCMediaNotPresent,
+ eUSBDMSCMediaStopped,
+ eUSBDMSCMediaUnknown
+}
+tUSBDMSCMediaStatus;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// mass storage class. The memory for this structure is in the the
+// sPrivateData field in the tUSBDMSCDevice structure passed on
+// USBDMSCInit() and should not be modified by any code outside of the mass
+// storage device code.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // These three values are used to return the current sense data for an
+ // instance of the mass storage class.
+ //
+ uint8_t ui8ErrorCode;
+ uint8_t ui8SenseKey;
+ uint16_t ui16AddSenseCode;
+
+ //
+ // The pointer to the instance returned from the Open call to the media.
+ //
+ void *pvMedia;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // Holds the flag settings for this instance.
+ //
+ uint32_t ui32Flags;
+
+ //
+ // Holds the current media status.
+ //
+ tUSBDMSCMediaStatus iMediaStatus;
+
+ //
+ // MSC block buffer.
+ //
+ uint32_t pui32Buffer[0x1000>>2];
+
+ //
+ // Current number of bytes to transfer.
+ //
+ uint32_t ui32BytesToTransfer;
+
+ //
+ // The LBA for the current transfer.
+ //
+ uint32_t ui32CurrentLBA;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8INEndpoint;
+
+ //
+ // The IN DMA channel.
+ //
+ uint8_t ui8INDMA;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The OUT DMA channel.
+ //
+ uint8_t ui8OUTDMA;
+
+ //
+ // The bulk class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+
+ //
+ // Active SCSI state.
+ //
+ uint8_t ui8SCSIState;
+
+ //
+ // A copy of the DMA instance data used with calls to USBLibDMA functions.
+ //
+ tUSBDMAInstance *psDMAInstance;
+}
+tMSCInstance;
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8MSCInterface array in bytes.
+//
+//*****************************************************************************
+#define MSCINTERFACE_SIZE (23)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Audio Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//
+//*****************************************************************************
+#define COMPOSITE_DMSC_SIZE (MSCINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the mass storage device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! 8 byte vendor string.
+ //
+ const uint8_t pui8Vendor[8];
+
+ //
+ //! 16 byte vendor string.
+ //
+ const uint8_t pui8Product[16];
+
+ //
+ //! 4 byte vendor string.
+ //
+ const uint8_t pui8Version[4];
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1), MSC
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the \e ppStringDescriptors
+ //! array. This must be 1 + ((5 + (num HID strings)) * (num languages)).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! This structure holds the access functions for the media used by this
+ //! instance of the mass storage class device. All of the functions in
+ //! this structure are required to be filled out with valid functions.
+ //
+ const tMSCDMedia sMediaFunctions;
+
+ //
+ //! This is the callback function for various events that occur during
+ //! mass storage class operation.
+ //
+ const tUSBCallback pfnEventCallback;
+
+ //
+ //! The private instance data for this device. This memory
+ //! must remain accessible for as long as the MSC device is in use and
+ //! must not be modified by any code outside the MSC class driver.
+ //
+ tMSCInstance sPrivateData;
+}
+tUSBDMSCDevice;
+
+//*****************************************************************************
+//
+// MSC-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the host has completed other operations and is
+//! no longer accessing the device.
+//
+//*****************************************************************************
+#define USBD_MSC_EVENT_IDLE (USBD_MSC_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This event indicates that the host is reading the storage media.
+//
+//*****************************************************************************
+#define USBD_MSC_EVENT_READING (USBD_MSC_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+//! This event indicates that the host is writing to the storage media.
+//
+//*****************************************************************************
+#define USBD_MSC_EVENT_WRITING (USBD_MSC_EVENT_BASE + 2)
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDMSCInit(uint32_t ui32Index,
+ tUSBDMSCDevice *psMSCDevice);
+extern void *USBDMSCCompositeInit(uint32_t ui32Index,
+ tUSBDMSCDevice *psMSCDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDMSCTerm(void *pvInstance);
+extern void USBDMSCMediaChange(void *pvInstance,
+ tUSBDMSCMediaStatus eMediaStatus);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
|
