summaryrefslogtreecommitdiff
path: root/usblib/device
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2012-10-29 23:08:53 +0200
committerYuval Adam <yuv.adm@gmail.com>2012-10-29 23:08:53 +0200
commitc241dbd7e78c50327781a35d88d9f2db7ff2b271 (patch)
tree2c84fe512c0cd3ee328244bca2f8ed4f9622074d /usblib/device
parent4ba8614c006f9828f0796c140bc3e13c9e67938c (diff)
Added usblib
Diffstat (limited to 'usblib/device')
-rw-r--r--usblib/device/usbdaudio.c1485
-rw-r--r--usblib/device/usbdaudio.h362
-rw-r--r--usblib/device/usbdbulk.c1447
-rw-r--r--usblib/device/usbdbulk.h269
-rw-r--r--usblib/device/usbdcdc.c2972
-rw-r--r--usblib/device/usbdcdc.h353
-rw-r--r--usblib/device/usbdcdesc.c649
-rw-r--r--usblib/device/usbdcomp.c1543
-rw-r--r--usblib/device/usbdcomp.h297
-rw-r--r--usblib/device/usbdconfig.c654
-rw-r--r--usblib/device/usbddfu-rt.c589
-rw-r--r--usblib/device/usbddfu-rt.h163
-rw-r--r--usblib/device/usbdenum.c2900
-rw-r--r--usblib/device/usbdevice.h223
-rw-r--r--usblib/device/usbdevicepriv.h223
-rw-r--r--usblib/device/usbdhandler.c82
-rw-r--r--usblib/device/usbdhid.c2579
-rw-r--r--usblib/device/usbdhid.h974
-rw-r--r--usblib/device/usbdhidkeyb.c1119
-rw-r--r--usblib/device/usbdhidkeyb.h382
-rw-r--r--usblib/device/usbdhidmouse.c843
-rw-r--r--usblib/device/usbdhidmouse.h321
-rw-r--r--usblib/device/usbdmsc.c2130
-rw-r--r--usblib/device/usbdmsc.h391
24 files changed, 22950 insertions, 0 deletions
diff --git a/usblib/device/usbdaudio.c b/usblib/device/usbdaudio.c
new file mode 100644
index 0000000..a1ef199
--- /dev/null
+++ b/usblib/device/usbdaudio.c
@@ -0,0 +1,1485 @@
+//*****************************************************************************
+//
+// usbdaudio.c - USB audio device class driver.
+//
+// Copyright (c) 2009-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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 "driverlib/udma.h"
+#include "usblib/usblib.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
+#define ISOC_OUT_DMA_CHANNEL UDMA_CHANNEL_USBEP1RX
+
+//*****************************************************************************
+//
+// 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 unsigned char g_pAudioDeviceDescriptor[] =
+{
+ 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 unsigned char g_pAudioDescriptor[] =
+{
+ //
+ // 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.
+//
+//*****************************************************************************
+unsigned char g_pIADAudioDescriptor[] =
+{
+
+ 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_pIADAudioDescriptor),
+ g_pIADAudioDescriptor
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const unsigned char g_pAudioControlInterface[] =
+{
+ //
+ // 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_pAudioControlInterface
+ 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 unsigned char g_pAudioStreamInterface[] =
+{
+ //
+ // 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 | USB_EP_TO_INDEX(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_pAudioDescriptor),
+ g_pAudioDescriptor
+};
+
+const tConfigSection g_sAudioStreamInterfaceSection =
+{
+ sizeof(g_pAudioStreamInterface),
+ g_pAudioStreamInterface
+};
+
+const tConfigSection g_sAudioControlInterfaceSection =
+{
+ sizeof(g_pAudioControlInterface),
+ g_pAudioControlInterface
+};
+
+//*****************************************************************************
+//
+// 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(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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_pAudioConfigDescriptors[] =
+{
+ &g_sAudioConfigHeader
+};
+
+//*****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//*****************************************************************************
+static void HandleDisconnect(void *pvInstance);
+static void InterfaceChange(void *pvInstance, unsigned char ucInterface,
+ unsigned char ucAlternateSetting);
+static void ConfigChangeHandler(void *pvInstance, unsigned long ulValue);
+static void DataReceived(void *pvInstance, unsigned long ulInfo);
+static void HandleEndpoints(void *pvInstance, unsigned long ulStatus);
+static void HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest);
+static void HandleDevice(void *pvInstance, unsigned long ulRequest,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The FIFO configuration for USB audio device class.
+//
+//*****************************************************************************
+const tFIFOConfig g_sUSBAudioFIFOConfig =
+{
+ //
+ // IN endpoints.
+ //
+ {
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN }
+ },
+
+ //
+ // OUT endpoints.
+ //
+ {
+ { false, USB_EP_DEV_OUT | USB_EP_DMA_MODE_1 | USB_EP_AUTO_CLEAR },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT }
+ },
+};
+
+//*****************************************************************************
+//
+// The device information structure for the USB Audio device.
+//
+//*****************************************************************************
+tDeviceInfo g_sAudioDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ //
+ // 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
+ },
+ g_pAudioDeviceDescriptor,
+ g_pAudioConfigDescriptors,
+ 0,
+ 0,
+ &g_sUSBAudioFIFOConfig
+};
+
+//*****************************************************************************
+//
+// 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 *pvInstance, unsigned long ulInfo)
+{
+ tAudioInstance *psInst;
+ const tUSBDAudioDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // Make a copy of this pointer for ease of use in this function.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // If there is an update pending and the request was to set a current
+ // value then check which value was set.
+ //
+ if(psInst->usUpdate && (psInst->ucRequest == USB_AC_SET_CUR))
+ {
+ //
+ // Only handling interface requests.
+ //
+ if((psInst->usRequestType & USB_RTYPE_RECIPIENT_M) ==
+ USB_RTYPE_INTERFACE)
+ {
+ if(psInst->usUpdate == VOLUME_CONTROL)
+ {
+ //
+ // Inform the callback of the new volume.
+ //
+ psDevice->pfnCallback(0, USBD_AUDIO_EVENT_VOLUME,
+ psInst->sVolume, 0);
+ }
+ else if(psDevice->psPrivateData->usUpdate == MUTE_CONTROL)
+ {
+ //
+ // Inform the callback of the new data.
+ //
+ psDevice->pfnCallback(0, USBD_AUDIO_EVENT_MUTE, psInst->ucMute,
+ 0);
+ }
+ }
+ psInst->usUpdate = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called to handle the interrupts on the isochronous endpoint
+// for the audio device class.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvInstance, unsigned long ulStatus)
+{
+ unsigned long ulEPStatus;
+ tAudioInstance *psInst;
+ unsigned char *pucData;
+ const tUSBDAudioDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // Make a copy of this pointer for ease of use later in this function.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Make sure this was for the isochronous out endpoint.
+ //
+ if((psInst->sBuffer.pvData != 0) &&
+ (MAP_uDMAChannelModeGet(psInst->ucOUTDMA) == UDMA_MODE_STOP))
+ {
+ //
+ // Save the pointer to the data buffer.
+ //
+ pucData = psInst->sBuffer.pvData;
+
+ //
+ // Clear out the buffer pointer to indicate it is no longer in use.
+ //
+ psInst->sBuffer.pvData = 0;
+
+ //
+ // Inform the callback of the new data.
+ //
+ psInst->sBuffer.pfnCallback(pucData, psInst->sBuffer.ulSize,
+ USBD_AUDIO_EVENT_DATAOUT);
+
+ //
+ // Read out the current endpoint status.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ucOUTEndpoint);
+
+ //
+ // Acknowledge that the data was read, this will not cause a bus
+ // acknowledgment.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, psInst->ucOUTEndpoint, 0);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ucOUTEndpoint,
+ ulEPStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvInstance, unsigned long ulRequest, void *pvRequestData)
+{
+ tAudioInstance *psInst;
+ unsigned char *pucData;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = ((tUSBDAudioDevice *)pvInstance)->psPrivateData;
+
+ //
+ // Create the char array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pucData = (unsigned char *)pvRequestData;
+
+ switch(ulRequest)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the appropriate interface number.
+ //
+ if(pucData[0] == AUDIO_INTERFACE_CONTROL)
+ {
+ psInst->ucInterfaceControl = pucData[1];
+ }
+ else if(pucData[0] == AUDIO_INTERFACE_OUTPUT)
+ {
+ psInst->ucInterfaceAudio = pucData[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((pucData[0] & USB_EP_DESC_IN) == 0)
+ {
+ //
+ // Extract the new endpoint number without the DIR bit.
+ //
+ psInst->ucOUTEndpoint = INDEX_TO_USB_EP(pucData[1] & 0x7f);
+
+ //
+ // Extract the new DMA channel.
+ //
+ psInst->ucOUTDMA = UDMA_CHANNEL_USBEP1RX +
+ (((pucData[1] & 0x7f) - 1) * 2);
+
+ //
+ // Basic configuration for DMA on the OUT endpoint.
+ //
+ MAP_uDMAChannelControlSet(psInst->ucOUTDMA,
+ (UDMA_SIZE_32 | UDMA_SRC_INC_NONE|
+ UDMA_DST_INC_32 | UDMA_ARB_16));
+
+ //
+ // Select this channel for this endpoint, this only affects
+ // devices that have this feature.
+ //
+ MAP_USBEndpointDMAChannel(USB0_BASE, psInst->ucOUTEndpoint,
+ psInst->ucOUTDMA);
+ }
+ 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.
+ //
+ pucData[2] = psInst->ucInterfaceControl;
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvInstance)
+{
+ const tUSBDAudioDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ psDevice->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 *pvInstance, unsigned char ucInterface,
+ unsigned char ucAlternateSetting)
+{
+ const tUSBDAudioDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // Check which interface to change into.
+ //
+ if(ucAlternateSetting == 0)
+ {
+ //
+ // Alternate setting 0 is an inactive state.
+ //
+ if(psDevice->pfnCallback)
+ {
+ psDevice->pfnCallback(0, USBD_AUDIO_EVENT_IDLE, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Alternate setting 1 is the active state.
+ //
+ if(psDevice->pfnCallback)
+ {
+ psDevice->pfnCallback(0, USBD_AUDIO_EVENT_ACTIVE, 0, 0);
+ }
+
+ //
+ // Enable uDMA on the endpoint now that the active configuration
+ // has been selected.
+ //
+ MAP_USBEndpointDMAEnable(USB0_BASE,
+ psDevice->psPrivateData->ucOUTEndpoint,
+ USB_EP_DEV_OUT);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes.
+//
+//*****************************************************************************
+static void
+ConfigChangeHandler(void *pvInstance, unsigned long ulValue)
+{
+ const tUSBDAudioDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psDevice->pfnCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psDevice->pfnCallback(pvInstance, 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 ulIndex is the index of the USB controller to initialize for
+//! audio class device operation.
+//! \param psDevice 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 psDevice 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(unsigned long ulIndex, const tUSBDAudioDevice *psDevice)
+{
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateData);
+
+ USBDAudioCompositeInit(ulIndex, psDevice);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ulIndex, psDevice->psPrivateData->psDevInfo);
+
+ //
+ // Basic configuration for DMA on the OUT endpoint.
+ //
+ MAP_uDMAChannelControlSet(psDevice->psPrivateData->ucOUTDMA,
+ (UDMA_SIZE_32 | UDMA_SRC_INC_NONE|
+ UDMA_DST_INC_32 | UDMA_ARB_16));
+
+ //
+ // Select this channel for this endpoint, this only affects devices that
+ // have this feature.
+ //
+ MAP_USBEndpointDMAChannel(USB0_BASE, psDevice->psPrivateData->ucOUTEndpoint,
+ psDevice->psPrivateData->ucOUTDMA);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the audio class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ulIndex is the index of the USB controller to initialize for
+//! audio class device operation.
+//! \param psDevice 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 psDevice 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 *
+USBDAudioCompositeInit(unsigned long ulIndex, const tUSBDAudioDevice *psDevice)
+{
+ tAudioInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateData);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateData;
+ psInst->psConfDescriptor = (tConfigDescriptor *)g_pAudioDescriptor;
+ psInst->psDevInfo = &g_sAudioDeviceInfo;
+ psInst->ulUSBBase = USB0_BASE;
+
+ //
+ // The Control interface is at index 0.
+ //
+ psInst->ucInterfaceControl = AUDIO_INTERFACE_CONTROL;
+
+ //
+ // The Audio interface is at index 1.
+ //
+ psInst->ucInterfaceAudio = AUDIO_INTERFACE_OUTPUT;
+
+ //
+ // Set the default Isochronous OUT endpoint.
+ //
+ psInst->ucOUTEndpoint = ISOC_OUT_ENDPOINT;
+ psInst->ucOUTDMA = ISOC_OUT_DMA_CHANNEL;
+
+ //
+ // Set the initial buffer to null.
+ //
+ psInst->sBuffer.pvData = 0;
+
+ //
+ // Save the volume settings.
+ //
+ psInst->sVolumeMax = psDevice->sVolumeMax;
+ psInst->sVolumeMin = psDevice->sVolumeMin;
+ psInst->sVolumeStep = psDevice->sVolumeStep;
+
+ //
+ // No update pending to any command.
+ //
+ psInst->usUpdate = 0;
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
+ psDevDesc->idVendor = psDevice->usVID;
+ psDevDesc->idProduct = psDevice->usPID;
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
+ psInst->psConfDescriptor->bMaxPower =
+ (unsigned char)(psDevice->usMaxPowermA / 2);
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psInst->psDevInfo->ulNumStringDescriptors =
+ psDevice->ulNumStringDescriptors;
+ psInst->psDevInfo->pvInstance = (void *)psDevice;
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the audio device.
+//!
+//! \param pvInstance 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 pvInstance instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDAudioTerm(void *pvInstance)
+{
+ ASSERT(pvInstance != 0);
+
+ //
+ // Cleanly exit device mode.
+ //
+ USBDCDTerm(0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvInstance is the instance data for this request.
+// \param pUSBRequest 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned long ulControl;
+ unsigned long ulRecipient;
+ unsigned long ulStall;
+ tAudioInstance *psInst;
+ const tUSBDAudioDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // Make a copy of this pointer for ease of use in this function.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // 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.
+ //
+ ulStall = 0;
+
+ //
+ // Get the request type.
+ //
+ ulRecipient = pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M;
+
+ //
+ // Save the request type and request value.
+ //
+ psInst->usRequestType = pUSBRequest->bmRequestType;
+ psInst->ucRequest = pUSBRequest->bRequest;
+
+ //
+ // Check if this is an endpoint request to the audio streaming endpoint.
+ //
+ if((ulRecipient == USB_RTYPE_ENDPOINT) &&
+ (pUSBRequest->wIndex == USB_EP_TO_INDEX(psInst->ucOUTEndpoint)))
+ {
+ //
+ // Determine the type of request.
+ //
+ switch(psInst->ucRequest)
+ {
+ case USB_AC_SET_CUR:
+ {
+ //
+ // Handle retrieving the sample rate.
+ //
+ if(pUSBRequest->wValue == SAMPLING_FREQ_CONTROL)
+ {
+ //
+ // Retrieve the requested sample rate.
+ //
+ USBDCDRequestDataEP0(0,
+ (unsigned char *)&psInst->ulSampleRate,
+ 3);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->usUpdate = SAMPLING_FREQ_CONTROL;
+ }
+ break;
+ }
+ case USB_AC_GET_CUR:
+ {
+ //
+ // Handle retrieving the sample rate.
+ //
+ if(pUSBRequest->wValue == SAMPLING_FREQ_CONTROL)
+ {
+ //
+ // Send back the current sample rate.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)&psInst->ulSampleRate,
+ 3);
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ break;
+ }
+ }
+ }
+ else if(ulRecipient == USB_RTYPE_INTERFACE)
+ {
+ //
+ // Make sure the request was for the control interface.
+ //
+ if((unsigned char)pUSBRequest->wIndex != psInst->ucInterfaceControl)
+ {
+ return;
+ }
+
+ //
+ // Extract the control value from the message.
+ //
+ ulControl = pUSBRequest->wValue & USB_CS_CONTROL_M;
+
+ //
+ // Handle an audio control request to the feature control unit.
+ //
+ if((AUDIO_CONTROL_ID << 8) == (pUSBRequest->wIndex & USB_CS_CONTROL_M))
+ {
+ //
+ // Determine the type of request.
+ //
+ switch(psInst->ucRequest)
+ {
+ case USB_AC_GET_MAX:
+ {
+ if(ulControl == VOLUME_CONTROL)
+ {
+ //
+ // Return the maximum volume setting.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)&psInst->sVolumeMax,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_MIN:
+ {
+ if(ulControl == VOLUME_CONTROL)
+ {
+ //
+ // Return the minimum volume setting.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)&psInst->sVolumeMin,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_RES:
+ {
+ if(ulControl == VOLUME_CONTROL)
+ {
+ //
+ // Return the volume step setting.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)&psInst->sVolumeStep,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_CUR:
+ {
+ if(ulControl == VOLUME_CONTROL)
+ {
+ //
+ // Send back the current volume level.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)&psInst->sVolume,
+ 2);
+ }
+ else if(ulControl == MUTE_CONTROL)
+ {
+ //
+ // Send back the current mute value.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)&psInst->ucMute, 1);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ }
+ break;
+ }
+ case USB_AC_SET_CUR:
+ {
+ if(ulControl == VOLUME_CONTROL)
+ {
+ //
+ // Read the new volume level.
+ //
+ USBDCDRequestDataEP0(0,
+ (unsigned char *)&psInst->sVolume,
+ 2);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->usUpdate = VOLUME_CONTROL;
+ }
+ else if(ulControl == MUTE_CONTROL)
+ {
+ //
+ // Read the new mute setting.
+ //
+ USBDCDRequestDataEP0(0,
+ (unsigned char *)&psInst->ucMute,
+ 1);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->usUpdate = MUTE_CONTROL;
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ }
+ break;
+ }
+ case USB_AC_SET_RES:
+ {
+ if(ulControl == VOLUME_CONTROL)
+ {
+ //
+ // Read the new volume step setting.
+ //
+ USBDCDRequestDataEP0(0,
+ (unsigned char *)&psInst->sVolumeStep, 2);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->usUpdate = VOLUME_CONTROL;
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ulStall = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Stall on all unknown commands.
+ //
+ if(ulStall)
+ {
+ USBDCDStallEP0(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to supply buffers to the audio class to be filled
+//! from the USB host device.
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDAudioInit() or USBDAudioInitComposite().
+//! \param pvBuffer is a pointer to the buffer to fill with audio data.
+//! \param ulSize is the size in bytes of the buffer pointed to by the 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 ulSize one packet of data from the host controller. The ulSize
+//! 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.
+//
+//*****************************************************************************
+long
+USBAudioBufferOut(void *pvInstance, void *pvBuffer, unsigned long ulSize,
+ tUSBAudioBufferCallback pfnCallback)
+{
+ tAudioInstance *psInst;
+ const tUSBDAudioDevice *psDevice;
+
+ //
+ // Make sure we were not passed NULL pointers.
+ //
+ ASSERT(pvInstance != 0);
+ ASSERT(pvBuffer != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDAudioDevice *)pvInstance;
+
+ //
+ // Buffer must be at least one packet in size.
+ //
+ ASSERT(ulSize >= ISOC_OUT_EP_MAX_SIZE);
+ ASSERT(pfnCallback);
+
+ //
+ // Create a pointer of the correct type from the private pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Initialize the buffer instance.
+ //
+ psInst->sBuffer.pvData = pvBuffer;
+ psInst->sBuffer.ulSize = ulSize;
+ psInst->sBuffer.ulNumBytes = 0;
+ psInst->sBuffer.pfnCallback = pfnCallback;
+
+ //
+ // Configure and enable DMA for the OUT transfer.
+ //
+ MAP_uDMAChannelTransferSet(psInst->ucOUTDMA, UDMA_MODE_BASIC,
+ (void *)USBFIFOAddrGet(USB0_BASE,
+ psInst->ucOUTEndpoint),
+ psInst->sBuffer.pvData, ulSize >> 2);
+
+ //
+ // Start the DMA transfer.
+ //
+ MAP_uDMAChannelEnable(psInst->ucOUTDMA);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/usblib/device/usbdaudio.h b/usblib/device/usbdaudio.h
new file mode 100644
index 0000000..4406597
--- /dev/null
+++ b/usblib/device/usbdaudio.h
@@ -0,0 +1,362 @@
+//*****************************************************************************
+//
+// usbdaudio.h - USB audio device class driver.
+//
+// Copyright (c) 2009-2012 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 9453 of the Stellaris 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, unsigned long ulParam,
+ unsigned long ulEvent);
+
+//*****************************************************************************
+//
+// 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 psPrivateData field in the tUSBDAudioDevice structure passed on
+// USBDAudioInit() and should not be modified by any code outside of the audio
+// device.
+//
+//*****************************************************************************
+typedef struct
+{
+ unsigned long ulUSBBase;
+ tDeviceInfo *psDevInfo;
+ tConfigDescriptor *psConfDescriptor;
+
+ //
+ // The maximum volume expressed as an 8.8 signed value.
+ //
+ short sVolumeMax;
+
+ //
+ // The minimum volume expressed as an 8.8 signed value.
+ //
+ short sVolumeMin;
+
+ //
+ // The minimum volume step expressed as an 8.8 signed value.
+ //
+ short sVolumeStep;
+
+ struct
+ {
+ //
+ // Pointer to a buffer provided by caller.
+ //
+ void *pvData;
+
+ //
+ // Size of the data area provided in pvData in bytes.
+ //
+ unsigned long ulSize;
+
+ //
+ // Number of valid bytes copied into the pvData area.
+ //
+ unsigned long ulNumBytes;
+
+ //
+ // The buffer callback for this function.
+ //
+ tUSBAudioBufferCallback pfnCallback;
+ } sBuffer;
+
+ //
+ // Pending request type.
+ //
+ unsigned short usRequestType;
+
+ //
+ // Pending request.
+ //
+ unsigned char ucRequest;
+
+ //
+ // Pending update value.
+ //
+ unsigned short usUpdate;
+
+ //
+ // Current Volume setting.
+ //
+ short sVolume;
+
+ //
+ // Current Mute setting.
+ //
+ unsigned char ucMute;
+
+ //
+ // Current Sample rate, this is not writable but the host will try.
+ //
+ unsigned long ulSampleRate;
+
+ //
+ // The OUT endpoint in use by this instance.
+ //
+ unsigned char ucOUTEndpoint;
+
+ //
+ // The OUT endpoint DMA channel in use by this instance.
+ //
+ unsigned char ucOUTDMA;
+
+ //
+ // The control interface number associated with this instance.
+ //
+ unsigned char ucInterfaceControl;
+
+ //
+ // The audio interface number associated with this instance.
+ //
+ unsigned char ucInterfaceAudio;
+}
+tAudioInstance;
+
+//*****************************************************************************
+//
+//! This is the size in bytes of the private data for the device audio class.
+//
+//*****************************************************************************
+#define USB_AUDIO_INSTANCE_SIZE sizeof(tAudioInstance);
+
+//*****************************************************************************
+//
+//! 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.
+//
+// This value must be at least sizeof(g_pIADAudioDescriptor) +
+// sizeof(g_pAudioControlInterface) +
+// sizeof(g_sAudioStreamInterfaceSection)
+//
+//*****************************************************************************
+#define COMPOSITE_DAUDIO_SIZE (8 + 52 + 52)
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! 8 byte vendor string.
+ //
+ unsigned char pucVendor[8];
+
+ //
+ //! 16 byte vendor string.
+ //
+ unsigned char pucProduct[16];
+
+ //
+ //! 4 byte vendor string.
+ //
+ unsigned char pucVersion[4];
+
+ //
+ //! The maximum power consumption of the device, expressed in mA.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the audio
+ //! device.
+ //
+ 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (number of strings)) *
+ //! (number of languages)).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! The maximum volume expressed as an 8.8 signed value.
+ //
+ short sVolumeMax;
+
+ //
+ //! The minimum volume expressed as an 8.8 signed value.
+ //
+ short sVolumeMin;
+
+ //
+ //! The minimum volume step expressed as an 8.8 signed value.
+ //
+ short sVolumeStep;
+
+ //
+ //! A pointer to private instance data for the audio device. This memory
+ //! must remain accessible for as long as the audio device is in use and
+ //! must not be modified by any code outside the audio class driver.
+ //
+ tAudioInstance *psPrivateData;
+}
+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 ulParam 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 occured. The
+//! \e ulParam 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 occured. The
+//! \e ulParam 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)
+
+extern tDeviceInfo g_sAudioDeviceInfo;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDAudioInit(unsigned long ulIndex,
+ const tUSBDAudioDevice *psAudioDevice);
+extern void *USBDAudioCompositeInit(unsigned long ulIndex,
+ const tUSBDAudioDevice *psAudioDevice);
+extern void USBDAudioTerm(void *pvInstance);
+extern long USBAudioBufferOut(void *pvInstance, void *pvBuffer,
+ unsigned long ulSize,
+ 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..f623516
--- /dev/null
+++ b/usblib/device/usbdbulk.c
@@ -0,0 +1,1447 @@
+//*****************************************************************************
+//
+// usbdbulk.c - USB bulk device class driver.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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/device/usbdevice.h"
+#include "usblib/device/usbdbulk.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 usDeferredOpFlags 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->usDeferredOpFlags to indicate that the operation is pending.
+//
+//*****************************************************************************
+#define BULK_DO_PACKET_RX 5
+
+//*****************************************************************************
+//
+// Macros to convert between USB controller base address and an index. These
+// are currently trivial but are included to allow for the possibility of
+// supporting more than one controller in the future.
+//
+//*****************************************************************************
+#define USB_BASE_TO_INDEX(BaseAddr) (0)
+#define USB_INDEX_TO_BASE(Index) (USB0_BASE)
+
+//*****************************************************************************
+//
+// 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 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 DATA_IN_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
+#define DATA_OUT_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(DATA_IN_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.
+//
+//*****************************************************************************
+unsigned char g_pBulkDeviceDescriptor[] =
+{
+ 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.
+//
+//*****************************************************************************
+unsigned char g_pBulkDescriptor[] =
+{
+ //
+ // 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 unsigned char g_pBulkInterface[] =
+{
+ //
+ // 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 | USB_EP_TO_INDEX(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 | USB_EP_TO_INDEX(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 serial config 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_pBulkDescriptor),
+ g_pBulkDescriptor
+};
+
+const tConfigSection g_sBulkInterfaceSection =
+{
+ sizeof(g_pBulkInterface),
+ g_pBulkInterface
+};
+
+//*****************************************************************************
+//
+// 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(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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_pBulkConfigDescriptors[] =
+{
+ &g_sBulkConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleConfigChange(void *pvInstance, unsigned long ulInfo);
+static void HandleDisconnect(void *pvInstance);
+static void HandleEndpoints(void *pvInstance, unsigned long ulStatus);
+static void HandleSuspend(void *pvInstance);
+static void HandleResume(void *pvInstance);
+static void HandleDevice(void *pvInstance, unsigned long ulRequest,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB serial device.
+//
+//*****************************************************************************
+tDeviceInfo g_sBulkDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ 0, // GetDescriptor
+ 0, // RequestHandler
+ 0, // InterfaceChange
+ HandleConfigChange, // ConfigChange
+ 0, // DataReceived
+ 0, // DataSentCallback
+ 0, // ResetHandler
+ HandleSuspend, // SuspendHandler
+ HandleResume, // ResumeHandler
+ HandleDisconnect, // DisconnectHandler
+ HandleEndpoints, // EndpointHandler
+ HandleDevice // Device handler.
+ },
+ g_pBulkDeviceDescriptor,
+ g_pBulkConfigDescriptors,
+ 0, // Will be completed during USBDBulkInit().
+ 0, // Will be completed during USBDBulkInit().
+ &g_sUSBDefaultFIFOConfig
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pusDeferredOp points to the flags variable which is to be modified.
+// \param usBit 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 unsigned short *pusDeferredOp, unsigned short usBit,
+ tBoolean bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pusDeferredOp, usBit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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 tBoolean
+ProcessDataFromHost(const tUSBDBulkDevice *psDevice, unsigned long ulStatus)
+{
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+ tBulkInstance *psInst;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateBulkData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ucOUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ucOUTEndpoint, ulEPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ulEPStatus & 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 signaled later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, BULK_DO_PACKET_RX, true);
+
+ //
+ // How big is the packet we've just been sent?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ //
+ // 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.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ulSize,
+ (void *)0);
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ulEPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ulEPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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 tBoolean
+ProcessDataToHost(const tUSBDBulkDevice *psDevice, unsigned long ulStatus)
+{
+ tBulkInstance *psInst;
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateBulkData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase, psInst->ucINEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucINEndpoint,
+ ulEPStatus);
+
+ //
+ // Our last transmission completed. Clear our state back to idle and
+ // see if we need to send any more data.
+ //
+ psInst->eBulkTxState = BULK_STATE_IDLE;
+
+ //
+ // Notify the client that the last transmission completed.
+ //
+ ulSize = psInst->usLastTxSize;
+ psInst->usLastTxSize = 0;
+ psDevice->pfnTxCallback(psDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
+ ulSize, (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 ulStatus.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvInstance, unsigned long ulStatus)
+{
+ const tUSBDBulkDevice *psBulkInst;
+ tBulkInstance *psInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ulIndex is different in both cases.
+ //
+ psBulkInst = (const tUSBDBulkDevice *)pvInstance;
+ psInst = psBulkInst->psPrivateBulkData;
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucOUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(pvInstance, ulStatus);
+ }
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucINEndpoint)))
+ {
+ ProcessDataToHost(pvInstance, ulStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvInstance, unsigned long ulInfo)
+{
+ tBulkInstance *psInst;
+ const tUSBDBulkDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psDevice = (const tUSBDBulkDevice *)pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateBulkData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->eBulkRxState = BULK_STATE_IDLE;
+ psInst->eBulkTxState = BULK_STATE_IDLE;
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psDevice->pfnRxCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_CONNECTED, 0,
+ (void *)0);
+ }
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvInstance, unsigned long ulRequest, void *pvRequestData)
+{
+ tBulkInstance *psInst;
+ unsigned char *pucData;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
+
+ //
+ // Create the char array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pucData = (unsigned char *)pvRequestData;
+
+ switch(ulRequest)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ucInterface = pucData[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(pucData[0] & USB_EP_DESC_IN)
+ {
+ psInst->ucINEndpoint = INDEX_TO_USB_EP((pucData[1] & 0x7f));
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ucOUTEndpoint = INDEX_TO_USB_EP(pucData[1] & 0x7f);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvInstance)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+ tBulkInstance *psInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psBulkDevice->psPrivateBulkData;
+
+ //
+ // 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 *pvInstance)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvInstance;
+
+ //
+ // 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 *pvInstance)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvInstance;
+
+ //
+ // 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 ulIndex is the index of the USB controller for which this tick
+// is being generated.
+// \param ulTimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+BulkTickHandler(void *pvInstance, unsigned long ulTimemS)
+{
+ tBulkInstance *psInst;
+ unsigned long ulSize;
+ const tUSBDBulkDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDBulkDevice *)pvInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateBulkData;
+
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->usDeferredOpFlags & (1 << BULK_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ //
+ // Tell the client that there is a packet waiting for it.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_RX_AVAILABLE,
+ ulSize, (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes bulk device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for bulk device operation.
+//! \param psDevice 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 psDevice 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
+//! 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 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 the psDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDBulkInit(unsigned long ulIndex, const tUSBDBulkDevice *psDevice)
+{
+ void *pvInstance;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+
+ pvInstance = USBDBulkCompositeInit(ulIndex, psDevice);
+
+ if(pvInstance)
+ {
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ulIndex, psDevice->psPrivateBulkData->psDevInfo);
+ }
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return(pvInstance);
+}
+
+//*****************************************************************************
+//
+//! Initializes bulk device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for bulk device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the bulk 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.
+//!
+//! \return Returns zero on failure or a non-zero value that should be
+//! used with the remaining USB HID Bulk APIs.
+//
+//*****************************************************************************
+void *
+USBDBulkCompositeInit(unsigned long ulIndex, const tUSBDBulkDevice *psDevice)
+{
+ tBulkInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateBulkData);
+ ASSERT(psDevice->pfnRxCallback);
+ ASSERT(psDevice->pfnTxCallback);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateBulkData;
+ psInst->psConfDescriptor = (tConfigDescriptor *)g_pBulkDescriptor;
+ psInst->psDevInfo = &g_sBulkDeviceInfo;
+ psInst->ulUSBBase = USB0_BASE;
+ psInst->eBulkRxState = BULK_STATE_UNCONFIGURED;
+ psInst->eBulkTxState = BULK_STATE_UNCONFIGURED;
+ psInst->usDeferredOpFlags = 0;
+ psInst->bConnected = false;
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ucINEndpoint = DATA_IN_ENDPOINT;
+ psInst->ucOUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ucInterface = 0;
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
+ psDevDesc->idVendor = psDevice->usVID;
+ psDevDesc->idProduct = psDevice->usPID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
+ psInst->psConfDescriptor->bMaxPower =
+ (unsigned char)(psDevice->usMaxPowermA / 2);
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psInst->psDevInfo->ulNumStringDescriptors
+ = psDevice->ulNumStringDescriptors;
+
+ //
+ // Set the device instance.
+ //
+ psInst->psDevInfo->pvInstance = (void *)psDevice;
+
+ //
+ // 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 *)psDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! Shut down the bulk device.
+//!
+//! \param pvInstance 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 pvInstance instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDBulkTerm(void *pvInstance)
+{
+ tBulkInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USB_BASE_TO_INDEX(psInst->ulUSBBase));
+
+ psInst->ulUSBBase = 0;
+ psInst->psDevInfo = (tDeviceInfo *)0;
+ psInst->psConfDescriptor = (tConfigDescriptor *)0;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the receive channel
+//! callback.
+//!
+//! \param pvInstance 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 pvInstance structure passed to USBDBulkInit() 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 receive callback.
+//
+//*****************************************************************************
+void *
+USBDBulkSetRxCBData(void *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDBulkDevice *)pvInstance)->pvRxCBData;
+ ((tUSBDBulkDevice *)pvInstance)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the transmit callback.
+//!
+//! \param pvInstance 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 pvInstance structure passed to USBDBulkInit() 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 transmit callback.
+//
+//*****************************************************************************
+void *
+USBDBulkSetTxCBData(void *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback pointer for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDBulkDevice *)pvInstance)->pvTxCBData;
+ ((tUSBDBulkDevice *)pvInstance)->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 pvInstance is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pcData points to the first byte of data which is to be transmitted.
+//! \param ulLength 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
+//! 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 ulLength 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.
+//
+//*****************************************************************************
+unsigned long
+USBDBulkPacketWrite(void *pvInstance, unsigned char *pcData,
+ unsigned long ulLength, tBoolean bLast)
+{
+ tBulkInstance *psInst;
+ long lRetcode;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
+
+ //
+ // Can we send the data provided?
+ //
+ if((ulLength > DATA_IN_EP_MAX_SIZE) ||
+ (psInst->eBulkTxState != BULK_STATE_IDLE))
+ {
+ //
+ // 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.
+ //
+ lRetcode = MAP_USBEndpointDataPut(psInst->ulUSBBase, psInst->ucINEndpoint,
+ pcData, ulLength);
+
+ //
+ // Did we copy the data successfully?
+ //
+ if(lRetcode != -1)
+ {
+ //
+ // Remember how many bytes we sent.
+ //
+ psInst->usLastTxSize += (unsigned short)ulLength;
+
+ //
+ // 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->eBulkTxState = BULK_STATE_WAIT_DATA;
+ lRetcode = MAP_USBEndpointDataSend(psInst->ulUSBBase,
+ psInst->ucINEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(lRetcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ulLength);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we couldn't send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the bulk data
+//! interface.
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pcData points to a buffer into which the received data will be
+//! written.
+//! \param ulLength is the size of the buffer pointed to by pcData.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to \e ulLength 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.
+//
+//*****************************************************************************
+unsigned long
+USBDBulkPacketRead(void *pvInstance, unsigned char *pcData,
+ unsigned long ulLength, tBoolean bLast)
+{
+ unsigned long ulEPStatus, ulCount, ulPkt;
+ tBulkInstance *psInst;
+ long lRetcode;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ if(ulEPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // How many bytes are available for us to receive?
+ //
+ ulPkt = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ulCount = ulLength;
+ lRetcode = MAP_USBEndpointDataGet(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint,
+ pcData, &ulCount);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ulCount == ulPkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint,
+ ulEPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, psInst->ucOUTEndpoint,
+ true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, BULK_DO_PACKET_RX,
+ false);
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(lRetcode != -1)
+ {
+ return(ulCount);
+ }
+ }
+
+ //
+ // 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 pvInstance 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.
+//
+//*****************************************************************************
+unsigned long
+USBDBulkTxPacketAvailable(void *pvInstance)
+{
+ tBulkInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->eBulkTxState != BULK_STATE_IDLE)
+ {
+ //
+ // 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 pvInstance 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.
+//
+//*****************************************************************************
+unsigned long
+USBDBulkRxPacketAvailable(void *pvInstance)
+{
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+ tBulkInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ if(ulEPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ return(ulSize);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvInstance is the pointer to the bulk device instance structure.
+//! \param ucPower 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 *pvInstance, unsigned char ucPower)
+{
+ ASSERT(pvInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ucPower);
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvInstance 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.
+//
+//*****************************************************************************
+tBoolean
+USBDBulkRemoteWakeupRequest(void *pvInstance)
+{
+ ASSERT(pvInstance);
+
+ //
+ // 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..abfe85f
--- /dev/null
+++ b/usblib/device/usbdbulk.h
@@ -0,0 +1,269 @@
+//*****************************************************************************
+//
+// usbdcdc.h - USBLib support for a generic bulk device.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris 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
+{
+ //
+ // Unconfigured.
+ //
+ BULK_STATE_UNCONFIGURED,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ BULK_STATE_IDLE,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ BULK_STATE_WAIT_DATA,
+
+ //
+ // Waiting for client to process data.
+ //
+ BULK_STATE_WAIT_CLIENT
+} tBulkState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// Bulk only example device. The memory for this structure is pointed to by
+// the psPrivateBulkData field in the tUSBDBulkDevice structure passed on
+// USBDBulkInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ unsigned long ulUSBBase;
+ tDeviceInfo *psDevInfo;
+ tConfigDescriptor *psConfDescriptor;
+ volatile tBulkState eBulkRxState;
+ volatile tBulkState eBulkTxState;
+ volatile unsigned short usDeferredOpFlags;
+ unsigned short usLastTxSize;
+ volatile tBoolean bConnected;
+ unsigned char ucINEndpoint;
+ unsigned char ucOUTEndpoint;
+ unsigned char ucInterface;
+}
+tBulkInstance;
+
+#ifndef DEPRECATED
+//*****************************************************************************
+//
+// The number of bytes of workspace required by the bulk device class driver.
+// The client must provide a block of RAM of at least this size in the
+// tBulkInstance field of the tUSBBulkDevice structure passed on USBDBulkInit.
+//
+// This value is deprecated and should not be used, any new code should just
+// pass in a tBulkInstance structure in the psPrivateBulkData field.
+//
+//*****************************************************************************
+#define USB_BULK_WORKSPACE_SIZE (sizeof(tBulkInstance))
+#endif
+
+//*****************************************************************************
+//
+//! 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.
+//
+// For reference this is sizeof(g_sCDCSerIfaceHeaderSectionNOINT) +
+// sizeof(g_sCDCSerInterfaceSection) + sizeof(g_sCDCSerIfaceEndpointsNOINT)
+//
+//*****************************************************************************
+#define COMPOSITE_DBULK_SIZE (23)
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data receive channel.
+ //
+ 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.
+ //
+ 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors array.
+ //! This must be 1 + (5 * number of supported languages).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! A pointer to private instance data for this device. This memory must
+ //! remain accessible for as long as the bulk device is in use and must not
+ //! be modified by any code outside the bulk class driver.
+ //
+ tBulkInstance *psPrivateBulkData;
+}
+tUSBDBulkDevice;
+
+extern tDeviceInfo g_sBulkDeviceInfo;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDBulkInit(unsigned long ulIndex,
+ const tUSBDBulkDevice *psDevice);
+extern void *USBDBulkCompositeInit(unsigned long ulIndex,
+ const tUSBDBulkDevice *psDevice);
+extern void USBDBulkTerm(void *pvInstance);
+extern void *USBDBulkSetRxCBData(void *pvInstance, void *pvCBData);
+extern void *USBDBulkSetTxCBData(void *pvInstance, void *pvCBData);
+extern unsigned long USBDBulkPacketWrite(void *pvInstance,
+ unsigned char *pcData,
+ unsigned long ulLength,
+ tBoolean bLast);
+extern unsigned long USBDBulkPacketRead(void *pvInstance,
+ unsigned char *pcData,
+ unsigned long ulLength,
+ tBoolean bLast);
+extern unsigned long USBDBulkTxPacketAvailable(void *pvInstance);
+extern unsigned long USBDBulkRxPacketAvailable(void *pvInstance);
+extern void USBDBulkPowerStatusSet(void *pvInstance, unsigned char ucPower);
+extern tBoolean USBDBulkRemoteWakeupRequest(void *pvInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// 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..f25b4bc
--- /dev/null
+++ b/usblib/device/usbdcdc.c
@@ -0,0 +1,2972 @@
+//*****************************************************************************
+//
+// usbdcdc.c - USB CDC ACM (serial) device class driver.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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 usDeferredOpFlags 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))
+
+//*****************************************************************************
+//
+// Macros to convert between USB controller base address and an index. These
+// are currently trivial but are included to allow for the possibility of
+// supporting more than one controller in the future.
+//
+//*****************************************************************************
+#define USB_BASE_TO_INDEX(BaseAddr) (0)
+#define USB_INDEX_TO_BASE(Index) (USB0_BASE)
+
+//*****************************************************************************
+//
+// 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 USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
+#define DATA_OUT_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
+#define CTL_IN_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(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.
+//
+//*****************************************************************************
+unsigned char g_pCDCSerDeviceDescriptor[] =
+{
+ 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.
+//
+//*****************************************************************************
+unsigned char g_pCDCSerDescriptor[] =
+{
+ //
+ // 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_pCDCSerDescriptor),
+ g_pCDCSerDescriptor
+};
+
+//*****************************************************************************
+//
+// This is the Interface Association Descriptor for the serial device used in
+// composite devices.
+//
+//*****************************************************************************
+unsigned char g_pIADSerDescriptor[] =
+{
+
+ 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_pIADSerDescriptor),
+ g_pIADSerDescriptor
+};
+
+//*****************************************************************************
+//
+// This is the control interface for the serial device.
+//
+//*****************************************************************************
+const unsigned char g_pCDCSerCommInterface[] =
+{
+ //
+ // 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 | USB_EP_TO_INDEX(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_pCDCSerCommInterface),
+ g_pCDCSerCommInterface
+};
+
+//*****************************************************************************
+//
+// This is the Data interface for the serial device.
+//
+//*****************************************************************************
+const unsigned char g_pCDCSerDataInterface[] =
+{
+ //
+ // 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 | USB_EP_TO_INDEX(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 | USB_EP_TO_INDEX(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_pCDCSerDataInterface),
+ g_pCDCSerDataInterface
+};
+
+//*****************************************************************************
+//
+// 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(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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_pCDCSerConfigDescriptors[] =
+{
+ &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 *pvInstance, tUSBRequest *pUSBRequest);
+static void HandleConfigChange(void *pvInstance, unsigned long ulInfo);
+static void HandleEP0Data(void *pvInstance, unsigned long ulDataSize);
+static void HandleDisconnect(void *pvInstance);
+static void HandleEndpoints(void *pvInstance, unsigned long ulStatus);
+static void HandleSuspend(void *pvInstance);
+static void HandleResume(void *pvInstance);
+static void HandleDevice(void *pvInstance, unsigned long ulRequest,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB serial device.
+//
+//*****************************************************************************
+tDeviceInfo g_sCDCSerDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ //
+ // 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
+ },
+
+ //
+ // The common device descriptor.
+ //
+ g_pCDCSerDeviceDescriptor,
+
+ //
+ // Default to no interrupt endpoint.
+ //
+ g_pCDCCompSerConfigDescriptors,
+
+ //
+ // String descriptors will be passed in.
+ //
+ 0,
+ 0,
+
+ //
+ // Use the default USB FIFO configuration.
+ //
+ &g_sUSBDefaultFIFOConfig,
+
+ //
+ // Zero out the instance pointer by default.
+ //
+ 0
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pusDeferredOp points to the flags variable which is to be modified.
+// \param usBit 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 unsigned short *pusDeferredOp,
+ unsigned short usBit, tBoolean bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pusDeferredOp, usBit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// Determines whether or not a client has consumed all received data previously
+// passed to it.
+//
+//! \param psDevice 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 tBoolean
+DeviceConsumedAllData(const tUSBDCDCDevice *psDevice)
+{
+ unsigned long ulRemaining;
+
+ //
+ // Send the device an event requesting that it tell us how many bytes
+ // of data it still has to process.
+ //
+ ulRemaining = psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_DATA_REMAINING, 0, (void *)0);
+
+ //
+ // If any data remains to be processed, return false, else return true.
+ //
+ return(ulRemaining ? false : true);
+}
+
+//*****************************************************************************
+//
+// Notifies the client that it should set or clear a break condition.
+//
+// \param psDevice 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(const tUSBDCDCDevice *psDevice, tBoolean bSend)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // 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->usDeferredOpFlags, CDC_DO_SEND_BREAK, false);
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_CLEAR_BREAK, bSend);
+
+ //
+ // Tell the client to start or stop sending the break.
+ //
+ psDevice->pfnControlCallback(psDevice->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 psDevice 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(const tUSBDCDCDevice *psDevice)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Clear the flag we use to tell ourselves that the line coding change has
+ // yet to be notified to the client.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_LINE_CODING_CHANGE,
+ false);
+
+ //
+ // Tell the client to update their serial line coding parameters.
+ //
+ psDevice->pfnControlCallback(psDevice->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 psDevice 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(const tUSBDCDCDevice *psDevice)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Clear the flag we use to tell ourselves that the line coding change has
+ // yet to be notified to the client.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_LINE_STATE_CHANGE,
+ false);
+
+ //
+ // Tell the client to update their serial line coding parameters.
+ //
+ psDevice->pfnControlCallback(psDevice->pvControlCBData,
+ USBD_CDC_EVENT_SET_CONTROL_LINE_STATE,
+ psInst->usControlLineState,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a break request if no data remains to be processed.
+//
+// \param psDevice 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 tBoolean
+CheckAndSendBreak(const tUSBDCDCDevice *psDevice, unsigned short usDuration)
+{
+ tBoolean bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the break request on to the client since no data remains to be
+ // consumed.
+ //
+ SendBreak(psDevice, (usDuration ? 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 psDevice 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 tBoolean
+CheckAndSendLineCodingChange(const tUSBDCDCDevice *psDevice)
+{
+ tBoolean bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the request on to the client since no data remains to be
+ // consumed.
+ //
+ SendLineCodingChange(psDevice);
+ }
+
+ //
+ // 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 psDevice 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 tBoolean
+CheckAndSendLineStateChange(const tUSBDCDCDevice *psDevice)
+{
+ tBoolean bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the request on to the client since no data remains to be
+ // consumed.
+ //
+ SendLineStateChange(psDevice);
+ }
+
+ //
+ // 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 tBoolean
+SendSerialState(const tUSBDCDCDevice *psDevice)
+{
+ tUSBRequest sRequest;
+ unsigned short usSerialState;
+ tCDCSerInstance *psInst;
+ long lRetcode;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Remember that we are in the middle of sending a notification.
+ //
+ psInst->eCDCInterruptState = CDC_STATE_WAIT_DATA;
+
+ //
+ // Clear the flag we use to indicate that a send is required.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
+ false);
+ //
+ // Take a snapshot of the serial state.
+ //
+ usSerialState = psInst->usSerialState;
+
+ //
+ // 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.
+ //
+ lRetcode = MAP_USBEndpointDataPut(psInst->ulUSBBase,
+ psInst->ucControlEndpoint,
+ (unsigned char *)&sRequest,
+ sizeof(tUSBRequest));
+ lRetcode = MAP_USBEndpointDataPut(psInst->ulUSBBase, psInst->ucControlEndpoint,
+ (unsigned char *)&usSerialState,
+ USB_CDC_NOTIFY_SERIAL_STATE_SIZE);
+
+ //
+ // Did we correctly write the data to the endpoint FIFO?
+ //
+ if(lRetcode != -1)
+ {
+ //
+ // We put the data into the FIFO so now schedule it to be
+ // sent.
+ //
+ lRetcode = MAP_USBEndpointDataSend(psInst->ulUSBBase,
+ psInst->ucControlEndpoint,
+ USB_TRANS_IN);
+ }
+
+ //
+ // If an error occurred, mark the endpoint as idle (to prevent possible
+ // lockup) and return an error.
+ //
+ if(lRetcode == -1)
+ {
+ psInst->eCDCInterruptState = CDC_STATE_IDLE;
+ return(false);
+ }
+ else
+ {
+ //
+ // Everything went fine. Clear the error bits that we just notified
+ // and return true.
+ //
+ psInst->usSerialState &= ~(usSerialState & USB_CDC_SERIAL_ERRORS);
+ return(true);
+ }
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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.
+//
+//*****************************************************************************
+tBoolean
+ProcessDataFromHost(const tUSBDCDCDevice *psDevice, unsigned long ulStatus)
+{
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucBulkOUTEndpoint,
+ ulEPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ulEPStatus & 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->usDeferredOpFlags, CDC_DO_PACKET_RX, true);
+
+ //
+ // Is the receive channel currently blocked?
+ //
+ if(!psInst->bControlBlocked && !psInst->bRxBlocked)
+ {
+ //
+ // How big is the packet we've just been sent?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ //
+ // 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.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ulSize,
+ (void *)0);
+ }
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ulEPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ulEPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to interrupt messages sent to the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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.
+//
+//*****************************************************************************
+tBoolean
+ProcessNotificationToHost(const tUSBDCDCDevice *psDevice,
+ unsigned long ulStatus)
+{
+ unsigned long ulEPStatus;
+ tCDCSerInstance *psInst;
+ tBoolean bRetcode;
+
+ //
+ // Assume all will go well until we have reason to believe otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucControlEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase,
+ psInst->ucControlEndpoint, ulEPStatus);
+
+ //
+ // Did the state change while we were waiting for the previous notification
+ // to complete?
+ //
+ if(psInst->usDeferredOpFlags & (1 << CDC_DO_SERIAL_STATE_CHANGE))
+ {
+ //
+ // The state changed while we were waiting so we need to schedule
+ // another notification immediately.
+ //
+ bRetcode = SendSerialState(psDevice);
+ }
+ else
+ {
+ //
+ // Our last notification completed and we didn't have any new
+ // notifications to make so the interrupt channel is now idle again.
+ //
+ psInst->eCDCInterruptState = CDC_STATE_IDLE;
+ }
+
+ //
+ // Tell the caller how things went.
+ //
+ return(bRetcode);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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.
+//
+//*****************************************************************************
+tBoolean
+ProcessDataToHost(const tUSBDCDCDevice *psDevice, unsigned long ulStatus)
+{
+ tCDCSerInstance *psInst;
+ unsigned long ulEPStatus, ulSize;
+ tBoolean bSentFullPacket;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucBulkINEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase,
+ psInst->ucBulkINEndpoint, ulEPStatus);
+
+ //
+ // Our last transmission completed. Clear our state back to idle and
+ // see if we need to send any more data.
+ //
+ psInst->eCDCTxState = CDC_STATE_IDLE;
+
+ //
+ // If this notification isn't 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->usLastTxSize)
+ {
+ //
+ // Have we just sent a 64 byte packet?
+ //
+ bSentFullPacket = (psInst->usLastTxSize == DATA_IN_EP_MAX_SIZE) ?
+ true : false;
+
+ //
+ // Notify the client that the last transmission completed.
+ //
+ ulSize = (unsigned long)psInst->usLastTxSize;
+ psInst->usLastTxSize = 0;
+ psDevice->pfnTxCallback(psDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
+ ulSize, (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->usLastTxSize)
+ {
+ //
+ // We can expect another transmit complete notification after doing
+ // this.
+ //
+ psInst->eCDCTxState = CDC_STATE_WAIT_DATA;
+
+ //
+ // Send the zero-length packet.
+ //
+ MAP_USBEndpointDataSend(psInst->ulUSBBase,
+ psInst->ucBulkINEndpoint,
+ 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 ulStatus.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvInstance, unsigned long ulStatus)
+{
+ const tUSBDCDCDevice *psDeviceInst;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ulIndex is different in both cases.
+ //
+ psDeviceInst = pvInstance;
+ psInst = psDeviceInst->psPrivateCDCSerData;
+
+ //
+ // Handler for the interrupt IN notification endpoint.
+ //
+ if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucControlEndpoint)))
+ {
+ //
+ // We have sent an interrupt notification to the host.
+ //
+ ProcessNotificationToHost(psDeviceInst, ulStatus);
+ }
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucBulkOUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(psDeviceInst, ulStatus);
+ }
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucBulkINEndpoint)))
+ {
+ ProcessDataToHost(psDeviceInst, ulStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvInstance, unsigned long ulInfo)
+{
+ tCDCSerInstance *psInst;
+ const tUSBDCDCDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psDevice = (const tUSBDCDCDevice *)pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->eCDCInterruptState = CDC_STATE_IDLE;
+ psInst->eCDCRequestState = CDC_STATE_IDLE;
+ psInst->eCDCRxState = CDC_STATE_IDLE;
+ psInst->eCDCTxState = CDC_STATE_IDLE;
+
+ //
+ // 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.
+ //
+ psDevice->pfnControlCallback(psDevice->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 *pvInstance, unsigned long ulDataSize)
+{
+ const tUSBDCDCDevice *psDevice;
+ tCDCSerInstance *psInst;
+ tBoolean bRetcode;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psDevice = (const tUSBDCDCDevice *)pvInstance;
+
+ //
+ // If we were not passed any data, just return.
+ //
+ if(ulDataSize == 0)
+ {
+ return;
+ }
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Make sure we are actually expecting something.
+ //
+ if(psInst->eCDCRequestState != CDC_STATE_WAIT_DATA)
+ {
+ return;
+ }
+
+ //
+ // Process the data received. This will be a request-specific data
+ // block associated with the last request received.
+ //
+ switch (psInst->ucPendingRequest)
+ {
+ //
+ // 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(ulDataSize != sizeof(tLineCoding))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Set the flag telling us that we need to send a line coding
+ // notification to the client.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags,
+ CDC_DO_LINE_CODING_CHANGE, true);
+
+ //
+ // See if we can send the notification immediately.
+ //
+ bRetcode = CheckAndSendLineCodingChange(psDevice);
+
+ //
+ // If we couldn't 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->eCDCRequestState = CDC_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvInstance, unsigned long ulRequest, void *pvRequestData)
+{
+ tCDCSerInstance *psInst;
+ unsigned char *pucData;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // Create the char array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pucData = (unsigned char *)pvRequestData;
+
+ switch(ulRequest)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the appropriate interface number.
+ //
+ if(pucData[0] == SERIAL_INTERFACE_CONTROL)
+ {
+ psInst->ucInterfaceControl = pucData[1];
+ }
+ else if(pucData[0] == SERIAL_INTERFACE_DATA)
+ {
+ psInst->ucInterfaceData = pucData[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(pucData[0] & USB_EP_DESC_IN)
+ {
+ //
+ // Determine which IN endpoint to modify.
+ //
+ if((pucData[0] & 0x7f) == USB_EP_TO_INDEX(CONTROL_ENDPOINT))
+ {
+ psInst->ucControlEndpoint =
+ INDEX_TO_USB_EP((pucData[1] & 0x7f));
+ }
+ else
+ {
+ psInst->ucBulkINEndpoint =
+ INDEX_TO_USB_EP((pucData[1] & 0x7f));
+ }
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ucBulkOUTEndpoint =
+ INDEX_TO_USB_EP(pucData[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.
+ //
+ pucData[2] = psInst->ucInterfaceControl;
+
+ //
+ // 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.
+ //
+ pucData[29] = psInst->ucInterfaceControl;
+ pucData[30] = psInst->ucInterfaceData;
+
+ //
+ // This sets the bDataInterface of the Union descriptor to the
+ // Data interface used by this instance.
+ pucData[35] = psInst->ucInterfaceData;
+ 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ const tUSBDCDCDevice *psDevice;
+ tCDCSerInstance *psInst;
+ tBoolean bRetcode;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psDevice = (const tUSBDCDCDevice *)pvInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Only handle requests meant for this interface.
+ //
+ if(pUSBRequest->wIndex != psInst->ucInterfaceControl)
+ {
+ 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->ucPendingRequest = USB_CDC_SET_LINE_CODING;
+
+ //
+ // Set the state to indicate we are waiting for data.
+ //
+ psInst->eCDCRequestState = CDC_STATE_WAIT_DATA;
+
+ //
+ // Now read the payload of the request. We handle the actual
+ // operation in the data callback once this data is received.
+ //
+ USBDCDRequestDataEP0(0, (unsigned char *)&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->ulUSBBase, 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->ulUSBBase, USB_EP_0, false);
+
+ //
+ // Ask the client for the current line coding.
+ //
+ psDevice->pfnControlCallback(psDevice->pvControlCBData,
+ USBD_CDC_EVENT_GET_LINE_CODING, 0,
+ &sLineCoding);
+
+ //
+ // Send the line coding information back to the host.
+ //
+ USBDCDSendDataEP0(0, (unsigned char *)&sLineCoding,
+ sizeof(tLineCoding));
+
+ break;
+ }
+
+ case USB_CDC_SET_CONTROL_LINE_STATE:
+ {
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, false);
+
+ //
+ // Set the handshake lines as required.
+ //
+ psInst->usControlLineState = pUSBRequest->wValue;
+
+ //
+ // Remember that we are due to notify the client of a line
+ // state change.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags,
+ CDC_DO_LINE_STATE_CHANGE, true);
+
+ //
+ // See if we can notify now.
+ //
+ bRetcode = CheckAndSendLineStateChange(psDevice);
+
+ //
+ // If we couldn't 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->ulUSBBase, USB_EP_0, false);
+
+ //
+ // Keep a copy of the requested break duration.
+ //
+ psInst->usBreakDuration = pUSBRequest->wValue;
+
+ //
+ // Remember that we need to send a break request.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags,
+ CDC_DO_SEND_BREAK, true);
+
+ //
+ // Send the break request if all outstanding receive data has been
+ // processed.
+ //
+ bRetcode = CheckAndSendBreak(psDevice, pUSBRequest->wValue);
+
+ //
+ // If we couldn't 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 *pvInstance)
+{
+ const tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psCDCDevice = (const tUSBDCDCDevice *)pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psCDCDevice->psPrivateCDCSerData;
+
+ //
+ // 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 *pvInstance)
+{
+ const tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psCDCDevice = (const tUSBDCDCDevice *)pvInstance;
+
+ //
+ // 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 *pvInstance)
+{
+ tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvInstance;
+
+ //
+ // 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 ulIndex is the index of the USB controller for which this tick
+// is being generated.
+// \param ulTimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+CDCTickHandler(void *pvInstance, unsigned long ulTimemS)
+{
+ tBoolean bCanSend;
+ const tUSBDCDCDevice *psDevice;
+ tCDCSerInstance *psInst;
+ unsigned long ulSize;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDCDCDevice *)pvInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateCDCSerData;
+
+ //
+ // Is there any outstanding operation that we should try to perform?
+ //
+ if(psInst->usDeferredOpFlags)
+ {
+ //
+ // 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->usDeferredOpFlags & (1 << CDC_DO_CLEAR_BREAK))
+ {
+ //
+ // Will our break timer expire this time?
+ //
+ if(psInst->usBreakDuration <= ulTimemS)
+ {
+ //
+ // Yes - turn off the break condition.
+ //
+ SendBreak(psDevice, false);
+ }
+ else
+ {
+ //
+ // We have not timed out yet. Decrement the break timer.
+ //
+ psInst->usBreakDuration -= (unsigned short)ulTimemS;
+ }
+ }
+
+ // 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(psDevice);
+
+ //
+ // 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->usDeferredOpFlags & (1 << CDC_DO_SEND_BREAK))
+ {
+ SendBreak(psDevice, true);
+ }
+
+ //
+ // Do we need to set the RTS/DTR states?
+ //
+ if(psInst->usDeferredOpFlags & (1 << CDC_DO_LINE_STATE_CHANGE))
+ {
+ SendLineStateChange(psDevice);
+ }
+
+ //
+ // Do we need to change the line coding parameters?
+ //
+ if(psInst->usDeferredOpFlags & (1 << CDC_DO_LINE_CODING_CHANGE))
+ {
+ SendLineCodingChange(psDevice);
+ }
+
+ //
+ // 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->usDeferredOpFlags & 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->usDeferredOpFlags & (1 << CDC_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ // Tell the client that there is a packet waiting for it.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ulSize,
+ (void *)0);
+ }
+ }
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes CDC device operation when used with a composite device.
+//!
+//! \param ulIndex is the index of the USB controller in use.
+//! \param psCDCDevice points to a structure containing parameters customizing
+//! the operation of the CDC 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.
+//!
+//! \return Returns NULL on failure or the psCDCDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDCDCCompositeInit(unsigned long ulIndex, const tUSBDCDCDevice *psCDCDevice)
+{
+ tCDCSerInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psCDCDevice);
+ ASSERT(psCDCDevice->psPrivateCDCSerData);
+ ASSERT(psCDCDevice->pfnControlCallback);
+ ASSERT(psCDCDevice->pfnRxCallback);
+ ASSERT(psCDCDevice->pfnTxCallback);
+
+ //
+ // Create an instance pointer to the private data area.
+ //
+ psInst = psCDCDevice->psPrivateCDCSerData;
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ucBulkINEndpoint = DATA_IN_ENDPOINT;
+ psInst->ucBulkOUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ucInterfaceControl = SERIAL_INTERFACE_CONTROL;
+ psInst->ucInterfaceData = 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->ucControlEndpoint = CONTROL_ENDPOINT;
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst->psConfDescriptor = (tConfigDescriptor *)g_pCDCSerDescriptor;
+ psInst->psDevInfo = &g_sCDCSerDeviceInfo;
+ psInst->ulUSBBase = USB0_BASE;
+ psInst->eCDCRxState = CDC_STATE_UNCONFIGURED;
+ psInst->eCDCTxState = CDC_STATE_UNCONFIGURED;
+ psInst->eCDCInterruptState = CDC_STATE_UNCONFIGURED;
+ psInst->eCDCRequestState = CDC_STATE_UNCONFIGURED;
+ psInst->ucPendingRequest = 0;
+ psInst->usBreakDuration = 0;
+ psInst->usSerialState = 0;
+ psInst->usDeferredOpFlags = 0;
+ psInst->usControlLineState = 0;
+ psInst->bRxBlocked = false;
+ psInst->bControlBlocked = false;
+ psInst->bConnected = false;
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
+ psDevDesc->idVendor = psCDCDevice->usVID;
+ psDevDesc->idProduct = psCDCDevice->usPID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->psConfDescriptor->bmAttributes = psCDCDevice->ucPwrAttributes;
+ psInst->psConfDescriptor->bMaxPower =
+ (unsigned char)(psCDCDevice->usMaxPowermA / 2);
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->psDevInfo->ppStringDescriptors = psCDCDevice->ppStringDescriptors;
+ psInst->psDevInfo->ulNumStringDescriptors
+ = psCDCDevice->ulNumStringDescriptors;
+
+ //
+ // 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 ulIndex 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(unsigned long ulIndex, const tUSBDCDCDevice *psCDCDevice)
+{
+ void *pvRet;
+ tCDCSerInstance *psInst;
+
+ //
+ // Initialize the internal state for this class.
+ //
+ pvRet = USBDCDCCompositeInit(ulIndex, psCDCDevice);
+
+ if(pvRet)
+ {
+ //
+ // Create an instance pointer to the private data area.
+ //
+ psInst = psCDCDevice->psPrivateCDCSerData;
+
+ //
+ // Set the instance data for this device so that USBDCDInit() call can
+ // have the instance data.
+ //
+ psInst->psDevInfo->pvInstance = (void *)psCDCDevice;
+
+ //
+ // Enable the default interrupt control endpoint if this class is not
+ // being used in a composite device.
+ //
+ psInst->ucControlEndpoint = CONTROL_ENDPOINT;
+
+ //
+ // Use the configuration descriptor with the interrupt control endpoint.
+ //
+ psInst->psDevInfo->ppConfigDescriptors = g_pCDCSerConfigDescriptors;
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the CDC device on the bus.
+ //
+ USBDCDInit(ulIndex, psInst->psDevInfo);
+ }
+
+ return(pvRet);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the CDC device instance.
+//!
+//! \param pvInstance 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 pvInstance instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCTerm(void *pvInstance)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USB_BASE_TO_INDEX(psInst->ulUSBBase));
+
+ psInst->ulUSBBase = 0;
+ psInst->psDevInfo = (tDeviceInfo *)0;
+ psInst->psConfDescriptor = (tConfigDescriptor *)0;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer for the control callback.
+//!
+//! \param pvInstance 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 *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback pointer for the control channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDCDCDevice *)pvInstance)->pvControlCBData;
+ ((tUSBDCDCDevice *)pvInstance)->pvControlCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data parameter for the receive channel callback.
+//!
+//! \param pvInstance 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 *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDCDCDevice *)pvInstance)->pvRxCBData;
+ ((tUSBDCDCDevice *)pvInstance)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data parameter for the transmit callback.
+//!
+//! \param pvInstance 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 *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback data for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDCDCDevice *)pvInstance)->pvTxCBData;
+ ((tUSBDCDCDevice *)pvInstance)->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a packet of data to the USB host via the CDC data interface.
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pcData points to the first byte of data which is to be transmitted.
+//! \param ulLength 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
+//! 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 ulLength 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.
+//
+//*****************************************************************************
+unsigned long
+USBDCDCPacketWrite(void *pvInstance, unsigned char *pcData,
+ unsigned long ulLength, tBoolean bLast)
+{
+ tCDCSerInstance *psInst;
+ long lRetcode;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // Can we send the data provided?
+ //
+ if((ulLength > DATA_IN_EP_MAX_SIZE) ||
+ (psInst->eCDCTxState != CDC_STATE_IDLE))
+ {
+ //
+ // 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.
+ //
+ lRetcode = MAP_USBEndpointDataPut(psInst->ulUSBBase,
+ psInst->ucBulkINEndpoint, pcData,
+ ulLength);
+
+ //
+ // Did we copy the data successfully?
+ //
+ if(lRetcode != -1)
+ {
+ //
+ // Remember how many bytes we sent.
+ //
+ psInst->usLastTxSize += (unsigned short)ulLength;
+
+ //
+ // 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->eCDCTxState = CDC_STATE_WAIT_DATA;
+ lRetcode = MAP_USBEndpointDataSend(psInst->ulUSBBase,
+ psInst->ucBulkINEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(lRetcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ulLength);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we couldn't send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the CDC data
+//! interface.
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pcData points to a buffer into which the received data will be
+//! written.
+//! \param ulLength is the size of the buffer pointed to by pcData.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to ulLength 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.
+//
+//*****************************************************************************
+unsigned long
+USBDCDCPacketRead(void *pvInstance, unsigned char *pcData,
+ unsigned long ulLength, tBoolean bLast)
+{
+ unsigned long ulEPStatus, ulCount, ulPkt;
+ tCDCSerInstance *psInst;
+ long lRetcode;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ if(ulEPStatus & 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->usDeferredOpFlags,
+ 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?
+ //
+ ulPkt = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ulCount = ulLength;
+ lRetcode = MAP_USBEndpointDataGet(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint,
+ pcData, &ulCount);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ulCount == ulPkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint,
+ ulEPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint,
+ true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags,
+ CDC_DO_PACKET_RX, false);
+
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(lRetcode != -1)
+ {
+ return(ulCount);
+ }
+ }
+ }
+
+ //
+ // 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 pvInstance 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 (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.
+//
+//*****************************************************************************
+unsigned long
+USBDCDCTxPacketAvailable(void *pvInstance)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->eCDCTxState != CDC_STATE_IDLE)
+ {
+ //
+ // 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 pvInstance 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.
+//
+//*****************************************************************************
+unsigned long
+USBDCDCRxPacketAvailable(void *pvInstance)
+{
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // 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?
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ if(ulEPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucBulkOUTEndpoint);
+
+ return(ulSize);
+ }
+ 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 pvInstance is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param usState 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 usState 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 *pvInstance, unsigned short usState)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
+
+ //
+ // 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->usSerialState |= (usState & USB_CDC_SERIAL_ERRORS);
+ psInst->usSerialState &= ~USB_CDC_SERIAL_ERRORS;
+ psInst->usSerialState |= (usState & ~USB_CDC_SERIAL_ERRORS);
+
+ //
+ // Set the flag indicating that a serial state change is to be sent.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
+ true);
+
+ //
+ // Can we send the state change immediately?
+ //
+ if(psInst->eCDCInterruptState == CDC_STATE_IDLE)
+ {
+ //
+ // 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->eCDCInterruptState = CDC_STATE_WAIT_DATA;
+ SendSerialState(pvInstance);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvInstance is the pointer to the CDC device instance structure.
+//! \param ucPower 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 *pvInstance, unsigned char ucPower)
+{
+ ASSERT(pvInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ucPower);
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wakeup to resume communication when in suspended state.
+//!
+//! \param pvInstance 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 config 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.
+//
+//*****************************************************************************
+tBoolean
+USBDCDCRemoteWakeupRequest(void *pvInstance)
+{
+ ASSERT(pvInstance);
+
+ //
+ // 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..f2f9b00
--- /dev/null
+++ b/usblib/device/usbdcdc.h
@@ -0,0 +1,353 @@
+//*****************************************************************************
+//
+// usbdcdc.h - USBLib support for generic CDC ACM (serial) device.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris 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.
+ //
+ CDC_STATE_UNCONFIGURED,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ CDC_STATE_IDLE,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ CDC_STATE_WAIT_DATA,
+
+ //
+ // Waiting for client to process data.
+ //
+ CDC_STATE_WAIT_CLIENT
+}
+tCDCState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// CDC Serial device. The memory for this structure is pointed to by the
+// psPrivateCDCSerData field in the tUSBDCDCDevice structure passed on
+// USBDCDCInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ unsigned long ulUSBBase;
+ tDeviceInfo *psDevInfo;
+ tConfigDescriptor *psConfDescriptor;
+ volatile tCDCState eCDCRxState;
+ volatile tCDCState eCDCTxState;
+ volatile tCDCState eCDCRequestState;
+ volatile tCDCState eCDCInterruptState;
+ volatile unsigned char ucPendingRequest;
+ unsigned short usBreakDuration;
+ unsigned short usControlLineState;
+ unsigned short usSerialState;
+ volatile unsigned short usDeferredOpFlags;
+ unsigned short usLastTxSize;
+ tLineCoding sLineCoding;
+ volatile tBoolean bRxBlocked;
+ volatile tBoolean bControlBlocked;
+ volatile tBoolean bConnected;
+ unsigned char ucControlEndpoint;
+ unsigned char ucBulkINEndpoint;
+ unsigned char ucBulkOUTEndpoint;
+ unsigned char ucInterfaceControl;
+ unsigned char ucInterfaceData;
+}
+tCDCSerInstance;
+
+
+#ifndef DEPRECATED
+//*****************************************************************************
+//
+// The number of bytes of workspace required by the CDC device class driver.
+// The client must provide a block of RAM of at least this size in the
+// psPrivateCDCSerData field of the tUSBCDCDevice structure passed on
+// USBDCDCInit().
+//
+// This value is deprecated and should not be used, any new code should just
+// pass in a tUSBCDCDevice structure in the psPrivateCDCSerData field.
+//
+//*****************************************************************************
+#define USB_CDCSER_WORKSPACE_SIZE (sizeof(tCDCSerInstance))
+#endif
+
+//*****************************************************************************
+//
+// The following defines are used when working with composite devices.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! 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.
+//
+// For reference this is sizeof(g_pIADSerDescriptor) +
+// sizeof(g_pCDCSerCommInterface) + sizeof(g_pCDCSerDataInterface)
+//
+//*****************************************************************************
+#define COMPOSITE_DCDC_SIZE (8 + 35 + 23)
+
+//*****************************************************************************
+//
+// CDC-specific events These events are provided to the application in the
+// \e ulMsg 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 ulMsgValue 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! 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.
+ //
+ 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.
+ //
+ 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.
+ //
+ 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + (5 * number of supported languages).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! A pointer to 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 *psPrivateCDCSerData;
+}
+tUSBDCDCDevice;
+
+extern tDeviceInfo g_sCDCSerDeviceInfo;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void * USBDCDCCompositeInit(unsigned long ulIndex,
+ const tUSBDCDCDevice *psCDCDevice);
+extern void *USBDCDCInit(unsigned long ulIndex,
+ const tUSBDCDCDevice *psCDCDevice);
+extern void USBDCDCTerm(void *pvInstance);
+extern void *USBDCDCSetControlCBData(void *pvInstance, void *pvCBData);
+extern void *USBDCDCSetRxCBData(void *pvInstance, void *pvCBData);
+extern void *USBDCDCSetTxCBData(void *pvInstance, void *pvCBData);
+extern unsigned long USBDCDCPacketWrite(void *pvInstance,
+ unsigned char *pcData,
+ unsigned long ulLength,
+ tBoolean bLast);
+extern unsigned long USBDCDCPacketRead(void *pvInstance,
+ unsigned char *pcData,
+ unsigned long ulLength,
+ tBoolean bLast);
+extern unsigned long USBDCDCTxPacketAvailable(void *pvInstance);
+extern unsigned long USBDCDCRxPacketAvailable(void *pvInstance);
+extern void USBDCDCSerialStateChange(void *pvInstance,
+ unsigned short usState);
+extern void USBDCDCPowerStatusSet(void *pvInstance, unsigned char ucPower);
+extern tBoolean USBDCDCRemoteWakeupRequest(void *pvInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// 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..2bb1731
--- /dev/null
+++ b/usblib/device/usbdcdesc.c
@@ -0,0 +1,649 @@
+//*****************************************************************************
+//
+// usbcdesc.c - Config descriptor parsing functions.
+//
+// Copyright (c) 2007-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/device/usbdevice.h"
+
+//*****************************************************************************
+//
+// The functions in this file mirror the descriptor parsing APIs available
+// in usblib.h but parse config 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 psDesc.
+//! \param pulSec points to a variable containing the section within \e
+//! psConfig which contains \e psDesc.
+//! \param psDesc points to the descriptor that we want to step past.
+//!
+//! This function walks forward one descriptor within a config descriptor. The
+//! value returned is a pointer to the header of the next descriptor after the
+//! descriptor supplied in \e psDesc. If the next descriptor is in the next
+//! section, \e *pulSec will be incremented accordlingly.
+//!
+//! \return Returns a pointer to the next descriptor in the config descrptor.
+//
+//*****************************************************************************
+static tDescriptorHeader *
+NextConfigDescGet(const tConfigHeader *psConfig, unsigned long *pulSec,
+ 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((unsigned char *)psDesc >= (psConfig->psSections[*pulSec]->pucData +
+ psConfig->psSections[*pulSec]->usSize))
+ {
+ //
+ // Yes - move to the next section.
+ //
+ (*pulSec)++;
+
+ //
+ // Are we still within the config descriptor?
+ //
+ if(*pulSec < psConfig->ucNumSections)
+ {
+ //
+ // Yes - the new descriptor is at the start of the new section.
+ //
+ psDesc =
+ (tDescriptorHeader *)psConfig->psSections[*pulSec]->pucData;
+ }
+ 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 config descriptor
+//! with the supplied interface number.
+//!
+//! \param psConfig points to the header structure for the config descriptor
+//! that is to be searched.
+//! \param ucInterfaceNumber is the interface number of the descriptor that is
+//! being queried.
+//! \param ulIndex is the zero based index of the descriptor to return.
+//! \param pulSection points to storage which will be 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,
+ unsigned char ucInterfaceNumber,
+ unsigned long ulIndex,
+ unsigned long *pulSection)
+{
+ tDescriptorHeader *psDescCheck;
+ unsigned long ulCount;
+ unsigned long ulSec;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pucData;
+ ulCount = 0;
+ ulSec = 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 ==
+ ucInterfaceNumber))
+ {
+ //
+ // This is an interface descriptor for interface ucInterfaceNumber.
+ // Determine if this is the n-th one we have found and, if so,
+ // return its pointer.
+ //
+ if(ulCount == ulIndex)
+ {
+ //
+ // Found it - return the pointer and section number.
+ //
+ *pulSection = ulSec;
+ 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.
+ //
+ ulCount++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ psDescCheck = NextConfigDescGet(psConfig, &ulSec, 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 config 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 config descriptor will result
+//! from concatenating the required sections.
+//
+//*****************************************************************************
+unsigned long
+USBDCDConfigDescGetSize(const tConfigHeader *psConfig)
+{
+ unsigned long ulLoop;
+ unsigned long ulLen;
+
+ ulLen = 0;
+
+ //
+ // Determine the size of the whole descriptor by adding the sizes of
+ // each section which will be concatenated to produce it.
+ //
+ for(ulLoop = 0; ulLoop < psConfig->ucNumSections; ulLoop++)
+ {
+ ulLen += psConfig->psSections[ulLoop]->usSize;
+ }
+
+ return(ulLen);
+}
+
+//*****************************************************************************
+//
+//! \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 ulType 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.
+//
+//*****************************************************************************
+unsigned long
+USBDCDConfigDescGetNum(const tConfigHeader *psConfig, unsigned long ulType)
+{
+ unsigned long ulSection;
+ unsigned long ulNumDescs;
+
+ //
+ // Initialize our counts.
+ //
+ ulNumDescs = 0;
+
+ //
+ // Determine the number of descriptors of the given type in each of the
+ // sections comprising the config descriptor. Note that this assumes each
+ // section contains only whole descriptors!
+ //
+ for(ulSection = 0; ulSection < (unsigned long)psConfig->ucNumSections;
+ ulSection++)
+ {
+ ulNumDescs += USBDescGetNum(
+ (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData,
+ psConfig->psSections[ulSection]->usSize,
+ ulType);
+ }
+
+ return(ulNumDescs);
+}
+
+//*****************************************************************************
+//
+//! \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 ulType 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 ulIndex is the zero based index of the descriptor whose pointer is
+//! to be returned. For example, passing value 1 in \e ulIndex returns the
+//! second matching descriptor.
+//! \param pulSection 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, unsigned long ulType,
+ unsigned long ulIndex, unsigned long *pulSection)
+{
+ unsigned long ulSection;
+ unsigned long ulTotalDescs;
+ unsigned long ulNumDescs;
+
+ //
+ // Initialize our counts.
+ //
+ ulTotalDescs = 0;
+
+ //
+ // Determine the number of descriptors of the given type in each of the
+ // sections comprising the config descriptor. This allows us to determine
+ // which section contains the descriptor we are being asked for.
+ //
+ for(ulSection = 0; ulSection < (unsigned long)psConfig->ucNumSections;
+ ulSection++)
+ {
+ //
+ // How many descriptors of the requested type exist in this section?
+ //
+ ulNumDescs = USBDescGetNum(
+ (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData,
+ psConfig->psSections[ulSection]->usSize,
+ ulType);
+
+ //
+ // Does this section contain the descriptor whose index we are looking
+ // for?
+ //
+ if((ulTotalDescs + ulNumDescs) > ulIndex)
+ {
+ //
+ // We know the requested descriptor exists in the current
+ // block so write the section number to the caller's storage.
+ //
+ *pulSection = ulSection;
+
+ //
+ // Now find the actual descriptor requested and return its pointer.
+ //
+ return(USBDescGet(
+ (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData,
+ psConfig->psSections[ulSection]->usSize,
+ ulType,
+ ulIndex - ulTotalDescs));
+ }
+
+ //
+ // 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.
+ //
+ ulTotalDescs += ulNumDescs;
+ }
+
+ //
+ // 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 config descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ucInterfaceNumber 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 config
+//! descriptor.
+//
+//*****************************************************************************
+unsigned long
+USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
+ unsigned char ucInterfaceNumber)
+{
+ tDescriptorHeader *psDescCheck;
+ unsigned long ulCount;
+ unsigned long ulSec;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pucData;
+ ulSec = 0;
+ ulCount = 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 ==
+ ucInterfaceNumber))
+ {
+ //
+ // Yes - increment our count.
+ //
+ ulCount++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ psDescCheck = NextConfigDescGet(psConfig, &ulSec, psDescCheck);
+ }
+
+ //
+ // Return the descriptor count to the caller.
+ //
+ return(ulCount);
+}
+
+//*****************************************************************************
+//
+//! \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 ulIndex is the zero based index of the interface that is to be
+//! found. If \e ulAlt is set to a value other than \b USB_DESC_ANY, this will
+//! be equivalent to the interface number being searched for.
+//! \param ulAlt 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 pulSection 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 ulAlt 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
+//! ulAlt if \e ulIndex is set to the required interface number and \e ulAlt
+//! 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, unsigned long ulIndex,
+ unsigned long ulAlt, unsigned long *pulSection)
+{
+ //
+ // If we are being told to ignore the alternate configuration, this boils
+ // down to a very simple query.
+ //
+ if(ulAlt == USB_DESC_ANY)
+ {
+ //
+ // Return the ulIndex-th interface descriptor we find in the
+ // configuration descriptor.
+ //
+ return((tInterfaceDescriptor *)USBDCDConfigDescGet(psConfig,
+ USB_DTYPE_INTERFACE,
+ ulIndex,
+ pulSection));
+ }
+ else
+ {
+ //
+ // In this case, a specific alternate setting number is required.
+ // Given that interface numbers are zero based indices, we can
+ // pass the supplied ulIndex parameter directly as the interface
+ // number to USBDescGetAlternateInterface to retrieve the requested
+ // interface descriptor pointer.
+ //
+ return(ConfigAlternateInterfaceGet(psConfig, ulIndex, ulAlt,
+ pulSection));
+ }
+}
+
+//*****************************************************************************
+//
+//! \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 ulInterfaceNumber is the interface number whose endpoint is to be
+//! found.
+//! \param ulAltCfg is the alternate setting number which is to be searched
+//! for. This must be a valid alternate setting number for the requested
+//! interface.
+//! \param ulIndex 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 ulIndex 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,
+ unsigned long ulInterfaceNumber,
+ unsigned long ulAltCfg, unsigned long ulIndex)
+{
+ tInterfaceDescriptor *psInterface;
+ tDescriptorHeader *psEndpoint;
+ unsigned long ulSection;
+ unsigned long ulCount;
+
+ //
+ // Find the requested interface descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ulInterfaceNumber,
+ ulAltCfg, &ulSection);
+
+ //
+ // Did we find the requested interface?
+ //
+ if(psInterface)
+ {
+ //
+ // Is the index passed valid?
+ //
+ if(ulIndex >= 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.
+ //
+ ulCount = 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(ulCount == ulIndex)
+ {
+ //
+ // Yes - return the descriptor pointer to the caller.
+ //
+ return((tEndpointDescriptor *)psEndpoint);
+ }
+
+ //
+ // Move on to look for the next endpoint.
+ //
+ ulCount++;
+ }
+
+ //
+ // Move to the next descriptor.
+ //
+ psEndpoint = NextConfigDescGet(psConfig, &ulSection,
+ psEndpoint);
+ }
+ }
+ }
+
+ //
+ // We couldn't 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..feb22bf
--- /dev/null
+++ b/usblib/device/usbdcomp.c
@@ -0,0 +1,1543 @@
+//****************************************************************************
+//
+// usbdcomp.c - USB composite device class driver.
+//
+// Copyright (c) 2010-2012 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 9453 of the Stellaris USB Library.
+//
+//****************************************************************************
+
+#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/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 unsigned char g_pCompDeviceDescriptor[] =
+{
+ 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 unsigned char g_pCompConfigDescriptor[] =
+{
+ //
+ // 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.pulDeviceWorkspace). 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
+
+//*****************************************************************************
+//
+// Macros to convert between USB controller base address and an index. These
+// are currently trivial but are included to allow for the possibility of
+// supporting more than one controller in the future.
+//
+//*****************************************************************************
+#define USB_BASE_TO_INDEX(BaseAddr) (0)
+#define USB_INDEX_TO_BASE(Index) (USB0_BASE)
+
+//****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//****************************************************************************
+static void HandleDisconnect(void *pvInstance);
+static void InterfaceChange(void *pvInstance, unsigned char ucInterfaceNum,
+ unsigned char ucAlternateSetting);
+static void ConfigChangeHandler(void *pvInstance, unsigned long ulValue);
+static void DataSent(void *pvInstance, unsigned long ulInfo);
+static void DataReceived(void *pvInstance, unsigned long ulInfo);
+static void HandleEndpoints(void *pvInstance, unsigned long ulStatus);
+static void HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest);
+static void SuspendHandler(void *pvInstance);
+static void ResumeHandler(void *pvInstance);
+static void ResetHandler(void *pvInstance);
+static void GetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest);
+
+//****************************************************************************
+//
+// Configuration Descriptor.
+//
+//****************************************************************************
+tConfigHeader *g_pCompConfigDescriptors[1];
+
+//****************************************************************************
+//
+// The FIFO configuration for USB mass storage class device.
+//
+//****************************************************************************
+tFIFOConfig g_sUSBCompositeFIFOConfig =
+{
+ //
+ // IN endpoints.
+ //
+ {
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN }
+ },
+ //
+ // OUT endpoints.
+ //
+ {
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT }
+ },
+};
+
+//****************************************************************************
+//
+// The device information structure for the USB Composite device.
+//
+//****************************************************************************
+tDeviceInfo g_sCompositeDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ //
+ // GetDescriptor
+ //
+ GetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ InterfaceChange,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ DataSent,
+
+ //
+ // ResetHandler
+ //
+ ResetHandler,
+
+ //
+ // SuspendHandler
+ //
+ SuspendHandler,
+
+ //
+ // ResumeHandler
+ //
+ ResumeHandler,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints
+ },
+ g_pCompDeviceDescriptor,
+ (const tConfigHeader **)g_pCompConfigDescriptors,
+ 0,
+ 0,
+ &g_sUSBCompositeFIFOConfig
+};
+
+//****************************************************************************
+//
+// Use the lookup table from the field pulDeviceWorkspace 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 unsigned long
+InterfaceToIndex(tUSBDCompositeDevice *psDevice, unsigned long ulInterface)
+{
+ unsigned long ulLoop;
+ unsigned char *pucLookupEntry;
+
+ //
+ // Get a pointer to the lookup table.
+ //
+ pucLookupEntry = (unsigned char *)psDevice->pulDeviceWorkspace;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ulLoop = 0; ulLoop < psDevice->ulNumDevices; ulLoop++)
+ {
+ //
+ // 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(ulInterface < (unsigned long)pucLookupEntry[LOOKUP_INTERFACE_BYTE])
+ {
+ return(ulLoop);
+ }
+
+ //
+ // Move to the next lookup table entry.
+ //
+ pucLookupEntry += sizeof(unsigned long);
+ }
+
+ //
+ // 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 pulDeviceWorkspace 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 unsigned long
+EndpointToIndex(tUSBDCompositeDevice *psDevice, unsigned long ulEndpoint,
+ tBoolean bInEndpoint)
+{
+ unsigned long ulLoop, ulEndpointByte;
+ unsigned char *pucLookupEntry;
+
+ //
+ // Get a pointer to the lookup table.
+ //
+ pucLookupEntry = (unsigned char *)psDevice->pulDeviceWorkspace;
+
+ //
+ // Are we considering an IN or OUT endpoint?
+ //
+ ulEndpointByte = bInEndpoint ? LOOKUP_IN_END_BYTE : LOOKUP_OUT_END_BYTE;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ulLoop = 0; ulLoop < psDevice->ulNumDevices; ulLoop++)
+ {
+ //
+ // 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(ulEndpoint < (unsigned long)pucLookupEntry[ulEndpointByte])
+ {
+ return(ulLoop);
+ }
+
+ //
+ // Move to the next lookup table entry.
+ //
+ pucLookupEntry += sizeof(unsigned long);
+ }
+
+ //
+ // 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // 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(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ulIdx = InterfaceToIndex(psDevice, (pUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ulIdx = EndpointToIndex(psDevice, (pUSBRequest->wIndex & 0x0F),
+ (pUSBRequest->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:
+ {
+ ulIdx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ulIdx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ //
+ // Does this device have a GetDescriptor callback?
+ //
+ if(pDeviceInfo->sCallbacks.pfnGetDescriptor)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psDevice->psPrivateData->ulEP0Owner = ulIdx;
+
+ //
+ // Call the device to retrieve the descriptor.
+ //
+ pDeviceInfo->sCallbacks.pfnGetDescriptor(
+ psDevice->psDevices[ulIdx].pvInstance, pUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(
+ USB_BASE_TO_INDEX(psDevice->psPrivateData->ulUSBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USB_BASE_TO_INDEX(psDevice->psPrivateData->ulUSBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an suspend handler
+// called.
+//
+//****************************************************************************
+static void
+SuspendHandler(void *pvInstance)
+{
+ unsigned long ulIdx;
+ tUSBDCompositeDevice *psDevice;
+ const tDeviceInfo *pDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psDevice->pfnCallback)
+ {
+ psDevice->pfnCallback(pvInstance, USB_EVENT_SUSPEND, 0, 0);
+ }
+
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+ pvDeviceInst = psDevice->psDevices[ulIdx].pvInstance;
+
+ if(pDeviceInfo->sCallbacks.pfnSuspendHandler)
+ {
+ pDeviceInfo->sCallbacks.pfnSuspendHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an resume handler
+// called.
+//
+//****************************************************************************
+static void
+ResumeHandler(void *pvInstance)
+{
+ unsigned long ulIdx;
+ tUSBDCompositeDevice *psDevice;
+ const tDeviceInfo *pDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psDevice->pfnCallback)
+ {
+ psDevice->pfnCallback(pvInstance, USB_EVENT_RESUME, 0, 0);
+ }
+
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+ pvDeviceInst = psDevice->psDevices[ulIdx].pvInstance;
+
+ if(pDeviceInfo->sCallbacks.pfnResumeHandler)
+ {
+ pDeviceInfo->sCallbacks.pfnResumeHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an reset handler
+// called.
+//
+//****************************************************************************
+static void
+ResetHandler(void *pvInstance)
+{
+ unsigned long ulIdx;
+ tUSBDCompositeDevice *psDevice;
+ const tDeviceInfo *pDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // Inform the application that the device has been connected.
+ //
+ if(psDevice->pfnCallback)
+ {
+ psDevice->pfnCallback(pvInstance, USB_EVENT_CONNECTED, 0, 0);
+ }
+
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+ pvDeviceInst = psDevice->psDevices[ulIdx].pvInstance;
+
+ if(pDeviceInfo->sCallbacks.pfnResetHandler)
+ {
+ pDeviceInfo->sCallbacks.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 *pvInstance, unsigned long ulInfo)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ulIdx = psDevice->psPrivateData->ulEP0Owner;
+
+ if(ulIdx != INVALID_DEVICE_INDEX)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ if(pDeviceInfo->sCallbacks.pfnDataSent)
+ {
+ pDeviceInfo->sCallbacks.pfnDataSent(
+ psDevice->psDevices[ulIdx].pvInstance, ulInfo);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// 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 *pvInstance, unsigned long ulInfo)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ulIdx = psDevice->psPrivateData->ulEP0Owner;
+
+ if(ulIdx != INVALID_DEVICE_INDEX)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ if(pDeviceInfo->sCallbacks.pfnDataReceived)
+ {
+ pDeviceInfo->sCallbacks.pfnDataReceived(
+ psDevice->psDevices[ulIdx].pvInstance, ulInfo);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an endpoint handler
+// called.
+//
+//****************************************************************************
+static void
+HandleEndpoints(void *pvInstance, unsigned long ulStatus)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // 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 ulStatus will be 0). Since the handlers are
+ // set up to ignore any callback that isn't for them, this is safe.
+ //
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ if(pDeviceInfo->sCallbacks.pfnEndpointHandler)
+ {
+ pDeviceInfo->sCallbacks.pfnEndpointHandler(
+ psDevice->psDevices[ulIdx].pvInstance, ulStatus);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//****************************************************************************
+static void
+HandleDisconnect(void *pvInstance)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ if(psDevice->pfnCallback)
+ {
+ psDevice->pfnCallback(pvInstance, USB_EVENT_DISCONNECTED, 0, 0);
+ }
+
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ if(pDeviceInfo->sCallbacks.pfnDisconnectHandler)
+ {
+ pDeviceInfo->sCallbacks.pfnDisconnectHandler(
+ psDevice->psDevices[ulIdx].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 *pvInstance, unsigned char ucInterfaceNum,
+ unsigned char ucAlternateSetting)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ if(pDeviceInfo->sCallbacks.pfnInterfaceChange)
+ {
+ pDeviceInfo->sCallbacks.pfnInterfaceChange(
+ psDevice->psDevices[ulIdx].pvInstance, ucInterfaceNum,
+ ucAlternateSetting);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// 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 *pvInstance, unsigned long ulValue)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ for(ulIdx = 0; ulIdx < psDevice->ulNumDevices; ulIdx++)
+ {
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ if(pDeviceInfo->sCallbacks.pfnConfigChange)
+ {
+ pDeviceInfo->sCallbacks.pfnConfigChange(
+ psDevice->psDevices[ulIdx].pvInstance, ulValue);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvInstance
+// \param pUSBRequest 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned long ulIdx;
+ const tDeviceInfo *pDeviceInfo;
+ tUSBDCompositeDevice *psDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psDevice = (tUSBDCompositeDevice *)pvInstance;
+
+ //
+ // 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(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ulIdx = InterfaceToIndex(psDevice, (pUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ulIdx = EndpointToIndex(psDevice, (pUSBRequest->wIndex & 0x0F),
+ (pUSBRequest->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:
+ {
+ ulIdx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ulIdx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ pDeviceInfo = psDevice->psDevices[ulIdx].psDevice;
+
+ //
+ // Does this device have a RequestHandler callback?
+ //
+ if(pDeviceInfo->sCallbacks.pfnRequestHandler)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psDevice->psPrivateData->ulEP0Owner = ulIdx;
+
+ //
+ // Yes - call the device to retrieve the descriptor.
+ //
+ pDeviceInfo->sCallbacks.pfnRequestHandler(
+ psDevice->psDevices[ulIdx].pvInstance, pUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(
+ USB_BASE_TO_INDEX(psDevice->psPrivateData->ulUSBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USB_BASE_TO_INDEX(psDevice->psPrivateData->ulUSBBase));
+ }
+
+}
+
+//****************************************************************************
+//
+// This function handles sending interface number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeIfaceChange(tCompositeEntry *pCompDevice, unsigned char ucOld,
+ unsigned char ucNew)
+{
+ unsigned char pucInterfaces[2];
+
+ if(pCompDevice->psDevice->sCallbacks.pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pucInterfaces[0] = ucOld;
+ pucInterfaces[1] = ucNew;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ pCompDevice->psDevice->sCallbacks.pfnDeviceHandler(
+ pCompDevice->pvInstance, USB_EVENT_COMP_IFACE_CHANGE,
+ (void *)pucInterfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending endpoint number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeEPChange(tCompositeEntry *pCompDevice, unsigned char ucOld,
+ unsigned char ucNew)
+{
+ unsigned char pucInterfaces[2];
+ unsigned char ucIndex;
+
+ if(pCompDevice->psDevice->sCallbacks.pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pucInterfaces[0] = ucOld;
+ pucInterfaces[1] = ucNew;
+
+ ucNew--;
+
+ if(ucOld & USB_RTYPE_DIR_IN)
+ {
+ ucIndex = (ucOld & ~USB_RTYPE_DIR_IN) - 1;
+
+ g_sUSBCompositeFIFOConfig.sIn[ucNew].bDoubleBuffer =
+ pCompDevice->psDevice->psFIFOConfig->sIn[ucIndex].bDoubleBuffer;
+
+ g_sUSBCompositeFIFOConfig.sIn[ucNew].usEPFlags =
+ pCompDevice->psDevice->psFIFOConfig->sIn[ucIndex].usEPFlags;
+ }
+ else
+ {
+ ucIndex = ucOld - 1;
+
+ g_sUSBCompositeFIFOConfig.sOut[ucNew].bDoubleBuffer =
+ pCompDevice->psDevice->psFIFOConfig->sOut[ucIndex].bDoubleBuffer;
+
+ g_sUSBCompositeFIFOConfig.sOut[ucNew].usEPFlags =
+ pCompDevice->psDevice->psFIFOConfig->sOut[ucIndex].usEPFlags;
+ }
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ pCompDevice->psDevice->sCallbacks.pfnDeviceHandler(
+ pCompDevice->pvInstance, USB_EVENT_COMP_EP_CHANGE,
+ (void *)pucInterfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function merges the configuration descriptors into a single multiple
+// instance device.
+//
+//****************************************************************************
+unsigned long
+BuildCompositeDescriptor(tUSBDCompositeDevice *psCompDevice)
+{
+ unsigned long ulIdx, ulOffset, ulCPIdx, ulFixINT, ulDev;
+ unsigned short usTotalLength, usBytes;
+ unsigned char ucInterface, ucINEndpoint, ucOUTEndpoint;
+ unsigned char *pucData, *pucConfig;
+ const tConfigHeader *pConfigHeader;
+ tDescriptorHeader *psHeader;
+ const unsigned char *pucDescriptor;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ const tDeviceInfo *psDevice;
+
+ //
+ // Save the number of devices to look through.
+ //
+ ulDev = 0;
+ ulIdx = 0;
+ ucInterface = 0;
+ ucINEndpoint = 1;
+ ucOUTEndpoint = 1;
+ ulOffset = 0;
+ ulFixINT = 0;
+
+ //
+ // This puts the first section pointer in the first entry in the list
+ // of sections.
+ //
+ psCompDevice->psPrivateData->ppsCompSections[0] =
+ &psCompDevice->psPrivateData->psCompSections[0];
+
+ //
+ // Put the pointer to this instances configuration descriptor into the
+ // front of the list.
+ //
+ psCompDevice->psPrivateData->ppsCompSections[0]->pucData =
+ (unsigned char *)&psCompDevice->psPrivateData->sConfigDescriptor;
+
+ psCompDevice->psPrivateData->ppsCompSections[0]->usSize =
+ psCompDevice->psPrivateData->sConfigDescriptor.bLength;
+
+ //
+ // The configuration descriptor is 9 bytes so initialize the total length
+ // to 9 bytes.
+ //
+ usTotalLength = 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->psPrivateData->ppsCompSections[1] =
+ &psCompDevice->psPrivateData->psCompSections[1];
+
+ //
+ // Copy the pointer to the application supplied space into the section
+ // list.
+ //
+ psCompDevice->psPrivateData->ppsCompSections[1]->usSize = 0;
+ psCompDevice->psPrivateData->ppsCompSections[1]->pucData =
+ psCompDevice->psPrivateData->pucData;
+
+ //
+ // Create a local pointer to the data that is used to copy data from
+ // the other devices into the composite descriptor.
+ //
+ pucData = psCompDevice->psPrivateData->pucData;
+
+ //
+ // Consider each device in turn.
+ //
+ while(ulDev < psCompDevice->ulNumDevices)
+ {
+ //
+ // Save the current starting address of this descriptor.
+ //
+ pucConfig = pucData + ulOffset;
+
+ //
+ // Create a local pointer to the configuration header.
+ //
+ psDevice = psCompDevice->psDevices[ulDev].psDevice;
+ pConfigHeader = psDevice->ppConfigDescriptors[0];
+
+ //
+ // Loop through each of the sections in this device's configuration
+ // descriptor.
+ //
+ for(ulIdx = 0; ulIdx < pConfigHeader->ucNumSections; ulIdx++)
+ {
+ //
+ // Initialize the local offset in this descriptor. We include
+ // a special case here to ignore the initial 9 byte config
+ // descriptor since this has already been handled.
+ //
+ if(ulIdx)
+ {
+ //
+ // This is not the first section so we handle everything in
+ // it.
+ //
+ usBytes = 0;
+ }
+ else
+ {
+ //
+ // This is the first section for this device so skip the 9
+ // byte config descriptor since we've already handled this.
+ //
+ usBytes = 9;
+
+ //
+ // If this section includes only the config descriptor, skip
+ // it entirely.
+ //
+ if(pConfigHeader->psSections[ulIdx]->usSize <= usBytes)
+ {
+ continue;
+ }
+ }
+
+ //
+ // Get a pointer to the configuration descriptor.
+ //
+ pucDescriptor = pConfigHeader->psSections[ulIdx]->pucData;
+
+ //
+ // Bounds check the allocated space and return if there is not
+ // enough space.
+ //
+ if(ulOffset > psCompDevice->psPrivateData->ulDataSize)
+ {
+ return(1);
+ }
+
+ //
+ // Copy the descriptor from the device into the descriptor list.
+ //
+ for(ulCPIdx = 0;
+ ulCPIdx < pConfigHeader->psSections[ulIdx]->usSize;
+ ulCPIdx++)
+ {
+ pucData[ulCPIdx + ulOffset] = pucDescriptor[ulCPIdx];
+ }
+
+ //
+ // Read out the descriptors in this section.
+ //
+ while(usBytes < pConfigHeader->psSections[ulIdx]->usSize)
+ {
+ //
+ // Create a descriptor header pointer.
+ //
+ psHeader = (tDescriptorHeader *)&pucData[ulOffset + usBytes];
+
+ //
+ // 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 = ucInterface - 1;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeIfaceChange(&psCompDevice->psDevices[ulDev],
+ psInterface->bInterfaceNumber,
+ ucInterface);
+ //
+ // This was the non-alternate setting so save the
+ // value and move to the next interface number.
+ //
+ psInterface->bInterfaceNumber = ucInterface;
+
+ //
+ // No strings allowed on interface descriptors for
+ // composite devices.
+ //
+ psInterface->iInterface = 0;
+
+ ucInterface++;
+ }
+ }
+ //
+ // 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->usPID == USB_PID_COMP_SERIAL))
+ {
+ //
+ // Check if the Fixed Interrupt endpoint has been
+ // set yet.
+ //
+ if(ulFixINT == 0)
+ {
+ //
+ // Allocate the fixed interrupt endpoint and
+ // save its number.
+ //
+ ulFixINT = ucINEndpoint++;
+ }
+
+ CompositeEPChange(&psCompDevice->psDevices[ulDev],
+ psEndpoint->bEndpointAddress,
+ ulFixINT);
+
+ psEndpoint->bEndpointAddress = ulFixINT |
+ USB_RTYPE_DIR_IN;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(&psCompDevice->psDevices[ulDev],
+ psEndpoint->bEndpointAddress,
+ ucINEndpoint);
+
+ psEndpoint->bEndpointAddress = ucINEndpoint++ |
+ USB_RTYPE_DIR_IN;
+ }
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(&psCompDevice->psDevices[ulDev],
+ psEndpoint->bEndpointAddress,
+ ucOUTEndpoint);
+ psEndpoint->bEndpointAddress = ucOUTEndpoint++;
+ }
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ usBytes += psHeader->bLength;
+ }
+
+ ulOffset += pConfigHeader->psSections[ulIdx]->usSize;
+
+ usTotalLength += usBytes;
+ }
+
+ //
+ // Allow the device class to make adjustments to the configuration
+ // descriptor.
+ //
+ psCompDevice->psDevices[ulDev].psDevice->sCallbacks.pfnDeviceHandler(
+ psCompDevice->psDevices[ulDev].pvInstance,
+ USB_EVENT_COMP_CONFIG, (void *)pucConfig);
+
+ //
+ // Add an entry into the device workspace array to allow us to quickly
+ // map interface and endpoint numbers to device instances later.
+ //
+ psCompDevice->pulDeviceWorkspace[ulDev] =
+ (ulDev << (LOOKUP_INDEX_BYTE * 8)) |
+ (ucInterface << (LOOKUP_INTERFACE_BYTE * 8)) |
+ (ucOUTEndpoint << (LOOKUP_OUT_END_BYTE * 8)) |
+ (ucINEndpoint << (LOOKUP_IN_END_BYTE * 8));
+
+ //
+ // Move on to the next device.
+ //
+ ulDev++;
+ }
+
+ //
+ // Modify the configuration descriptor to match the number of interfaces
+ // and the new total size.
+ //
+ psCompDevice->psPrivateData->sCompConfigHeader.ucNumSections = 2;
+ psCompDevice->psPrivateData->ppsCompSections[1]->usSize = ulOffset;
+ psCompDevice->psPrivateData->sConfigDescriptor.bNumInterfaces =
+ ucInterface;
+ psCompDevice->psPrivateData->sConfigDescriptor.wTotalLength =
+ usTotalLength;
+
+
+ return(0);
+}
+
+//****************************************************************************
+//
+//! This function should be called once for the composite class device to
+//! initialize basic operation and prepare for enumeration.
+//!
+//! \param ulIndex 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 ulSize is the size in bytes of the data pointed to by the
+//! \e pucData parameter.
+//! \param pucData 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 ulSize and \e pucData
+//! parameters should be large enough to hold all of the class instances
+//! passed in via the 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(unsigned long ulIndex, tUSBDCompositeDevice *psDevice,
+ unsigned long ulSize, unsigned char *pucData)
+{
+ tCompositeInstance *psInst;
+ long lIdx;
+ unsigned char *pucTemp;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateData);
+
+ //
+ // Initialize the work space in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateData;
+ psInst->ulDataSize = ulSize;
+ psInst->pucData = pucData;
+
+ //
+ // Save the base address of the USB controller.
+ //
+ psInst->ulUSBBase = USB_INDEX_TO_BASE(ulIndex);
+
+ //
+ // No device is currently transfering data on EP0.
+ //
+ psInst->ulEP0Owner = INVALID_DEVICE_INDEX;
+
+ //
+ // Set the device information for the composite device.
+ //
+ psInst->psDevInfo = &g_sCompositeDeviceInfo;
+
+ g_pCompConfigDescriptors[0] = &psInst->sCompConfigHeader;
+ g_pCompConfigDescriptors[0]->ucNumSections = 0;
+ g_pCompConfigDescriptors[0]->psSections =
+ (const tConfigSection * const *)psDevice->psPrivateData->ppsCompSections;
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pucTemp = (unsigned char *)&psInst->sConfigDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(lIdx = 0; lIdx < g_pCompConfigDescriptor[0]; lIdx++)
+ {
+ pucTemp[lIdx] = g_pCompConfigDescriptor[lIdx];
+ }
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pucTemp = (unsigned char *)&psInst->sDeviceDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(lIdx = 0; lIdx < g_pCompDeviceDescriptor[0]; lIdx++)
+ {
+ pucTemp[lIdx] = g_pCompDeviceDescriptor[lIdx];
+ }
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psInst->sDeviceDescriptor.idVendor = psDevice->usVID;
+ psInst->sDeviceDescriptor.idProduct = psDevice->usPID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->sConfigDescriptor.bmAttributes = psDevice->ucPwrAttributes;
+ psInst->sConfigDescriptor.bMaxPower =
+ (unsigned char)(psDevice->usMaxPowermA>>1);
+
+ g_sCompositeDeviceInfo.pDeviceDescriptor =
+ (const unsigned char *)&psInst->sDeviceDescriptor;
+
+ //
+ // Plug in the client's string table to the device information
+ // structure.
+ //
+ psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psInst->psDevInfo->ulNumStringDescriptors =
+ psDevice->ulNumStringDescriptors;
+
+ //
+ // 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);
+ }
+
+ //
+ // Set the instance data for this device.
+ //
+ psInst->psDevInfo->pvInstance = (void *)psDevice;
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ulIndex, psInst->psDevInfo);
+
+ //
+ // Return the pointer to the instance indicating that everything went
+ // well.
+ //
+ return((void *)psDevice);
+}
+
+//****************************************************************************
+//
+//! Shuts down the composite device.
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDCompositeInit().
+//!
+//! This function terminates composite device interface for the instance
+//! supplied. Following this call, the \e pvInstance instance should not me
+//! used in any other calls.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+USBDCompositeTerm(void *pvInstance)
+{
+ ASSERT(pvInstance != 0);
+
+}
+
+//****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//****************************************************************************
+
diff --git a/usblib/device/usbdcomp.h b/usblib/device/usbdcomp.h
new file mode 100644
index 0000000..5d26352
--- /dev/null
+++ b/usblib/device/usbdcomp.h
@@ -0,0 +1,297 @@
+//*****************************************************************************
+//
+// usbdcomp.h - USB composite device class driver.
+//
+// Copyright (c) 2010-2012 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 9453 of the Stellaris 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 *pDeviceInfo;
+
+ //
+ // 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.
+ //
+ unsigned char ucIfaceOffset;
+
+} tUSBDCompositeEntry;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// composite device class. The memory for this structure is pointed to by
+// the psPrivateData 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.
+ //
+ unsigned long ulUSBBase;
+
+ //
+ // The device information pointer.
+ //
+ tDeviceInfo *psDevInfo;
+
+ //
+ // 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.
+ //
+ unsigned long ulDataSize;
+ unsigned char *pucData;
+
+ //
+ // The current "owner" of endpoint 0. This is used to track the device
+ // class which is currently transferring data on EP0.
+ //
+ unsigned long ulEP0Owner;
+}
+tCompositeInstance;
+
+//*****************************************************************************
+//
+//! 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 *psDevice;
+
+ //
+ //! This is the instance data for the device structure.
+ //
+ void *pvInstance;
+}
+tCompositeEntry;
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! The maximum power consumption of the device, expressed in mA.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the composite
+ //! device.
+ //
+ 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (number of strings)) *
+ //! (number of languages)).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! The number of devices in the psDevices array.
+ //
+ unsigned long ulNumDevices;
+
+ //
+ //! This application supplied array holds the the top level device class
+ //! information as well as the Instance data for that class.
+ //
+ tCompositeEntry *psDevices;
+
+ //
+ //! A pointer to per-device workspace used by the composite device. This
+ //! buffer must be sized to contain at least ulNumDevices long integers
+ //! (or 4 * ulNumDevices bytes). It 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.
+ //
+ unsigned long *pulDeviceWorkspace;
+
+ //
+ //! A pointer to RAM work space for this device instance. The client
+ //! must fill in this field with a pointer to at least
+ //! sizeof(tCompositeInstance) bytes of read/write storage that the
+ //! library can use for driver work space. 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 *psPrivateData;
+}
+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(unsigned long ulIndex,
+ tUSBDCompositeDevice *psCompDevice,
+ unsigned long ulSize,
+ unsigned char *pucData);
+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..9737607
--- /dev/null
+++ b/usblib/device/usbdconfig.c
@@ -0,0 +1,654 @@
+//*****************************************************************************
+//
+// usbdconfig.c - High level USB device configuration function.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mask used to preserve various endpoint configuration flags.
+//
+//*****************************************************************************
+#define EP_FLAGS_MASK (USB_EP_MODE_MASK | USB_EP_DEV_IN | \
+ USB_EP_DEV_OUT)
+
+//*****************************************************************************
+//
+// Structure used in compiling FIFO size and endpoint properties from a
+// configuration descriptor.
+//
+//*****************************************************************************
+typedef struct
+{
+ unsigned long ulSize[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 unsigned long
+GetEndpointFIFOSize(unsigned long ulMaxPktSize, const tFIFOEntry *psFIFOParams,
+ unsigned long *pupBytesUsed)
+{
+ unsigned long ulBytes;
+ unsigned long ulLoop;
+ unsigned long ulFIFOSize;
+
+ //
+ // What is the basic size required for a single buffered FIFO entry
+ // containing the required number of packets?
+ //
+ ulBytes = ulMaxPktSize;
+
+ //
+ // 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(ulLoop = USB_FIFO_SZ_8; ulLoop <= USB_FIFO_SZ_4096; ulLoop++)
+ {
+ //
+ // How many bytes does this FIFO value represent?
+ //
+ ulFIFOSize = USB_FIFO_SZ_TO_BYTES(ulLoop);
+
+ //
+ // Is this large enough to satisfy the request?
+ //
+ if(ulFIFOSize >= ulBytes)
+ {
+ //
+ // Yes - are we being asked to double-buffer the FIFO for this
+ // endpoint?
+ //
+ if(psFIFOParams->bDoubleBuffer)
+ {
+ //
+ // Yes - FIFO requirement is double in this case.
+ //
+ *pupBytesUsed = ulFIFOSize * 2;
+ return(ulLoop | USB_FIFO_SIZE_DB_FLAG);
+ }
+ else
+ {
+ //
+ // No double buffering so just return the size and associated
+ // flag.
+ //
+ *pupBytesUsed = ulFIFOSize;
+ return(ulLoop);
+ }
+ }
+ }
+
+ //
+ // 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, unsigned long *pulEPIndex,
+ unsigned long *pulMaxPktSize, unsigned long *pulFlags)
+{
+ //
+ // Get the endpoint index.
+ //
+ *pulEPIndex = psEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+
+ //
+ // Extract the maximum packet size.
+ //
+ *pulMaxPktSize = psEndpoint->wMaxPacketSize & USB_EP_MAX_PACKET_COUNT_M;
+
+ //
+ // Is this an IN or an OUT endpoint?
+ //
+ *pulFlags = (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:
+ *pulFlags |= USB_EP_MODE_CTRL;
+ break;
+
+ case USB_EP_ATTR_BULK:
+ *pulFlags |= USB_EP_MODE_BULK;
+ break;
+
+ case USB_EP_ATTR_INT:
+ *pulFlags |= USB_EP_MODE_INT;
+ break;
+
+ case USB_EP_ATTR_ISOC:
+ *pulFlags |= USB_EP_MODE_ISOC;
+ break;
+ }
+}
+
+//*****************************************************************************
+//
+//! Configure the USB controller appropriately for the device whose config
+//! 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.
+//!
+//! USBDCDConfig() is an optional call and applications may chose to make
+//! direct calls to SysCtlPeripheralEnable(), SysCtlUSBPLLEnable(),
+//! USBDevEndpointConfigSet() and USBFIFOConfigSet() instead of using this
+//! function. If this function is used, it must be called prior to
+//! USBDCDInit() since this call assumes that the low level hardware
+//! configuration has been completed before it is made.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+tBoolean
+USBDeviceConfig(tDeviceInstance *psDevInst, const tConfigHeader *psConfig)
+{
+ unsigned long ulLoop;
+ unsigned long ulCount;
+ unsigned long ulNumInterfaces;
+ unsigned long ulEpIndex;
+ unsigned long ulEpType;
+ unsigned long ulMaxPkt;
+ unsigned long ulNumEndpoints;
+ unsigned long ulFlags;
+ unsigned long ulBytesUsed;
+ unsigned long ulSection;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ tFIFOConfig const *psFIFOConfig;
+ tUSBEndpointInfo psEPInfo[NUM_USB_EP - 1];
+
+ //
+ // A valid device instance is required.
+ //
+ ASSERT(psDevInst != 0);
+
+ //
+ // Catch bad pointers in a debug build.
+ //
+ ASSERT(psConfig);
+
+ psFIFOConfig = psDevInst->psInfo->psFIFOConfig;
+
+ //
+ // Clear out our endpoint info.
+ //
+ for(ulLoop = 0; ulLoop < (NUM_USB_EP - 1); ulLoop++)
+ {
+ psEPInfo[ulLoop].ulSize[EP_INFO_IN] = 0;
+ psEPInfo[ulLoop].ulSize[EP_INFO_OUT] = 0;
+ }
+
+ //
+ // How many (total) endpoints does this configuration describe?
+ //
+ ulNumEndpoints = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_ENDPOINT);
+
+ //
+ // How many interfaces are included?
+ //
+ ulNumInterfaces = 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(ulLoop = 0; ulLoop < ulNumEndpoints; ulLoop++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = (tEndpointDescriptor *)USBDCDConfigDescGet(
+ psConfig, USB_DTYPE_ENDPOINT, ulLoop,
+ &ulSection);
+
+ //
+ // Extract the endpoint number and whether it is an IN or OUT
+ // endpoint.
+ //
+ ulEpIndex = (unsigned long)
+ psEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+ ulEpType = (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((ulEpIndex >= NUM_USB_EP) || (ulEpIndex == 0))
+ {
+ return(false);
+ }
+
+ //
+ // Does this endpoint have a max packet size requirement larger than
+ // any previous use we have seen?
+ //
+ if(psEndpoint->wMaxPacketSize >
+ psEPInfo[ulEpIndex - 1].ulSize[ulEpType])
+ {
+ //
+ // Yes - remember the new maximum packet size.
+ //
+ psEPInfo[ulEpIndex - 1].ulSize[ulEpType] =
+ 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(ulLoop = 0; ulLoop < ulNumInterfaces; ulLoop++)
+ {
+ //
+ // Get the next interface descriptor in the config descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig,
+ ulLoop,
+ USB_DESC_ANY,
+ &ulSection);
+
+ //
+ // 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.
+ //
+ ulNumEndpoints = (unsigned long)psInterface->bNumEndpoints;
+
+ //
+ // Walk through each endpoint in this interface and configure
+ // it appropriately.
+ //
+ for(ulCount = 0; ulCount < ulNumEndpoints; ulCount++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = USBDCDConfigGetInterfaceEndpoint(psConfig,
+ psInterface->bInterfaceNumber,
+ psInterface->bAlternateSetting,
+ ulCount);
+
+ //
+ // Make sure we got a good pointer.
+ //
+ if(psEndpoint)
+ {
+ //
+ // Determine maximum packet size and flags from the
+ // endpoint descriptor.
+ //
+ GetEPDescriptorType(psEndpoint, &ulEpIndex, &ulMaxPkt,
+ &ulFlags);
+
+ //
+ // Make sure no-one is trying to configure endpoint 0.
+ //
+ if(!ulEpIndex)
+ {
+ return(false);
+ }
+
+ //
+ // Include any additional flags that the user wants.
+ //
+ if((ulFlags & (USB_EP_DEV_IN | USB_EP_DEV_OUT)) ==
+ USB_EP_DEV_IN)
+ {
+ //
+ // This is an IN endpoint.
+ //
+ ulFlags |= (unsigned long)(
+ psFIFOConfig->sIn[ulEpIndex - 1].usEPFlags);
+ }
+ else
+ {
+ //
+ // This is an OUT endpoint.
+ //
+ ulFlags |= (unsigned long)(
+ psFIFOConfig->sOut[ulEpIndex - 1].usEPFlags);
+ }
+
+ //
+ // Set the endpoint configuration.
+ //
+ USBDevEndpointConfigSet(USB0_BASE,
+ INDEX_TO_USB_EP(ulEpIndex),
+ ulMaxPkt, ulFlags);
+ }
+ }
+ }
+ }
+
+ //
+ // 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.
+ //
+ ulCount = MAX_PACKET_SIZE_EP0;
+ for(ulLoop = 1; ulLoop < NUM_USB_EP; ulLoop++)
+ {
+ //
+ // Configure the IN endpoint at this index if it is referred to
+ // anywhere.
+ //
+ if(psEPInfo[ulLoop - 1].ulSize[EP_INFO_IN])
+ {
+ //
+ // What FIFO size flag do we use for this endpoint?
+ //
+ ulMaxPkt = GetEndpointFIFOSize(
+ psEPInfo[ulLoop - 1].ulSize[EP_INFO_IN],
+ &(psFIFOConfig->sIn[ulLoop - 1]),
+ &ulBytesUsed);
+
+ //
+ // If we are told that 0 bytes of FIFO will be used, this implies
+ // that there is an error in psFIFOConfig or the descriptor
+ // somewhere so return an error indicator to the caller.
+ //
+ if(!ulBytesUsed)
+ {
+ return(false);
+ }
+
+ //
+ // Now actually configure the FIFO for this endpoint.
+ //
+ USBFIFOConfigSet(USB0_BASE, INDEX_TO_USB_EP(ulLoop), ulCount,
+ ulMaxPkt, USB_EP_DEV_IN);
+ ulCount += ulBytesUsed;
+ }
+
+ //
+ // Configure the OUT endpoint at this index.
+ //
+ if(psEPInfo[ulLoop - 1].ulSize[EP_INFO_OUT])
+ {
+ //
+ // What FIFO size flag do we use for this endpoint?
+ //
+ ulMaxPkt = GetEndpointFIFOSize(
+ psEPInfo[ulLoop - 1].ulSize[EP_INFO_OUT],
+ &(psFIFOConfig->sOut[ulLoop - 1]),
+ &ulBytesUsed);
+
+ //
+ // If we are told that 0 bytes of FIFO will be used, this implies
+ // that there is an error in psFIFOConfig or the descriptor
+ // somewhere so return an error indicator to the caller.
+ //
+ if(!ulBytesUsed)
+ {
+ return(false);
+ }
+
+ //
+ // Now actually configure the FIFO for this endpoint.
+ //
+ USBFIFOConfigSet(USB0_BASE, INDEX_TO_USB_EP(ulLoop), ulCount,
+ ulMaxPkt, USB_EP_DEV_OUT);
+ ulCount += ulBytesUsed;
+ }
+
+ }
+
+ //
+ // 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 ucInterfaceNum 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 ucAlternateSetting 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.
+//
+//*****************************************************************************
+tBoolean
+USBDeviceConfigAlternate(tDeviceInstance *psDevInst, const tConfigHeader *psConfig,
+ unsigned char ucInterfaceNum,
+ unsigned char ucAlternateSetting)
+{
+ unsigned long ulNumInterfaces;
+ unsigned long ulNumEndpoints;
+ unsigned long ulLoop;
+ unsigned long ulCount;
+ unsigned long ulMaxPkt;
+ unsigned long ulFlags;
+ unsigned long ulSection;
+ unsigned long ulEpIndex;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ tFIFOConfig const *psFIFOConfig;
+
+ //
+ // How many interfaces are included in the descriptor?
+ //
+ ulNumInterfaces = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_INTERFACE);
+
+ psFIFOConfig = psDevInst->psInfo->psFIFOConfig;
+
+ //
+ // Find the interface descriptor for the supplied interface and alternate
+ // setting numbers.
+ //
+
+ for(ulLoop = 0; ulLoop < ulNumInterfaces; ulLoop++)
+ {
+ //
+ // Get the next interface descriptor in the config descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ulLoop, USB_DESC_ANY,
+ &ulSection);
+
+ //
+ // Is this the default interface (bAlternateSetting set to 0)?
+ //
+ if(psInterface &&
+ (psInterface->bInterfaceNumber == ucInterfaceNum) &&
+ (psInterface->bAlternateSetting == ucAlternateSetting))
+ {
+ //
+ // 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?
+ //
+ ulNumEndpoints = (unsigned long)psInterface->bNumEndpoints;
+
+ //
+ // Walk through each endpoint in turn.
+ //
+ for(ulCount = 0; ulCount < ulNumEndpoints; ulCount++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = USBDCDConfigGetInterfaceEndpoint(psConfig,
+ psInterface->bInterfaceNumber,
+ psInterface->bAlternateSetting,
+ ulCount);
+
+ //
+ // Make sure we got a good pointer.
+ //
+ if(psEndpoint)
+ {
+ //
+ // Determine maximum packet size and flags from the
+ // endpoint descriptor.
+ //
+ GetEPDescriptorType(psEndpoint, &ulEpIndex, &ulMaxPkt,
+ &ulFlags);
+
+ //
+ // Make sure no-one is trying to configure endpoint 0.
+ //
+ if(!ulEpIndex)
+ {
+ return(false);
+ }
+
+ //
+ // Include any additional flags that the user wants.
+ //
+ if((ulFlags & (USB_EP_DEV_IN | USB_EP_DEV_OUT)) ==
+ USB_EP_DEV_IN)
+ {
+ //
+ // This is an IN endpoint.
+ //
+ ulFlags |= (unsigned long)(
+ psFIFOConfig->sIn[ulEpIndex - 1].usEPFlags);
+ }
+ else
+ {
+ //
+ // This is an OUT endpoint.
+ //
+ ulFlags |= (unsigned long)(
+ psFIFOConfig->sOut[ulEpIndex - 1].usEPFlags);
+ }
+
+ //
+ // Set the endpoint configuration.
+ //
+ USBDevEndpointConfigSet(USB0_BASE,
+ INDEX_TO_USB_EP(ulEpIndex),
+ ulMaxPkt, ulFlags);
+ }
+ }
+
+ //
+ // 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..8060eca
--- /dev/null
+++ b/usblib/device/usbddfu-rt.c
@@ -0,0 +1,589 @@
+//*****************************************************************************
+//
+// usbddfu-rt.c - USB Device Firmware Update runtime device class driver.
+//
+// Copyright (c) 2010-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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_map.h"
+#include "usblib/usblib.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 unsigned char g_pDFUDeviceDescriptor[] =
+{
+ 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 indentifier.
+ 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.
+//
+//*****************************************************************************
+unsigned char g_pDFUConfigDescriptor[] =
+{
+ //
+ // 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.
+//
+//*****************************************************************************
+unsigned char g_pDFUInterface[] =
+{
+ //
+ // 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.
+//
+//*****************************************************************************
+unsigned char g_pDFUFunctionalDesc[] =
+{
+ //
+ // 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_pDFUConfigDescriptor),
+ g_pDFUConfigDescriptor
+};
+
+const tConfigSection g_sDFUInterfaceSection =
+{
+ sizeof(g_pDFUInterface),
+ g_pDFUInterface
+};
+
+const tConfigSection g_sDFUFunctionalDescSection =
+{
+ sizeof(g_pDFUFunctionalDesc),
+ g_pDFUFunctionalDesc
+};
+
+//*****************************************************************************
+//
+// 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(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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_pDFUConfigDescriptors[] =
+{
+ &g_sDFUConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleGetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest);
+static void HandleRequest(void *pvInstance, tUSBRequest *pUSBRequest);
+static void HandleDevice(void *pvInstance, unsigned long ulRequest,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB DFU devices.
+//
+//*****************************************************************************
+tDeviceInfo g_sDFUDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ HandleGetDescriptor, // GetDescriptor
+ HandleRequest, // RequestHandler
+ 0, // InterfaceChange
+ 0, // ConfigChange
+ 0, // DataReceived
+ 0, // DataSentCallback
+ 0, // ResetHandler
+ 0, // SuspendHandler
+ 0, // ResumeHandler
+ 0, // DisconnectHandler
+ 0, // EndpointHandler
+ HandleDevice, // Device handler.
+ },
+ 0, // Device descriptor (unused - composite device)
+ g_pDFUConfigDescriptors,
+ 0, // Completed during USBDDFUCompositeInit().
+ 0, // Completed during USBDDFUCompositeInit().
+ &g_sUSBDefaultFIFOConfig,
+ 0
+};
+
+//*****************************************************************************
+//
+// 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 *pvInstance, unsigned long ulRequest, void *pvRequestData)
+{
+ tDFUInstance *psInst;
+ unsigned char *pucData;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = ((tUSBDDFUDevice *)pvInstance)->psPrivateDFUData;
+
+ //
+ // Get a byte pointer to the data.
+ //
+ pucData = (unsigned char *)pvRequestData;
+
+ //
+ // Which request event have we been passed?
+ //
+ switch(ulRequest)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the interface number.
+ //
+ psInst->ucInterface = pucData[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 pvInstance is the instance data for this request.
+// \param pUSBRequest 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned long ulSize;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Which type of class descriptor are we being asked for? We only support
+ // 1 type - the DFU functional descriptor.
+ //
+ if(((pUSBRequest->wValue >> 8) == USB_DFU_FUNC_DESCRIPTOR_TYPE) &&
+ ((pUSBRequest->wValue & 0xFF) == 0))
+ {
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if((unsigned short)g_pDFUFunctionalDesc[0] > pUSBRequest->wLength)
+ {
+ ulSize = (unsigned long)pUSBRequest->wLength;
+ }
+ else
+ {
+ ulSize = (unsigned long)g_pDFUFunctionalDesc[0];
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0, g_pDFUFunctionalDesc, ulSize);
+ }
+ 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 pvInstance is the instance data for this HID device.
+// \param pUSBRequest 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ tDFUInstance *psInst;
+ const tUSBDDFUDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psDevice = pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateDFUData;
+
+ //
+ // Make sure the request was for this interface.
+ //
+ if(pUSBRequest->wIndex != psInst->ucInterface)
+ {
+ return;
+ }
+
+ //
+ // Determine the type of request.
+ //
+ switch(pUSBRequest->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 ulIndex is the index of the USB controller which is to be
+//! initialized for DFU runtime device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the DFU device.
+//!
+//! \return Returns NULL on failure or the \e psDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDDFUCompositeInit(unsigned long ulIndex, const tUSBDDFUDevice *psDevice)
+{
+ tDFUInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->psPrivateDFUData);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateDFUData;
+ psInst->psDevInfo = &g_sDFUDeviceInfo;
+ psInst->ulUSBBase = USB0_BASE;
+ psInst->bConnected = false;
+ psInst->ucInterface = 0;
+
+ //
+ // Tag the device information with our device data structure pointer.
+ //
+ psInst->psDevInfo->pvInstance = (void *)psDevice;
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the DFU device.
+//!
+//! \param pvInstance 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 pvInstance instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDDFUCompositeTerm(void *pvInstance)
+{
+ tDFUInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = ((tUSBDDFUDevice *)pvInstance)->psPrivateDFUData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(0);
+
+ psInst->ulUSBBase = 0;
+ psInst->psDevInfo = (tDeviceInfo *)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))(*(unsigned long *)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..561d1a9
--- /dev/null
+++ b/usblib/device/usbddfu-rt.h
@@ -0,0 +1,163 @@
+//*****************************************************************************
+//
+// usbddfu-rt.h - Definitions used by runtime DFU class devices.
+//
+// Copyright (c) 2010-2012 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 9453 of the Stellaris 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
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! 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 ulSize parameter.
+//
+// For reference this is sizeof(g_pDFUInterface) + sizeof(g_pDFUFunctionalDesc)
+//
+//*****************************************************************************
+#define COMPOSITE_DDFU_SIZE (9 + 9)
+
+//*****************************************************************************
+//
+//! 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 pointed to by the
+// psPrivateDFUData field in the tUSBDDFUDevice structure passed in the
+// USBDDFUCompositeInit() function.
+//
+//*****************************************************************************
+typedef struct
+{
+ unsigned long ulUSBBase;
+ tDeviceInfo *psDevInfo;
+ unsigned char ucInterface;
+ tBoolean 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.
+ //
+ tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the pfnCallback function.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to private instance data for this device instance. 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 *psPrivateDFUData;
+}
+tUSBDDFUDevice;
+
+//*****************************************************************************
+//
+// Device information structure required to construct the composite device.
+//
+//*****************************************************************************
+extern tDeviceInfo g_sDFUDeviceInfo;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDDFUCompositeInit(unsigned long ulIndex,
+ const tUSBDDFUDevice *psDevice);
+extern void USBDDFUCompositeTerm(void *pvInstance);
+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..e8aa64e
--- /dev/null
+++ b/usblib/device/usbdenum.c
@@ -0,0 +1,2900 @@
+//*****************************************************************************
+//
+// usbenum.c - Enumeration code to handle all endpoint zero traffic.
+//
+// Copyright (c) 2007-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.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/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+// External prototypes.
+//
+//*****************************************************************************
+extern tUSBMode g_eUSBMode;
+
+//*****************************************************************************
+//
+// Local functions prototypes.
+//
+//*****************************************************************************
+static void USBDGetStatus(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDClearFeature(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDSetFeature(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDSetAddress(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDGetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDSetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDGetConfiguration(void *pvInstance,
+ tUSBRequest *pUSBRequest);
+static void USBDSetConfiguration(void *pvInstance,
+ tUSBRequest *pUSBRequest);
+static void USBDGetInterface(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDSetInterface(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDSyncFrame(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDEP0StateTx(unsigned long ulIndex);
+static void USBDEP0StateTxConfig(unsigned long ulIndex);
+static long USBDStringIndexFromRequest(unsigned short usLang,
+ unsigned short usIndex);
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The default USB endpoint FIFO configuration structure. This structure
+//! contains definitions to set all USB FIFOs into single buffered mode with
+//! no DMA use. Each endpoint's FIFO is sized to hold the largest maximum
+//! packet size for any interface alternate setting in the current
+//! configuration descriptor. A pointer to this structure may be passed in the
+//! psFIFOConfig field of the tDeviceInfo structure passed to USBCDCInit if the
+//! application does not require any special handling of the USB controller
+//! FIFO.
+//
+//*****************************************************************************
+const tFIFOConfig g_sUSBDefaultFIFOConfig =
+{
+ {
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 }
+ },
+ {
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 },
+ { false, 0 }
+ },
+};
+
+//*****************************************************************************
+//
+// Indices into the ucHalt 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.ulDevAddress 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 buffer for reading data coming into EP0
+//
+//*****************************************************************************
+static unsigned char g_pucDataBufferIn[EP0_MAX_PACKET_SIZE];
+
+tDeviceInstance g_psUSBDevice[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 the USB library device control driver for a given hardware
+//! controller.
+//!
+//! \param ulIndex 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.
+//!
+//! This function must be called by any application which wishes to operate
+//! as a USB device. It 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 device information structure passed in \e psDevice must remain
+//! unchanged between this call and any matching call to USBDCDTerm() since
+//! it is not copied by the USB library.
+//!
+//! The USBStackModeSet() function can be called with USB_MODE_FORCE_DEVICE 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.
+//!
+//! \note Forcing of the USB controller mode feature is not available on all
+//! Stellaris microcontrollers. Consult the data sheet for the microcontroller
+//! that the application is using to determine if this feature is available.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDInit(unsigned long ulIndex, tDeviceInfo *psDevice)
+{
+ const tConfigHeader *psHdr;
+ const tConfigDescriptor *psDesc;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice != 0);
+
+ //
+ // Should not call this if the stack is in host mode.
+ //
+ ASSERT(g_eUSBMode != USB_MODE_HOST);
+ ASSERT(g_eUSBMode != USB_MODE_FORCE_HOST);
+
+ //
+ // Initialize a couple of fields in the device state structure.
+ //
+ g_psUSBDevice[0].ulConfiguration = DEFAULT_CONFIG_ID;
+ g_psUSBDevice[0].ulDefaultConfiguration = DEFAULT_CONFIG_ID;
+
+ //
+ // Remember the device information pointer.
+ //
+ g_psUSBDevice[0].psInfo = psDevice;
+ g_psUSBDevice[0].pvInstance = psDevice->pvInstance;
+ g_psUSBDevice[0].eEP0State = USB_STATE_IDLE;
+
+ //
+ // Default to device mode if no mode was set.
+ //
+ if(g_eUSBMode == USB_MODE_NONE)
+ {
+ g_eUSBMode = USB_MODE_DEVICE;
+ }
+
+ //
+ // Only do hardware update if the stack is in not in OTG mode.
+ //
+ if(g_eUSBMode != USB_MODE_OTG)
+ {
+ //
+ // 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();
+
+ //
+ // If the application is requesting OTG or DEVICE mode then set the mode
+ // detection to OTG. If the mode was device then the rest of the library
+ // should make sure that no OTG signaling actually occurs.
+ //
+ if((g_eUSBMode == USB_MODE_DEVICE) || (g_eUSBMode == USB_MODE_OTG))
+ {
+ //
+ // Switch to OTG mode to detect VBUS changes.
+ //
+ MAP_USBOTGMode(USB0_BASE);
+ }
+ else
+ {
+ //
+ // Force device mode on devices that support forcing mode.
+ //
+ MAP_USBDevMode(USB0_BASE);
+ }
+
+ //
+ // In all other cases, set the mode to device this function should not
+ // be called in OTG mode.
+ //
+ g_eUSBMode = USB_MODE_DEVICE;
+ }
+
+ //
+ // Initialize the USB tick module.
+ //
+ InternalUSBTickInit();
+
+ //
+ // Get a pointer to the default configuration descriptor.
+ //
+ psHdr = psDevice->ppConfigDescriptors[
+ g_psUSBDevice[0].ulDefaultConfiguration - 1];
+ psDesc = (const tConfigDescriptor *)(psHdr->psSections[0]->pucData);
+
+ //
+ // Default to the state where remote wake up is disabled.
+ //
+ g_psUSBDevice[0].ucStatus = 0;
+ g_psUSBDevice[0].bRemoteWakeup = false;
+
+ //
+ // Determine the self- or bus-powered state based on the flags the
+ // user provided.
+ //
+ g_psUSBDevice[0].bPwrSrcSet = false;
+
+ if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) == USB_CONF_ATTR_SELF_PWR)
+ {
+ g_psUSBDevice[0].ucStatus |= USB_STATUS_SELF_PWR;
+ }
+ else
+ {
+ g_psUSBDevice[0].ucStatus &= ~USB_STATUS_SELF_PWR;
+ }
+
+ //
+ // Only do hardware update if the stack is not in OTG mode.
+ //
+ if(g_eUSBMode != USB_MODE_OTG)
+ {
+ //
+ // 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);
+
+ //
+ // Make sure we disconnect from the host for a while. This ensures
+ // that the host will enumerate us even if we were previously
+ // connected to the bus.
+ //
+ MAP_USBDevDisconnect(USB0_BASE);
+
+ //
+ // Wait about 100mS.
+ //
+ OS_DELAY(MAP_SysCtlClockGet() / 30);
+
+ //
+ // Attach the device using the soft connect.
+ //
+ MAP_USBDevConnect(USB0_BASE);
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(INT_USB0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Free the USB library device control driver for a given hardware controller.
+//!
+//! \param ulIndex 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(unsigned long ulIndex)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ulIndex == 0);
+
+ //
+ // Disable the USB interrupts.
+ //
+ OS_INT_DISABLE(INT_USB0);
+
+ //
+ // Reset the tick handlers so that they can be reconfigured when and if
+ // USBDCDInit() is called.
+ //
+ InternalUSBTickReset();
+
+ g_psUSBDevice[0].psInfo = (tDeviceInfo *)0;
+ g_psUSBDevice[0].pvInstance = 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 ulIndex is the index of the USB controller from which the data
+//! is being requested.
+//! \param pucData is a pointer to the buffer to fill with data from the USB
+//! host.
+//! \param ulSize 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>tDeviceInfo.sCallbacks.pfnDataReceived</tt> should 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(unsigned long ulIndex, unsigned char *pucData,
+ unsigned long ulSize)
+{
+ ASSERT(ulIndex == 0);
+
+ //
+ // Enter the RX state on end point 0.
+ //
+ g_psUSBDevice[0].eEP0State = USB_STATE_RX;
+
+ //
+ // Save the pointer to the data.
+ //
+ g_psUSBDevice[0].pEP0Data = pucData;
+
+ //
+ // Location to save the current number of bytes received.
+ //
+ g_psUSBDevice[0].ulOUTDataSize = ulSize;
+
+ //
+ // Bytes remaining to be received.
+ //
+ g_psUSBDevice[0].ulEP0DataRemain = ulSize;
+}
+
+//*****************************************************************************
+//
+//! This function requests transfer of data to the host on endpoint zero.
+//!
+//! \param ulIndex is the index of the USB controller which is to be used to
+//! send the data.
+//! \param pucData is a pointer to the buffer to send via endpoint zero.
+//! \param ulSize 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>tDeviceInfo.sCallbacks.pfnDataSent</tt> should contain a valid function
+//! pointer. This callback could be used to free up the buffer passed into
+//! this function in the \e pucData parameter. The contents of the \e pucData
+//! buffer must remain unchanged until the <tt>pfnDataSent</tt> callback is
+//! received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDSendDataEP0(unsigned long ulIndex, unsigned char *pucData,
+ unsigned long ulSize)
+{
+ ASSERT(ulIndex == 0);
+
+ //
+ // Return the externally provided device descriptor.
+ //
+ g_psUSBDevice[0].pEP0Data = pucData;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ g_psUSBDevice[0].ulEP0DataRemain = ulSize;
+
+ //
+ // Save the total size of the data sent.
+ //
+ g_psUSBDevice[0].ulOUTDataSize = ulSize;
+
+ //
+ // Now in the transmit data state.
+ //
+ USBDEP0StateTx(0);
+}
+
+//*****************************************************************************
+//
+//! This function sets the default configuration for the device.
+//!
+//! \param ulIndex is the index of the USB controller whose default
+//! configuration is to be set.
+//! \param ulDefaultConfig 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>ppConfigDescriptors</tt> array for the device.
+//!
+//! If this function is not called, the USB library will return the first
+//! configuration in the <tt>ppConfigDescriptors</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>ppConfigDescriptors</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(unsigned long ulIndex,
+ unsigned long ulDefaultConfig)
+{
+ ASSERT(ulIndex == 0);
+
+ g_psUSBDevice[0].ulDefaultConfiguration = ulDefaultConfig;
+}
+
+//*****************************************************************************
+//
+//! This function generates a stall condition on endpoint zero.
+//!
+//! \param ulIndex 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(unsigned long ulIndex)
+{
+ ASSERT(ulIndex == 0);
+
+ //
+ // Stall the endpoint in question.
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, USB_EP_0, USB_EP_DEV_OUT);
+
+ //
+ // Enter the stalled state.
+ //
+ g_psUSBDevice[0].eEP0State = USB_STATE_STALL;
+}
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the library.
+//!
+//! \param ulIndex is the index of the USB controller whose device power
+//! status is being reported.
+//! \param ucPower 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(unsigned long ulIndex, unsigned char ucPower)
+{
+ //
+ // Check for valid parameters.
+ //
+ ASSERT((ucPower == USB_STATUS_BUS_PWR) ||
+ (ucPower == USB_STATUS_SELF_PWR));
+ ASSERT(ulIndex == 0);
+
+ //
+ // Update the device status with the new power status flag.
+ //
+ g_psUSBDevice[0].bPwrSrcSet = true;
+ g_psUSBDevice[0].ucStatus &= ~USB_STATUS_PWR_M;
+ g_psUSBDevice[0].ucStatus |= ucPower;
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param ulIndex 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.
+//
+//*****************************************************************************
+tBoolean
+USBDCDRemoteWakeupRequest(unsigned long ulIndex)
+{
+ //
+ // Check for parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+
+ //
+ // Is remote wake up signaling currently enabled?
+ //
+ if(g_psUSBDevice[0].ucStatus & 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_psUSBDevice[0].bRemoteWakeup)
+ {
+ //
+ // No - we are not in the middle of a wake up sequence so start
+ // one here.
+ //
+ g_psUSBDevice[0].ucRemoteWakeupCount = 0;
+ g_psUSBDevice[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(tDeviceInstance *psDevInst)
+{
+ if(g_psUSBDevice[0].bRemoteWakeup)
+ {
+ //
+ // Increment the millisecond counter we use to time the resume
+ // signaling.
+ //
+ g_psUSBDevice[0].ucRemoteWakeupCount++;
+
+ //
+ // Have we reached the 10mS mark? If so, we need to turn the signaling
+ // off again.
+ //
+ if(g_psUSBDevice[0].ucRemoteWakeupCount == 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 doesn't 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_psUSBDevice[0].ucRemoteWakeupCount == REMOTE_WAKEUP_READY_MS)
+ {
+ //
+ // We are now finished with the remote wake up signaling.
+ //
+ g_psUSBDevice[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_psUSBDevice[0].psInfo->sCallbacks.pfnResumeHandler)
+ {
+ g_psUSBDevice[0].psInfo->sCallbacks.pfnResumeHandler(
+ g_psUSBDevice[0].pvInstance);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// 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(unsigned long ulIndex)
+{
+ unsigned long ulSize;
+ tUSBRequest *pRequest;
+
+ //
+ // Cast the buffer to a request structure.
+ //
+ pRequest = (tUSBRequest *)g_pucDataBufferIn;
+
+ //
+ // Set the buffer size.
+ //
+ ulSize = EP0_MAX_PACKET_SIZE;
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE,
+ USB_EP_0,
+ g_pucDataBufferIn,
+ &ulSize);
+
+ //
+ // If there was a null setup packet then just return.
+ //
+ if(!ulSize)
+ {
+ return;
+ }
+
+ //
+ // See if this is a standard request or not.
+ //
+ if((pRequest->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_psUSBDevice[0].psInfo->sCallbacks.pfnRequestHandler)
+ {
+ g_psUSBDevice[0].psInfo->sCallbacks.pfnRequestHandler(
+ g_psUSBDevice[0].pvInstance, pRequest);
+ }
+ else
+ {
+ //
+ // If there is no handler then stall this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ }
+ else
+ {
+ //
+ // Assure that the jump table is not out of bounds.
+ //
+ if((pRequest->bRequest <
+ (sizeof(g_psUSBDStdRequests) / sizeof(tStdRequest))) &&
+ (g_psUSBDStdRequests[pRequest->bRequest] != 0))
+ {
+ //
+ // Jump table to the appropriate handler.
+ //
+ g_psUSBDStdRequests[pRequest->bRequest](&g_psUSBDevice[0],
+ pRequest);
+ }
+ 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 USB_STATE_IDLE, \b USB_STATE_TX, \b USB_STATE_RX,
+// \b USB_STATE_STALL, and \b USB_STATE_STATUS. In the \b USB_STATE_IDLE
+// state the USB controller has not received the start of a request, and once
+// it does receive the data for the request it will either enter the
+// \b USB_STATE_TX, \b USB_STATE_RX, or \b USB_STATE_STALL depending on the
+// command. If the controller enters the \b USB_STATE_TX or \b USB_STATE_RX
+// then once all data has been sent or received, it must pass through the
+// \b USB_STATE_STATUS state to allow the host to acknowledge completion of
+// the request. The \b USB_STATE_STALL is entered from \b USB_STATE_IDLE in
+// the event that the USB request was not valid. Both the \b USB_STATE_STALL
+// and \b USB_STATE_STATUS are transitional states that return to the
+// \b USB_STATE_IDLE state.
+//
+// \return None.
+//
+// USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE
+// | | |
+// |--> USB_STATE_RX - |
+// | |
+// |--> USB_STATE_STALL ---------->---------
+//
+// ----------------------------------------------------------------
+// | Current State | State 0 | State 1 |
+// | --------------------|-------------------|----------------------
+// | USB_STATE_IDLE | USB_STATE_TX/RX | USB_STATE_STALL |
+// | USB_STATE_TX | USB_STATE_STATUS | |
+// | USB_STATE_RX | USB_STATE_STATUS | |
+// | USB_STATE_STATUS | USB_STATE_IDLE | |
+// | USB_STATE_STALL | USB_STATE_IDLE | |
+// ----------------------------------------------------------------
+//
+//*****************************************************************************
+void
+USBDeviceEnumHandler(tDeviceInstance *pDevInstance)
+{
+ unsigned long ulEPStatus;
+
+ //
+ // Get the end point 0 status.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(USB0_BASE, USB_EP_0);
+
+ switch(pDevInstance->eEP0State)
+ {
+ //
+ // Handle the status state, this is a transitory state from
+ // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE.
+ //
+ case USB_STATE_STATUS:
+ {
+ //
+ // Just go back to the idle state.
+ //
+ pDevInstance->eEP0State = USB_STATE_IDLE;
+
+ //
+ // If there is a pending address change then set the address.
+ //
+ if(pDevInstance->ulDevAddress & DEV_ADDR_PENDING)
+ {
+ //
+ // Clear the pending address change and set the address.
+ //
+ pDevInstance->ulDevAddress &= ~DEV_ADDR_PENDING;
+ MAP_USBDevAddrSet(USB0_BASE, pDevInstance->ulDevAddress);
+ }
+
+ //
+ // If a new packet is already pending, we need to read it
+ // and handle whatever request it contains.
+ //
+ if(ulEPStatus & 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 USB_STATE_IDLE:
+ {
+ //
+ // Is there a packet waiting for us?
+ //
+ if(ulEPStatus & 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 USB_STATE_TX:
+ {
+ USBDEP0StateTx(0);
+ break;
+ }
+
+ //
+ // We are still in the middle of sending the configuration descriptor
+ // so handle this in the EP0StateTxConfig() function.
+ //
+ case USB_STATE_TX_CONFIG:
+ {
+ USBDEP0StateTxConfig(0);
+ break;
+ }
+
+ //
+ // Handle the receive state for commands that are receiving data on
+ // endpoint zero.
+ //
+ case USB_STATE_RX:
+ {
+ unsigned long ulDataSize;
+
+ //
+ // Set the number of bytes to get out of this next packet.
+ //
+ if(pDevInstance->ulEP0DataRemain > EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // Don't send more than EP0_MAX_PACKET_SIZE bytes.
+ //
+ ulDataSize = EP0_MAX_PACKET_SIZE;
+ }
+ else
+ {
+ //
+ // There was space so send the remaining bytes.
+ //
+ ulDataSize = pDevInstance->ulEP0DataRemain;
+ }
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0, pDevInstance->pEP0Data,
+ &ulDataSize);
+
+ //
+ // 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->ulEP0DataRemain < EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // 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);
+
+ //
+ // Return to the idle state.
+ //
+ pDevInstance->eEP0State = USB_STATE_STATUS;
+
+ //
+ // If there is a receive callback then call it.
+ //
+ if((pDevInstance->psInfo->sCallbacks.pfnDataReceived) &&
+ (pDevInstance->ulOUTDataSize != 0))
+ {
+ //
+ // Call the custom receive handler to handle the data
+ // that was received.
+ //
+ pDevInstance->psInfo->sCallbacks.pfnDataReceived(
+ pDevInstance->pvInstance,
+ pDevInstance->ulOUTDataSize);
+
+ //
+ // Indicate that there is no longer any data being waited
+ // on.
+ //
+ pDevInstance->ulOUTDataSize = 0;
+ }
+ }
+ 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->pEP0Data += ulDataSize;
+
+ //
+ // Decrement the number of bytes that are being waited on.
+ //
+ pDevInstance->ulEP0DataRemain -= ulDataSize;
+
+ break;
+ }
+ //
+ // The device stalled endpoint zero so check if the stall needs to be
+ // cleared once it has been successfully sent.
+ //
+ case USB_STATE_STALL:
+ {
+ //
+ // If we sent a stall then acknowledge this interrupt.
+ //
+ if(ulEPStatus & 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->eEP0State = USB_STATE_IDLE;
+
+ }
+ break;
+ }
+ //
+ // Halt on an unknown state, but only in DEBUG mode builds.
+ //
+ default:
+ {
+ ASSERT(0);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// 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(tDeviceInstance *pDevInstance)
+{
+ unsigned long ulLoop;
+
+ //
+ // Disable remote wake up signaling (as per USB 2.0 spec 9.1.1.6).
+ //
+ pDevInstance->ucStatus &= ~USB_STATUS_REMOTE_WAKE;
+ pDevInstance->bRemoteWakeup = false;
+
+ //
+ // Call the device dependent code to indicate a bus reset has occurred.
+ //
+ if(pDevInstance->psInfo->sCallbacks.pfnResetHandler)
+ {
+ pDevInstance->psInfo->sCallbacks.pfnResetHandler(
+ pDevInstance->pvInstance);
+ }
+
+ //
+ // Reset the default configuration identifier and alternate function
+ // selections.
+ //
+ pDevInstance->ulConfiguration = pDevInstance->ulDefaultConfiguration;
+
+ for(ulLoop = 0; ulLoop < USB_MAX_INTERFACES_PER_DEVICE; ulLoop++)
+ {
+ pDevInstance->pucAltSetting[ulLoop] = (unsigned char)0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_STATUS standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param pUSBRequest holds the request type and endpoint number if endpoint
+// status is requested.
+//
+// This function handles responses to a Get Status request from the host
+// controller. A status request can be for the device, an interface or an
+// endpoint. If any other type of request is made this function will cause
+// a stall condition to indicate that the command is not supported. The
+// \e pUSBRequest structure holds the type of the request in the
+// bmRequestType field. If the type indicates that this is a request for an
+// endpoint's status, then the wIndex field holds the endpoint number.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetStatus(void *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned short usData;
+ tDeviceInstance *psUSBControl;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)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(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This was a Device Status request.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Return the current status for the device.
+ //
+ usData = (unsigned short)psUSBControl->ucStatus;
+
+ break;
+ }
+
+ //
+ // This was a Interface status request.
+ //
+ case USB_RTYPE_INTERFACE:
+ {
+ //
+ // Interface status always returns 0.
+ //
+ usData = (unsigned short)0;
+
+ break;
+ }
+
+ //
+ // This was an endpoint status request.
+ //
+ case USB_RTYPE_ENDPOINT:
+ {
+ unsigned short usIndex;
+ unsigned long ulDir;
+
+ //
+ // Which endpoint are we dealing with?
+ //
+ usIndex = pUSBRequest->wIndex & USB_REQ_EP_NUM_M;
+
+ //
+ // Check if this was a valid endpoint request.
+ //
+ if((usIndex == 0) || (usIndex >= NUM_USB_EP))
+ {
+ USBDCDStallEP0(0);
+ return;
+ }
+ else
+ {
+ //
+ // Are we dealing with an IN or OUT endpoint?
+ //
+ ulDir = ((pUSBRequest->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.
+ //
+ usData =
+ (unsigned short)psUSBControl->ucHalt[ulDir][usIndex - 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->ulEP0DataRemain = 2;
+ psUSBControl->pEP0Data = (unsigned char *)&usData;
+
+ //
+ // Send the response.
+ //
+ USBDEP0StateTx(0);
+}
+
+//*****************************************************************************
+//
+// This function handles the CLEAR_FEATURE standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param pUSBRequest holds the options for the Clear Feature USB request.
+//
+// This function handles device or endpoint clear feature requests. The
+// \e pUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. 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 *pUSBRequest)
+{
+ tDeviceInstance *psUSBControl;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)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(pUSBRequest->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 & pUSBRequest->wValue)
+ {
+ //
+ // Clear the remote wake up state.
+ //
+ psUSBControl->ucStatus &= ~USB_STATUS_REMOTE_WAKE;
+ }
+ else
+ {
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // This is a clear feature request at the endpoint level.
+ //
+ case USB_RTYPE_ENDPOINT:
+ {
+ unsigned long ulDir;
+ unsigned short usIndex;
+
+ //
+ // Which endpoint are we dealing with?
+ //
+ usIndex = pUSBRequest->wIndex & USB_REQ_EP_NUM_M;
+
+ //
+ // Not a valid endpoint.
+ //
+ if((usIndex == 0) || (usIndex > NUM_USB_EP))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Only the halt feature is supported.
+ //
+ if(USB_FEATURE_EP_HALT == pUSBRequest->wValue)
+ {
+ //
+ // Are we dealing with an IN or OUT endpoint?
+ //
+ ulDir = ((pUSBRequest->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->ucHalt[ulDir][usIndex - 1] = 0;
+
+ if(ulDir == HALT_EP_IN)
+ {
+ MAP_USBDevEndpointStallClear(USB0_BASE,
+ INDEX_TO_USB_EP(usIndex),
+ USB_EP_DEV_IN);
+ }
+ else
+ {
+ MAP_USBDevEndpointStallClear(USB0_BASE,
+ INDEX_TO_USB_EP(usIndex),
+ 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 pUSBRequest holds the feature in the wValue field of the USB
+// request.
+//
+// This function handles device or endpoint set feature requests. The
+// \e pUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. 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 *pUSBRequest)
+{
+ tDeviceInstance *psUSBControl;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)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(pUSBRequest->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 & pUSBRequest->wValue)
+ {
+ //
+ // Set the remote wake up state.
+ //
+ psUSBControl->ucStatus |= USB_STATUS_REMOTE_WAKE;
+ }
+ else
+ {
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // This is a set feature request at the endpoint level.
+ //
+ case USB_RTYPE_ENDPOINT:
+ {
+ unsigned short usIndex;
+ unsigned long ulDir;
+
+ //
+ // Which endpoint are we dealing with?
+ //
+ usIndex = pUSBRequest->wIndex & USB_REQ_EP_NUM_M;
+
+ //
+ // Not a valid endpoint?
+ //
+ if((usIndex == 0) || (usIndex >= NUM_USB_EP))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Only the Halt feature can be set.
+ //
+ if(USB_FEATURE_EP_HALT == pUSBRequest->wValue)
+ {
+ //
+ // Are we dealing with an IN or OUT endpoint?
+ //
+ ulDir = ((pUSBRequest->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->ucHalt[ulDir][usIndex - 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 pUSBRequest holds the new address to use in the wValue field of the
+// USB request.
+//
+// This function is called to handle the change of address request from the
+// host controller. This can only start the sequence as the host must
+// acknowledge that the device has changed address. Thus this function sets
+// the address change as pending until the status phase of the request has
+// been completed successfully. This prevents the devices address from
+// changing and not properly responding to the status phase.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetAddress(void *pvInstance, tUSBRequest *pUSBRequest)
+{
+ tDeviceInstance *psUSBControl;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)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->ulDevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING;
+
+ //
+ // Transition directly to the status state since there is no data phase
+ // for this request.
+ //
+ psUSBControl->eEP0State = USB_STATE_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_DESCRIPTOR standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param pUSBRequest 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->pDeviceDescriptor 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->sCallbacks.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 *pUSBRequest)
+{
+ tBoolean bConfig;
+ tDeviceInstance *psUSBControl;
+ tDeviceInfo *psDevice;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)pvInstance;
+ psDevice = psUSBControl->psInfo;
+
+ //
+ // 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(pUSBRequest->wValue >> 8)
+ {
+ //
+ // This request was for a device descriptor.
+ //
+ case USB_DTYPE_DEVICE:
+ {
+ //
+ // Return the externally provided device descriptor.
+ //
+ psUSBControl->pEP0Data =
+ (unsigned char *)psDevice->pDeviceDescriptor;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ psUSBControl->ulEP0DataRemain = psDevice->pDeviceDescriptor[0];
+
+ break;
+ }
+
+ //
+ // This request was for a configuration descriptor.
+ //
+ case USB_DTYPE_CONFIGURATION:
+ {
+ const tConfigHeader *psConfig;
+ const tDeviceDescriptor *psDeviceDesc;
+ unsigned char ucIndex;
+
+ //
+ // Which configuration are we being asked for?
+ //
+ ucIndex = (unsigned char)(pUSBRequest->wValue & 0xFF);
+
+ //
+ // Is this valid?
+ //
+ psDeviceDesc =
+ (const tDeviceDescriptor *)psDevice->pDeviceDescriptor;
+
+ if(ucIndex >= psDeviceDesc->bNumConfigurations)
+ {
+ //
+ // This is an invalid configuration index. Stall EP0 to
+ // indicate a request error.
+ //
+ USBDCDStallEP0(0);
+ psUSBControl->pEP0Data = 0;
+ psUSBControl->ulEP0DataRemain = 0;
+ }
+ else
+ {
+ //
+ // Return the externally specified configuration descriptor.
+ //
+ psConfig = psDevice->ppConfigDescriptors[ucIndex];
+
+ //
+ // Start by sending data from the beginning of the first
+ // descriptor.
+ //
+ psUSBControl->ucConfigSection = 0;
+ psUSBControl->ucSectionOffset = 0;
+ psUSBControl->pEP0Data = (unsigned char *)
+ psConfig->psSections[0]->pucData;
+
+ //
+ // Determine the total size of the configuration descriptor
+ // by counting the sizes of the sections comprising it.
+ //
+ psUSBControl->ulEP0DataRemain =
+ USBDCDConfigDescGetSize(psConfig);
+
+ //
+ // Remember that we need to send the configuration descriptor
+ // and which descriptor we need to send.
+ //
+ psUSBControl->ucConfigIndex = ucIndex;
+
+ bConfig = true;
+ }
+ break;
+ }
+
+ //
+ // This request was for a string descriptor.
+ //
+ case USB_DTYPE_STRING:
+ {
+ long lIndex;
+
+ //
+ // Determine the correct descriptor index based on the requested
+ // language ID and index.
+ //
+ lIndex = USBDStringIndexFromRequest(pUSBRequest->wIndex,
+ pUSBRequest->wValue & 0xFF);
+
+ //
+ // If the mapping function returned -1 then stall the request to
+ // indicate that the request was not valid.
+ //
+ if(lIndex == -1)
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ //
+ // Return the externally specified configuration descriptor.
+ //
+ psUSBControl->pEP0Data =
+ (unsigned char *)psDevice->ppStringDescriptors[lIndex];
+
+ //
+ // The total size of a string descriptor is in byte 0.
+ //
+ psUSBControl->ulEP0DataRemain =
+ psDevice->ppStringDescriptors[lIndex][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->sCallbacks.pfnGetDescriptor)
+ {
+ psDevice->sCallbacks.pfnGetDescriptor(psUSBControl->pvInstance,
+ pUSBRequest);
+ }
+ 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->pEP0Data)
+ {
+ //
+ // If there is more data to send than is requested then just
+ // send the requested amount of data.
+ //
+ if(psUSBControl->ulEP0DataRemain > pUSBRequest->wLength)
+ {
+ psUSBControl->ulEP0DataRemain = pUSBRequest->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 usLang is the requested string language ID.
+// \param usIndex 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 long
+USBDStringIndexFromRequest(unsigned short usLang, unsigned short usIndex)
+{
+ tString0Descriptor *pLang;
+ unsigned long ulNumLangs;
+ unsigned long ulNumStringsPerLang;
+ unsigned long ulLoop;
+
+ //
+ // Make sure we have a string table at all.
+ //
+ if((g_psUSBDevice[0].psInfo == 0) ||
+ (g_psUSBDevice[0].psInfo->ppStringDescriptors == 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(usIndex == 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).
+ //
+ ulNumLangs = (g_psUSBDevice[0].psInfo->ppStringDescriptors[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.
+ //
+ ulNumStringsPerLang = ((g_psUSBDevice[0].psInfo->ulNumStringDescriptors - 1) /
+ ulNumLangs);
+
+ //
+ // 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 + (ulNumStringsPerLang * ulNumLangs)) !=
+ g_psUSBDevice[0].psInfo->ulNumStringDescriptors)
+ {
+ 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_psUSBDevice[0].psInfo->ppStringDescriptors[0]);
+
+ //
+ // Look through the supported languages looking for the one we were asked
+ // for.
+ //
+ for(ulLoop = 0; ulLoop < ulNumLangs; ulLoop++)
+ {
+ //
+ // Have we found the requested language?
+ //
+ if(pLang->wLANGID[ulLoop] == usLang)
+ {
+ //
+ // Yes - calculate the index of the descriptor to send.
+ //
+ return((ulNumStringsPerLang * ulLoop) + usIndex);
+ }
+ }
+
+ //
+ // 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 pUSBRequest holds the data for this request.
+//
+// This function currently is not supported and will respond with a Stall
+// to indicate that this command is not supported by the device.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest)
+{
+ //
+ // 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 pUSBRequest holds the data for this request.
+//
+// This function responds to a host request to return the current
+// configuration of the USB device. The function will send the configuration
+// response to the host and return. This value will either be 0 or the last
+// value received from a call to SetConfiguration().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetConfiguration(void *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned char ucValue;
+ tDeviceInstance *psUSBControl;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)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->ulDevAddress & DEV_ADDR_PENDING)
+ {
+ ucValue = 0;
+ }
+ else
+ {
+ ucValue = (unsigned char)psUSBControl->ulConfiguration;
+ }
+
+ psUSBControl->ulEP0DataRemain = 1;
+ psUSBControl->pEP0Data = &ucValue;
+
+ //
+ // 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 pUSBRequest holds the data for this request.
+//
+// This function responds to a host request to change the current
+// configuration of the USB device. The actual configuration number is taken
+// from the structure passed in via \e pUSBRequest. 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->sCallbacks,
+// it will be called so that the application can respond to a change in
+// configuration.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetConfiguration(void *pvInstance, tUSBRequest *pUSBRequest)
+{
+ tDeviceInstance *psUSBControl;
+ tDeviceInfo *psDevice;
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)pvInstance;
+ psDevice = psUSBControl->psInfo;
+
+ //
+ // 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(pUSBRequest->wValue > psUSBControl->psInfo->pDeviceDescriptor[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->ulConfiguration = pUSBRequest->wValue;
+
+ //
+ // If passed a configuration other than 0 (which tells us that we are
+ // not currently configured), configure the endpoints (other than EP0)
+ // appropriately.
+ //
+ if(psUSBControl->ulConfiguration)
+ {
+ const tConfigHeader *psHdr;
+ const tConfigDescriptor *psDesc;
+
+ //
+ // Get a pointer to the configuration descriptor. This will always
+ // be the first section in the current configuration.
+ //
+ psHdr = psDevice->ppConfigDescriptors[pUSBRequest->wValue - 1];
+ psDesc = (const tConfigDescriptor *)(psHdr->psSections[0]->pucData);
+
+ //
+ // 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->ucStatus |= USB_STATUS_SELF_PWR;
+ }
+ else
+ {
+ psUSBControl->ucStatus &= ~USB_STATUS_SELF_PWR;
+ }
+ }
+
+ //
+ // Configure endpoints for the new configuration.
+ //
+ USBDeviceConfig(psUSBControl,
+ psDevice->ppConfigDescriptors[pUSBRequest->wValue - 1]);
+ }
+
+ //
+ // If there is a configuration change callback then call it.
+ //
+ if(psDevice->sCallbacks.pfnConfigChange)
+ {
+ psDevice->sCallbacks.pfnConfigChange(
+ psUSBControl->pvInstance, psUSBControl->ulConfiguration);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_INTERFACE standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param pUSBRequest holds the data for this request.
+//
+// This function is called when the host controller request the current
+// interface that is in use by the device. This simply returns the value set
+// by the last call to SetInterface().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetInterface(void *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned char ucValue;
+ tDeviceInstance *psUSBControl;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)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->ulDevAddress & DEV_ADDR_PENDING)
+ {
+ ucValue = (unsigned char)0;
+ }
+ else
+ {
+ //
+ // Is the interface number valid?
+ //
+ if(pUSBRequest->wIndex < USB_MAX_INTERFACES_PER_DEVICE)
+ {
+ //
+ // Read the current alternate setting for the required interface.
+ //
+ ucValue = psUSBControl->pucAltSetting[pUSBRequest->wIndex];
+ }
+ else
+ {
+ //
+ // An invalid interface number was specified.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+
+ //
+ // Send the single byte response.
+ //
+ psUSBControl->ulEP0DataRemain = 1;
+ psUSBControl->pEP0Data = &ucValue;
+
+ //
+ // 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 pUSBRequest 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->sCallbacks 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 *pUSBRequest)
+{
+ const tConfigHeader *psConfig;
+ tInterfaceDescriptor *psInterface;
+ unsigned long ulLoop;
+ unsigned long ulSection;
+ unsigned long ulNumInterfaces;
+ unsigned char ucInterface;
+ tBoolean bRetcode;
+ tDeviceInstance *psUSBControl;
+ tDeviceInfo *psDevice;
+
+ ASSERT(pUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDeviceInstance *)pvInstance;
+ psDevice = psUSBControl->psInfo;
+
+ //
+ // 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->ppConfigDescriptors[psUSBControl->ulConfiguration - 1];
+
+ //
+ // How many interfaces are included in the descriptor?
+ //
+ ulNumInterfaces = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_INTERFACE);
+
+ //
+ // Find the interface descriptor for the supplied interface and alternate
+ // setting numbers.
+ //
+ for(ulLoop = 0; ulLoop < ulNumInterfaces; ulLoop++)
+ {
+ //
+ // Get the next interface descriptor in the configuration descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ulLoop, USB_DESC_ANY,
+ &ulSection);
+
+ //
+ // Is this the required interface with the correct alternate setting?
+ //
+ if(psInterface &&
+ (psInterface->bInterfaceNumber == pUSBRequest->wIndex) &&
+ (psInterface->bAlternateSetting == pUSBRequest->wValue))
+ {
+ ucInterface = psInterface->bInterfaceNumber;
+
+ //
+ // Make sure we don't write outside the bounds of the pucAltSetting
+ // array (in a debug build, anyway, since this indicates an error
+ // in the device descriptor).
+ //
+ ASSERT(ucInterface < USB_MAX_INTERFACES_PER_DEVICE);
+
+ //
+ // This is the correct interface descriptor so save the
+ // setting.
+ //
+ psUSBControl->pucAltSetting[ucInterface] =
+ psInterface->bAlternateSetting;
+
+ //
+ // Reconfigure the endpoints to match the requirements of the
+ // new alternate setting for the interface.
+ //
+ bRetcode = USBDeviceConfigAlternate(psUSBControl, psConfig, ucInterface,
+ psInterface->bAlternateSetting);
+
+ //
+ // If there is a callback then notify the application of the
+ // change to the alternate interface.
+ //
+ if(bRetcode && psDevice->sCallbacks.pfnInterfaceChange)
+ {
+ psDevice->sCallbacks.pfnInterfaceChange(
+ psUSBControl->pvInstance,
+ pUSBRequest->wIndex,
+ pUSBRequest->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 pUSBRequest 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 *pUSBRequest)
+{
+ //
+ // 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 ulIndex is the index of the USB controller which is to be
+// initialized.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDEP0StateTx(unsigned long ulIndex)
+{
+ unsigned long ulNumBytes;
+ unsigned char *pData;
+
+ ASSERT(ulIndex == 0);
+
+ //
+ // In the TX state on endpoint zero.
+ //
+ g_psUSBDevice[0].eEP0State = USB_STATE_TX;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ulNumBytes = g_psUSBDevice[0].ulEP0DataRemain;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ulNumBytes > EP0_MAX_PACKET_SIZE)
+ {
+ ulNumBytes = EP0_MAX_PACKET_SIZE;
+ }
+
+ //
+ // Save the pointer so that it can be passed to the USBEndpointDataPut()
+ // function.
+ //
+ pData = (unsigned char *)g_psUSBDevice[0].pEP0Data;
+
+ //
+ // Advance the data pointer and counter to the next data to be sent.
+ //
+ g_psUSBDevice[0].ulEP0DataRemain -= ulNumBytes;
+ g_psUSBDevice[0].pEP0Data += ulNumBytes;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pData, ulNumBytes);
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ulNumBytes == 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_psUSBDevice[0].eEP0State = USB_STATE_STATUS;
+
+ //
+ // 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_psUSBDevice[0].psInfo->sCallbacks.pfnDataSent) &&
+ (g_psUSBDevice[0].ulOUTDataSize != 0))
+ {
+ //
+ // Call the custom handler.
+ //
+ g_psUSBDevice[0].psInfo->sCallbacks.pfnDataSent(
+ g_psUSBDevice[0].pvInstance, g_psUSBDevice[0].ulOUTDataSize);
+
+ //
+ // There is no longer any data pending to be sent.
+ //
+ g_psUSBDevice[0].ulOUTDataSize = 0;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending the configuration descriptor on
+// endpoint zero.
+//
+// \param ulIndex is the index of the USB controller which is to be used.
+//
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDEP0StateTxConfig(unsigned long ulIndex)
+{
+ unsigned long ulNumBytes;
+ unsigned long ulSecBytes;
+ unsigned long ulToSend;
+ unsigned char *pData;
+ tConfigDescriptor sConfDesc;
+ const tConfigHeader *psConfig;
+ const tConfigSection *psSection;
+
+ ASSERT(ulIndex == 0);
+
+ //
+ // In the TX state on endpoint zero.
+ //
+ g_psUSBDevice[0].eEP0State = USB_STATE_TX_CONFIG;
+
+ //
+ // Find the current configuration descriptor definition.
+ //
+ psConfig = g_psUSBDevice[0].psInfo->ppConfigDescriptors[
+ g_psUSBDevice[0].ucConfigIndex];
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ulNumBytes = g_psUSBDevice[0].ulEP0DataRemain;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ulNumBytes > EP0_MAX_PACKET_SIZE)
+ {
+ ulNumBytes = 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.ulEP0DataRemain.
+ //
+ if((g_psUSBDevice[0].ucSectionOffset == 0) &&
+ (g_psUSBDevice[0].ucConfigSection == 0))
+ {
+ //
+ // Copy the USB configuration descriptor from the beginning of the
+ // first section of the current configuration.
+ //
+ sConfDesc = *(tConfigDescriptor *)g_psUSBDevice[0].pEP0Data;
+
+ //
+ // Update the total size.
+ //
+ sConfDesc.wTotalLength = (unsigned short)USBDCDConfigDescGetSize(
+ psConfig);
+
+ //
+ // Write the descriptor to the USB FIFO.
+ //
+ ulToSend = (ulNumBytes < sizeof(tConfigDescriptor)) ? ulNumBytes :
+ sizeof(tConfigDescriptor);
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, (unsigned char *)&sConfDesc,
+ ulToSend);
+
+ //
+ // Did we reach the end of the first section?
+ //
+ if(psConfig->psSections[0]->usSize == ulToSend)
+ {
+ //
+ // Update our tracking indices to point to the start of the next
+ // section.
+ //
+ g_psUSBDevice[0].ucSectionOffset = 0;
+ g_psUSBDevice[0].ucConfigSection = 1;
+ }
+ else
+ {
+ //
+ // Note that we have sent the first few bytes of the descriptor.
+ //
+ g_psUSBDevice[0].ucSectionOffset = (unsigned char)ulToSend;
+ }
+
+ //
+ // How many bytes do we have remaining to send on this iteration?
+ //
+ ulToSend = ulNumBytes - ulToSend;
+ }
+ else
+ {
+ //
+ // Set the number of bytes we still have to send on this call.
+ //
+ ulToSend = ulNumBytes;
+ }
+
+ //
+ // Add the relevant number of bytes to the USB FIFO
+ //
+ while(ulToSend)
+ {
+ //
+ // Get a pointer to the current configuration section.
+ //
+ psSection = psConfig->psSections[g_psUSBDevice[0].ucConfigSection];
+
+ //
+ // Calculate bytes are available in the current configuration section.
+ //
+ ulSecBytes = (unsigned long)(psSection->usSize -
+ g_psUSBDevice[0].ucSectionOffset);
+
+ //
+ // Save the pointer so that it can be passed to the
+ // USBEndpointDataPut() function.
+ //
+ pData = (unsigned char *)psSection->pucData +
+ g_psUSBDevice[0].ucSectionOffset;
+
+ //
+ // Are there more bytes in this section that we still have to send?
+ //
+ if(ulSecBytes > ulToSend)
+ {
+ //
+ // Yes - send only the remaining bytes in the transfer.
+ //
+ ulSecBytes = ulToSend;
+ }
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pData, ulSecBytes);
+
+ //
+ // Fix up our pointers for the next iteration.
+ //
+ ulToSend -= ulSecBytes;
+ g_psUSBDevice[0].ucSectionOffset += (unsigned char)ulSecBytes;
+
+ //
+ // Have we reached the end of a section?
+ //
+ if(g_psUSBDevice[0].ucSectionOffset == psSection->usSize)
+ {
+ //
+ // Yes - move to the next one.
+ //
+ g_psUSBDevice[0].ucConfigSection++;
+ g_psUSBDevice[0].ucSectionOffset = 0;
+ }
+ }
+
+ //
+ // Fix up the number of bytes remaining to be sent and the start pointer.
+ //
+ g_psUSBDevice[0].ulEP0DataRemain -= ulNumBytes;
+
+ //
+ // If we ran out of bytes in the configuration section, bail and just
+ // send out what we have.
+ //
+ if(psConfig->ucNumSections <= g_psUSBDevice[0].ucConfigSection)
+ {
+ g_psUSBDevice[0].ulEP0DataRemain = 0;
+ }
+
+ //
+ // If there is no more data don't keep looking or ucConfigSection might
+ // overrun the available space.
+ //
+ if(g_psUSBDevice[0].ulEP0DataRemain != 0)
+ {
+ pData =(unsigned char *)
+ psConfig->psSections[g_psUSBDevice[0].ucConfigSection]->pucData;
+ ulToSend = g_psUSBDevice[0].ucSectionOffset;
+ g_psUSBDevice[0].pEP0Data = (pData + ulToSend);
+ }
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ulNumBytes == 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_psUSBDevice[0].psInfo->sCallbacks.pfnDataSent) &&
+ (g_psUSBDevice[0].ulOUTDataSize != 0))
+ {
+ //
+ // Call the custom handler.
+ //
+ g_psUSBDevice[0].psInfo->sCallbacks.pfnDataSent(
+ g_psUSBDevice[0].pvInstance, g_psUSBDevice[0].ulOUTDataSize);
+
+ //
+ // There is no longer any data pending to be sent.
+ //
+ g_psUSBDevice[0].ulOUTDataSize = 0;
+ }
+
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_psUSBDevice[0].eEP0State = USB_STATE_STATUS;
+ }
+}
+
+//*****************************************************************************
+//
+// The internal USB device interrupt handler.
+//
+// \param ulIndex is the USB controller associated with this interrupt.
+// \param ulStatus 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(unsigned long ulIndex, unsigned long ulStatus)
+{
+ static unsigned long ulSOFDivide = 0;
+ tDeviceInfo *psInfo;
+ void *pvInstance;
+
+ //
+ // If device initialization has not been performed then just disconnect
+ // from the USB bus and return from the handler.
+ //
+ if(g_psUSBDevice[0].psInfo == 0)
+ {
+ MAP_USBDevDisconnect(USB0_BASE);
+ return;
+ }
+
+ psInfo = g_psUSBDevice[0].psInfo;
+ pvInstance = g_psUSBDevice[0].pvInstance;
+
+ //
+ // Received a reset from the host.
+ //
+ if(ulStatus & USB_INTCTRL_RESET)
+ {
+ USBDeviceEnumResetHandler(&g_psUSBDevice[0]);
+ }
+
+ //
+ // Suspend was signaled on the bus.
+ //
+ if(ulStatus & USB_INTCTRL_SUSPEND)
+ {
+ //
+ // Call the SuspendHandler() if it was specified.
+ //
+ if(psInfo->sCallbacks.pfnSuspendHandler)
+ {
+ psInfo->sCallbacks.pfnSuspendHandler(pvInstance);
+ }
+ }
+
+ //
+ // Resume was signaled on the bus.
+ //
+ if(ulStatus & USB_INTCTRL_RESUME)
+ {
+ //
+ // Call the ResumeHandler() if it was specified.
+ //
+ if(psInfo->sCallbacks.pfnResumeHandler)
+ {
+ psInfo->sCallbacks.pfnResumeHandler(pvInstance);
+ }
+ }
+
+ //
+ // USB device was disconnected.
+ //
+ if(ulStatus & USB_INTCTRL_DISCONNECT)
+ {
+ //
+ // Call the DisconnectHandler() if it was specified.
+ //
+ if(psInfo->sCallbacks.pfnDisconnectHandler)
+ {
+ psInfo->sCallbacks.pfnDisconnectHandler(pvInstance);
+ }
+ }
+
+ //
+ // Start of Frame was received.
+ //
+ if(ulStatus & USB_INTCTRL_SOF)
+ {
+ //
+ // Increment the global Start of Frame counter.
+ //
+ g_ulUSBSOFCount++;
+
+ //
+ // Increment our SOF divider.
+ //
+ ulSOFDivide++;
+
+ //
+ // Handle resume signaling if required.
+ //
+ USBDeviceResumeTickHandler(&g_psUSBDevice[0]);
+
+ //
+ // Have we counted enough SOFs to allow us to call the tick function?
+ //
+ if(ulSOFDivide == USB_SOF_TICK_DIVIDE)
+ {
+ //
+ // Yes - reset the divider and call the SOF tick handler.
+ //
+ ulSOFDivide = 0;
+ InternalUSBStartOfFrameTick(USB_SOF_TICK_DIVIDE);
+ }
+ }
+
+ //
+ // Get the controller interrupt status.
+ //
+ ulStatus = MAP_USBIntStatusEndpoint(USB0_BASE);
+
+ //
+ // Handle end point 0 interrupts.
+ //
+ if(ulStatus & USB_INTEP_0)
+ {
+ USBDeviceEnumHandler(&g_psUSBDevice[0]);
+ }
+
+ //
+ // 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(psInfo->sCallbacks.pfnEndpointHandler)
+ {
+ psInfo->sCallbacks.pfnEndpointHandler(pvInstance, ulStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdevice.h b/usblib/device/usbdevice.h
new file mode 100644
index 0000000..edffb1d
--- /dev/null
+++ b/usblib/device/usbdevice.h
@@ -0,0 +1,223 @@
+//*****************************************************************************
+//
+// usbdevice.h - types and definitions used during USB enumeration.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris 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 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"
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ tCustomHandlers sCallbacks;
+
+ //
+ //! A pointer to the device descriptor for this device.
+ //
+ const unsigned char *pDeviceDescriptor;
+
+ //
+ //! 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, pDeviceDescriptor.
+ //
+ const tConfigHeader * const *ppConfigDescriptors;
+
+ //
+ //! 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The total number of descriptors provided in the ppStringDescriptors
+ //! array.
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! A structure defining how the USB controller FIFO is to be partitioned
+ //! between the various endpoints. This member can be set to point to
+ //! g_sUSBDefaultFIFOConfig if the default FIFO configuration is acceptable
+ //! This configuration sets each endpoint FIFO to be single buffered and
+ //! sized to hold the maximum packet size for the endpoint.
+ //
+ const tFIFOConfig *psFIFOConfig;
+
+ //
+ //! This value will be passed back to all call back functions so that
+ //! they have access to individual instance data based on the this pointer.
+ //
+ void *pvInstance;
+
+ //
+ //! The generic device instance data for this device. This will be set
+ //! by the call to DCDInit() which is usually made when the applicaiton
+ //! calls the class specific initialization function.
+ //
+ tDeviceInstance *psDevice;
+};
+
+//*****************************************************************************
+//
+// The default USB endpoint FIFO configuration structure. This structure
+// contains definitions to set all USB FIFOs into single buffered mode with
+// no DMA use. Each endpoint's FIFO is sized to hold the largest maximum
+// packet size for any interface alternate setting in the current config
+// descriptor. A pointer to this structure may be passed in the psFIFOConfig
+// field of the tDeviceInfo structure passed to USBCDCInit if the application
+// does not require any special handling of the USB controller FIFO.
+//
+//*****************************************************************************
+extern const tFIFOConfig g_sUSBDefaultFIFOConfig;
+
+//*****************************************************************************
+//
+// Public APIs offered by the USB library device control driver.
+//
+//*****************************************************************************
+extern void USBDCDInit(unsigned long ulIndex, tDeviceInfo *psDevice);
+extern void USBDCDTerm(unsigned long ulIndex);
+extern void USBDCDStallEP0(unsigned long ulIndex);
+extern void USBDCDRequestDataEP0(unsigned long ulIndex, unsigned char *pucData,
+ unsigned long ulSize);
+extern void USBDCDSendDataEP0(unsigned long ulIndex, unsigned char *pucData,
+ unsigned long ulSize);
+extern void USBDCDSetDefaultConfiguration(unsigned long ulIndex,
+ unsigned long ulDefaultConfig);
+extern unsigned long USBDCDConfigDescGetSize(const tConfigHeader *psConfig);
+extern unsigned long USBDCDConfigDescGetNum(const tConfigHeader *psConfig,
+ unsigned long ulType);
+extern tDescriptorHeader *USBDCDConfigDescGet(const tConfigHeader *psConfig,
+ unsigned long ulType,
+ unsigned long ulIndex,
+ unsigned long *pulSection);
+extern unsigned long
+ USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
+ unsigned char ucInterfaceNumber);
+extern tInterfaceDescriptor *
+ USBDCDConfigGetInterface(const tConfigHeader *psConfig,
+ unsigned long ulIndex, unsigned long ulAltCfg,
+ unsigned long *pulSection);
+extern tEndpointDescriptor *
+ USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig,
+ unsigned long ulInterfaceNumber,
+ unsigned long ulAltCfg,
+ unsigned long ulIndex);
+extern void USBDCDPowerStatusSet(unsigned long ulIndex, unsigned char ucPower);
+extern tBoolean USBDCDRemoteWakeupRequest(unsigned long ulIndex);
+
+//*****************************************************************************
+//
+// Early releases of the USB library had the following function named
+// incorrectly. This macro ensures that any code which used the previous name
+// will still operate as expected.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+#define USBCDCConfigGetInterfaceEndpoint(a, b, c, d) \
+ USBDCDConfigGetInterfaceEndpoint((a), (b), (c), (d))
+#endif
+
+//*****************************************************************************
+//
+// Device mode interrupt handler for controller index 0.
+//
+//*****************************************************************************
+extern void USB0DeviceIntHandler(void);
+
+//*****************************************************************************
+//
+// 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..341fb1b
--- /dev/null
+++ b/usblib/device/usbdevicepriv.h
@@ -0,0 +1,223 @@
+//*****************************************************************************
+//
+// 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-2012 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 9453 of the Stellaris 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.
+ //
+ USB_STATE_IDLE,
+
+ //
+ // The USB device is sending data back to the host due to an IN request.
+ //
+ USB_STATE_TX,
+
+ //
+ // The USB device is sending the configuration descriptor back to the host
+ // due to an IN request.
+ //
+ USB_STATE_TX_CONFIG,
+
+ //
+ // The USB device is receiving data from the host due to an OUT
+ // request from the host.
+ //
+ USB_STATE_RX,
+
+ //
+ // The USB device has completed the IN or OUT request and is now waiting
+ // for the host to acknowledge the end of the IN/OUT transaction. This
+ // is the status phase for a USB control transaction.
+ //
+ USB_STATE_STATUS,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ USB_STATE_STALL
+}
+tEP0State;
+
+typedef struct tDeviceInfo tDeviceInfo;
+typedef struct tDeviceInstance tDeviceInstance;
+
+//*****************************************************************************
+//
+// The USB controller device information.
+//
+//*****************************************************************************
+struct tDeviceInstance
+{
+ //
+ // The device information for the USB device.
+ //
+ tDeviceInfo *psInfo;
+
+ //
+ // The instance data for the USB device.
+ //
+ void *pvInstance;
+
+ //
+ // The current state of endpoint zero.
+ //
+ volatile tEP0State eEP0State;
+
+ //
+ // The devices current address, this also has a change pending bit in the
+ // MSB of this value specified by DEV_ADDR_PENDING.
+ //
+ volatile unsigned long ulDevAddress;
+
+ //
+ // This holds the current active configuration for this device.
+ //
+ unsigned long ulConfiguration;
+
+ //
+ // This holds the configuration id that will take effect after a reset.
+ //
+ unsigned long ulDefaultConfiguration;
+
+ //
+ // This holds the current alternate interface for this device.
+ //
+ unsigned char pucAltSetting[USB_MAX_INTERFACES_PER_DEVICE];
+
+ //
+ // This is the pointer to the current data being sent out or received
+ // on endpoint zero.
+ //
+ unsigned char *pEP0Data;
+
+ //
+ // This is the number of bytes that remain to be sent from or received
+ // into the g_sUSBDeviceState.pEP0Data data buffer.
+ //
+ volatile unsigned long ulEP0DataRemain;
+
+ //
+ // The amount of data being sent/received due to a custom request.
+ //
+ unsigned long ulOUTDataSize;
+
+ //
+ // Holds the current device status.
+ //
+ unsigned char ucStatus;
+
+ //
+ // Holds the endpoint status for the HALT condition. This array is sized
+ // to hold halt status for all IN and OUT endpoints.
+ //
+ unsigned char ucHalt[2][USBLIB_NUM_EP - 1];
+
+ //
+ // Holds the configuration descriptor section number currently being sent
+ // to the host.
+ //
+ unsigned char ucConfigSection;
+
+ //
+ // Holds the offset within the configuration descriptor section currently
+ // being sent to the host.
+ //
+ unsigned char ucSectionOffset;
+
+ //
+ // Holds the index of the configuration that we are currently sending back
+ // to the host.
+ //
+ unsigned char ucConfigIndex;
+
+ //
+ // 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.
+ //
+ tBoolean bPwrSrcSet;
+
+ //
+ // This flag indicates whether or not remote wake up signaling is in
+ // progress.
+ //
+ tBoolean bRemoteWakeup;
+
+ //
+ // During remote wake up signaling, this counter is used to track the
+ // number of milliseconds since the signaling was initiated.
+ //
+ unsigned char ucRemoteWakeupCount;
+};
+
+extern tDeviceInstance g_psUSBDevice[];
+
+//*****************************************************************************
+//
+// Device enumeration functions provided by device/usbenum.c and called from
+// the interrupt handler in device/usbhandler.c
+//
+//*****************************************************************************
+extern tBoolean USBDeviceConfig(tDeviceInstance *psDevInst,
+ const tConfigHeader *psConfig);
+extern tBoolean USBDeviceConfigAlternate(tDeviceInstance *psDevInst,
+ const tConfigHeader *psConfig,
+ unsigned char ucInterfaceNum,
+ unsigned char ucAlternateSetting);
+
+//*****************************************************************************
+//
+// 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..5ba33e5
--- /dev/null
+++ b/usblib/device/usbdhandler.c
@@ -0,0 +1,82 @@
+//*****************************************************************************
+//
+// usbhandler.c - General USB handling routines.
+//
+// Copyright (c) 2007-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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/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)
+{
+ unsigned long ulStatus;
+
+ //
+ // Get the controller interrupt status.
+ //
+ ulStatus = MAP_USBIntStatusControl(USB0_BASE);
+
+ //
+ // Call the internal handler.
+ //
+ USBDeviceIntHandlerInternal(0, ulStatus);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhid.c b/usblib/device/usbdhid.c
new file mode 100644
index 0000000..ccfca59
--- /dev/null
+++ b/usblib/device/usbdhid.c
@@ -0,0 +1,2579 @@
+//*****************************************************************************
+//
+// usbdhid.c - USB HID device class driver.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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/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 usDeferredOpFlags 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->usDeferredOpFlags to indicate that the operation is pending.
+//
+//*****************************************************************************
+#define HID_DO_PACKET_RX 5
+#define HID_DO_SEND_IDLE_REPORT 6
+
+//*****************************************************************************
+//
+// Macros to convert between USB controller base address and an index. These
+// are currently trivial but are included to allow for the possibility of
+// supporting more than one controller in the future.
+//
+//*****************************************************************************
+#define USB_BASE_TO_INDEX(BaseAddr) (0)
+#define USB_INDEX_TO_BASE(Index) (USB0_BASE)
+
+//*****************************************************************************
+//
+// 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
+
+//*****************************************************************************
+//
+// Maximum packet size for the interrupt endpoints used for report transmission
+// and reception and the associated FIFO sizes to set aside for each endpoint.
+//
+//*****************************************************************************
+#define INT_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define INT_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
+
+#define INT_IN_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(INT_IN_EP_FIFO_SIZE)
+#define INT_OUT_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(INT_IN_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.
+//
+//*****************************************************************************
+unsigned char g_pHIDDeviceDescriptor[] =
+{
+ 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
+ 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.
+};
+
+//*****************************************************************************
+//
+// 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.
+//
+//*****************************************************************************
+unsigned char g_pHIDDescriptor[] =
+{
+ //
+ // 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.
+//
+//*****************************************************************************
+unsigned char g_pHIDInterface[] =
+{
+ //
+ // 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.
+ 2, // 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.
+};
+
+const unsigned char g_pHIDInEndpoint[] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USB_EP_TO_INDEX(INT_IN_ENDPOINT),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(INT_IN_EP_MAX_SIZE), // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+const unsigned char g_pHIDOutEndpoint[] =
+{
+ //
+ // Interrupt OUT endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USB_EP_TO_INDEX(INT_OUT_ENDPOINT),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(INT_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// 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_pHIDDescriptor),
+ g_pHIDDescriptor
+};
+
+const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pHIDInterface),
+ g_pHIDInterface
+};
+
+const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pHIDInEndpoint),
+ g_pHIDInEndpoint
+};
+
+const tConfigSection g_sHIDOutEndpointSection =
+{
+ sizeof(g_pHIDOutEndpoint),
+ g_pHIDOutEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+tConfigSection g_sHIDDescriptorSection =
+{
+ 0, (void *)0
+};
+
+//*****************************************************************************
+//
+// 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,
+ &g_sHIDOutEndpointSection
+};
+
+#define NUM_HID_SECTIONS (sizeof(g_psHIDSections) / \
+ sizeof(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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_pHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleGetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest);
+static void HandleRequest(void *pvInstance, tUSBRequest *pUSBRequest);
+static void HandleConfigChange(void *pvInstance, unsigned long ulInfo);
+static void HandleEP0DataReceived(void *pvInstance, unsigned long ulInfo);
+static void HandleEP0DataSent(void *pvInstance, unsigned long ulInfo);
+static void HandleReset(void *pvInstance);
+static void HandleSuspend(void *pvInstance);
+static void HandleResume(void *pvInstance);
+static void HandleDisconnect(void *pvInstance);
+static void HandleEndpoints(void *pvInstance, unsigned long ulStatus);
+static void HandleDevice(void *pvInstance, unsigned long ulRequest,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB HID devices.
+//
+//*****************************************************************************
+tDeviceInfo g_sHIDDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ HandleGetDescriptor, // GetDescriptor
+ HandleRequest, // RequestHandler
+ 0, // InterfaceChange
+ HandleConfigChange, // ConfigChange
+ HandleEP0DataReceived, // DataReceived
+ HandleEP0DataSent, // DataSentCallback
+ HandleReset, // ResetHandler
+ HandleSuspend, // SuspendHandler
+ HandleResume, // ResumeHandler
+ HandleDisconnect, // DisconnectHandler
+ HandleEndpoints, // EndpointHandler
+ HandleDevice // Device handler.
+ },
+ g_pHIDDeviceDescriptor,
+ g_pHIDConfigDescriptors,
+ 0, // Will be completed during USBDHIDInit().
+ 0, // Will be completed during USBDHIDInit().
+ &g_sUSBDefaultFIFOConfig
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pusDeferredOp points to the flags variable which is to be modified.
+// \param usBit 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 unsigned short *pusDeferredOp,
+ unsigned short usBit, tBoolean bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pusDeferredOp, usBit) = 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 psDevice points to the HID device structure whose report timer is to
+// be cleared.
+// \param ucReportID 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 psDevice structure.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ClearReportTimer(const tUSBDHIDDevice *psDevice, unsigned char ucReportID)
+{
+ unsigned long ulLoop;
+
+ if(psDevice->ucNumInputReports > 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(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
+ {
+ if(psDevice->psReportIdle[ulLoop].ucReportID == ucReportID)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ ulLoop = 0;
+ }
+
+ //
+ // If we drop out of the loop with an index less than ucNumInputReports,
+ // we found the relevant report so clear its timer.
+ //
+ if(ulLoop < psDevice->ucNumInputReports)
+ {
+ psDevice->psReportIdle[ulLoop].ulTimeSinceReportmS = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called to clear the idle period timers for each input
+// report supported by the device.
+//
+// \param psDevice points to the HID device structure whose timers are to be
+// cleared.
+// \param ulTimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ClearIdleTimers(const tUSBDHIDDevice *psDevice)
+{
+ unsigned long ulLoop;
+
+ //
+ // Clear the "time till next report" counters for each input report.
+ //
+ for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
+ {
+ psDevice->psReportIdle[ulLoop].usTimeTillNextmS =
+ psDevice->psReportIdle[ulLoop].ucDuration4mS * 4;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called periodically to allow us to process the report idle
+// timers.
+//
+// \param psDevice points to the HID device structure whose timers are to be
+// updated.
+// \param ulElapsedmS indicates the number of milliseconds that have elapsed
+// since the last call to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ProcessIdleTimers(const tUSBDHIDDevice *psDevice, unsigned long ulElapsedmS)
+{
+ unsigned long ulLoop;
+ unsigned long ulSizeReport;
+ void *pvReport;
+ tHIDInstance *psInst;
+ tBoolean bDeferred;
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDHIDDevice *)psDevice)->psPrivateHIDData;
+
+ //
+ // We have not had to defer any report transmissions yet.
+ //
+ bDeferred = false;
+
+ //
+ // Look at each of the input report idle timers in turn.
+ //
+ for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
+ {
+ //
+ // Update the time since the last report was sent.
+ //
+ psDevice->psReportIdle[ulLoop].ulTimeSinceReportmS += ulElapsedmS;
+
+ //
+ // Is this timer running?
+ //
+ if(psDevice->psReportIdle[ulLoop].ucDuration4mS)
+ {
+ //
+ // Yes - is it about to expire?
+ //
+ if(psDevice->psReportIdle[ulLoop].usTimeTillNextmS <= ulElapsedmS)
+ {
+ //
+ // The timer is about to expire. Can we send a report right
+ // now?
+ //
+ if((psInst->eHIDTxState == HID_STATE_IDLE) &&
+ (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.
+ //
+ ulSizeReport = psDevice->pfnRxCallback(
+ psDevice->pvRxCBData,
+ USBD_HID_EVENT_IDLE_TIMEOUT,
+ psDevice->psReportIdle[ulLoop].ucReportID,
+ &pvReport);
+
+ //
+ // Schedule the report for transmission.
+ //
+ USBDHIDReportWrite((void *)psDevice, pvReport,
+ ulSizeReport, true);
+
+ //
+ // Reload the timer for the next period.
+ //
+ psDevice->psReportIdle[ulLoop].usTimeTillNextmS =
+ psDevice->psReportIdle[ulLoop].ucDuration4mS * 4;
+ }
+ else
+ {
+ //
+ // We can't send the report straight away so flag it for
+ // transmission as soon as the previous transmission ends.
+ //
+ psDevice->psReportIdle[ulLoop].usTimeTillNextmS = 0;
+ bDeferred = true;
+ }
+ }
+ else
+ {
+ //
+ // The timer is not about to expire. Update the time till the
+ // next report transmission.
+ //
+ psDevice->psReportIdle[ulLoop].usTimeTillNextmS -= ulElapsedmS;
+ }
+ }
+ }
+
+ //
+ // If we had to defer transmission of any report, remember this so that we
+ // will process it as soon as possible.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags,
+ HID_DO_SEND_IDLE_REPORT, bDeferred);
+}
+
+static void
+SetIdleTimeout(const tUSBDHIDDevice *psDevice, unsigned char ucReportID,
+ unsigned char ucTimeout4mS)
+{
+ unsigned long ulLoop;
+ tBoolean 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(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
+ {
+ psIdle = &psDevice->psReportIdle[ulLoop];
+
+ //
+ // 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(!ucReportID || (ucReportID == psIdle->ucReportID))
+ {
+ //
+ // Save the new duration for the idle timer.
+ //
+ psIdle->ucDuration4mS = ucTimeout4mS;
+
+ //
+ // Are we enabling the idle timer? If so, fix up the time until it
+ // needs to fire.
+ //
+ if(ucTimeout4mS)
+ {
+ //
+ // Determine what the timeout is for this report given the time
+ // since the last report of this type was sent.
+ //
+ if(psIdle->ulTimeSinceReportmS >=
+ ((unsigned long)ucTimeout4mS * 4))
+ {
+ psIdle->usTimeTillNextmS = 0;
+ bReportNeeded = true;
+ }
+ else
+ {
+ psIdle->usTimeTillNextmS =
+ (((unsigned short)ucTimeout4mS * 4) -
+ psIdle->ulTimeSinceReportmS);
+ }
+ }
+ }
+ }
+
+ //
+ // 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(psDevice, 0);
+ }
+}
+
+//*****************************************************************************
+//
+// Find the idle timeout for a given HID input report.
+//
+// \param psDevice points to the HID device whose report idle timeout is to be
+// found.
+// \param ucReportID 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 unsigned long
+GetIdleTimeout(const tUSBDHIDDevice *psDevice, unsigned char ucReportID)
+{
+ unsigned long ulLoop;
+ tHIDReportIdle *psIdle;
+
+ //
+ // Search through all the input reports looking for ones that fit the
+ // requirements.
+ //
+ for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
+ {
+ psIdle = &psDevice->psReportIdle[ulLoop];
+
+ //
+ // 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(!ucReportID || (ucReportID == psIdle->ucReportID))
+ {
+ //
+ // 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((unsigned long)psIdle->ucDuration4mS);
+ }
+ }
+
+ //
+ // If we drop out, the report couldn't 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 psDevice points to the HID device which is to be searched for the
+// required class descriptor.
+// \param ucType is the type of class descriptor being requested. This will
+// be either USB_HID_DTYPE_REPORT or USB_HID_DTYPE_PHYSICAL.
+// \param ulIndex 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 unsigned long
+FindHIDDescriptor(const tUSBDHIDDevice *psDevice, unsigned char ucType,
+ unsigned long ulIndex, unsigned long *pulLen)
+{
+ tBoolean bFoundType;
+ unsigned long ulLoop;
+ unsigned long ulCount;
+ unsigned long ulLastFound;
+ const tHIDClassDescriptorInfo *psDesc;
+
+ //
+ // Remember that we have not found any descriptor with a matching type yet.
+ //
+ bFoundType = false;
+ ulCount = 0;
+ ulLastFound = 0;
+
+ //
+ // Walk through all the class descriptors looking for the one which
+ // matches the requested index and type.
+ //
+ for(ulLoop = 0; ulLoop < psDevice->psHIDDescriptor->bNumDescriptors;
+ ulLoop++)
+ {
+ psDesc = &(psDevice->psHIDDescriptor->sClassDescriptor[ulLoop]);
+ if(psDesc->bDescriptorType == ucType)
+ {
+ //
+ // We found a descriptor of the correct type. Is this the
+ // correct index?
+ //
+ bFoundType = true;
+
+ //
+ // Is this the descriptor we are looking for?
+ //
+ if(ulCount == ulIndex)
+ {
+ //
+ // Yes - we found it so return the index and size to the
+ // caller.
+ //
+ *pulLen = (unsigned long)psDesc->wDescriptorLength;
+ return(ulLoop);
+ }
+ 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.
+ //
+ ulCount++;
+ ulLastFound = ulLoop;
+ }
+ }
+ }
+
+ //
+ // If we drop out, we didn't find the requested descriptor. Now handle
+ // the special case of a physical descriptor - if we found any physical
+ // descriptors, return the last one.
+ //
+ if((ucType == USB_HID_DTYPE_PHYSICAL) && bFoundType)
+ {
+ //
+ // Get the length of the last descriptor we found.
+ //
+ psDesc = &(psDevice->psHIDDescriptor->sClassDescriptor[ulLastFound]);
+ *pulLen = (unsigned long)psDesc->wDescriptorLength;
+
+ //
+ // Return the index to the caller.
+ //
+ return(ulLastFound);
+ }
+ else
+ {
+ //
+ // We couldn't 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 psInst points to the 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 short packet or a
+// packet with no data to indicate the end of the transaction.
+//
+//*****************************************************************************
+static long
+ScheduleReportTransmission(tHIDInstance *psInst)
+{
+ unsigned long ulNumBytes;
+ unsigned char *pucData;
+ long lRetcode;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ulNumBytes = (unsigned long)(psInst->usInReportSize -
+ psInst->usInReportIndex);
+
+ //
+ // Limit individual transfers to the maximum packet size for the endpoint.
+ //
+ if(ulNumBytes > INT_IN_EP_MAX_SIZE)
+ {
+ ulNumBytes = INT_IN_EP_MAX_SIZE;
+ }
+
+ //
+ // Where are we sending this data from?
+ //
+ pucData = psInst->pucInReportData + psInst->usInReportIndex;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ lRetcode = MAP_USBEndpointDataPut(psInst->ulUSBBase, psInst->ucINEndpoint,
+ pucData, ulNumBytes);
+
+ if(lRetcode != -1)
+ {
+ //
+ // Update the count and index ready for the next time round.
+ //
+ psInst->usInReportIndex += ulNumBytes;
+
+ //
+ // Send out the current data.
+ //
+ lRetcode = MAP_USBEndpointDataSend(psInst->ulUSBBase,
+ psInst->ucINEndpoint,
+ USB_TRANS_IN);
+ }
+
+ //
+ // Tell the caller how we got on.
+ //
+ return(lRetcode);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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 tBoolean
+ProcessDataFromHost(const tUSBDHIDDevice *psDevice, unsigned long ulStatus)
+{
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+ tHIDInstance *psInst;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ucOUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ucOUTEndpoint, ulEPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ulEPStatus & 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 signaled later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags, HID_DO_PACKET_RX, true);
+
+ //
+ // How big is the packet we've just been sent?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ //
+ // 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.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ulSize,
+ (void *)0);
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ulEPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ulEPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psDevice is the device instance whose endpoint is to be processed.
+// \param ulStatus 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 tBoolean
+ProcessDataToHost(const tUSBDHIDDevice *psDevice, unsigned long ulStatus)
+{
+ tHIDInstance *psInst;
+ unsigned long ulEPStatus;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase, psInst->ucINEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucINEndpoint,
+ ulEPStatus);
+
+ //
+ // 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 usInReportIndex has reached the usInReportSize value.
+ //
+ if(psInst->usInReportSize == psInst->usInReportIndex)
+ {
+ //
+ // We finished sending the last report so are idle once again.
+ //
+ psInst->eHIDTxState = HID_STATE_IDLE;
+
+ //
+ // Notify the client that the report transmission completed.
+ //
+ psDevice->pfnTxCallback(psDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
+ psInst->usInReportSize, (void *)0);
+
+ //
+ // Do we have any reports to send as a result of idle timer timeouts?
+ //
+ if(psInst->usDeferredOpFlags & (1 << HID_DO_SEND_IDLE_REPORT))
+ {
+ //
+ // Yes - send reports for any timers that expired recently.
+ //
+ ProcessIdleTimers(psDevice, 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 ulStatus.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvInstance, unsigned long ulStatus)
+{
+ const tUSBDHIDDevice *psHIDInst;
+ tHIDInstance *psInst;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ulIndex is different in both cases.
+ //
+ psHIDInst = (const tUSBDHIDDevice *)pvInstance;
+ psInst = psHIDInst->psPrivateHIDData;
+
+ //
+ // Handler for the interrupt OUT data endpoint.
+ //
+ if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucOUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(pvInstance, ulStatus);
+ }
+
+ //
+ // Handler for the interrupt IN data endpoint.
+ //
+ if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucINEndpoint)))
+ {
+ ProcessDataToHost(pvInstance, ulStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvInstance, unsigned long ulInfo)
+{
+ tHIDInstance *psInst;
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->eHIDRxState = HID_STATE_IDLE;
+ psInst->eHIDTxState = HID_STATE_IDLE;
+
+ //
+ // 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.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_CONNECTED, 0,
+ (void *)0);
+ }
+
+ //
+ // Clear the idle timers for each input report.
+ //
+ ClearIdleTimers(psDevice);
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvInstance, unsigned long ulRequest, void *pvRequestData)
+{
+ tHIDInstance *psInst;
+ unsigned char *pucData;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
+
+ //
+ // Create the char array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pucData = (unsigned char *)pvRequestData;
+
+ switch(ulRequest)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ucInterface = pucData[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(pucData[0] & USB_EP_DESC_IN)
+ {
+ psInst->ucINEndpoint =
+ INDEX_TO_USB_EP((pucData[1] & 0x7f));
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ucOUTEndpoint =
+ INDEX_TO_USB_EP(pucData[1] & 0x7f);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvInstance)
+{
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDHIDDevice *)pvInstance;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(psDevice->psPrivateHIDData->bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_DISCONNECTED,
+ 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psDevice->psPrivateHIDData->bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a request for a
+// non-standard descriptor is received.
+//
+// \param pvInstance is the instance data for this request.
+// \param pUSBRequest 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ unsigned long ulSize;
+ unsigned long ulDesc;
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psDevice = pvInstance;
+
+ //
+ // Which type of class descriptor are we being asked for?
+ //
+ switch(pUSBRequest->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.
+ //
+ ulSize = 0;
+ ulDesc = FindHIDDescriptor(psDevice, pUSBRequest->wValue >> 8,
+ pUSBRequest->wValue & 0xFF,
+ &ulSize);
+
+ //
+ // Did we find the descriptor?
+ //
+ if(ulDesc == 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(ulSize > pUSBRequest->wLength)
+ {
+ ulSize = pUSBRequest->wLength;
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0,
+ (unsigned char *)psDevice->ppClassDescriptors[ulDesc], ulSize);
+
+ 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?
+ //
+ ulSize = (unsigned long)psDevice->psHIDDescriptor->bLength;
+
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if(ulSize > pUSBRequest->wLength)
+ {
+ ulSize = pUSBRequest->wLength;
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0, (unsigned char *)psDevice->psHIDDescriptor,
+ ulSize);
+ 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 pvInstance is the instance data for this HID device.
+// \param pUSBRequest 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ tHIDInstance *psInst;
+ unsigned char ucProtocol;
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psDevice = pvInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // Make sure the request was for this interface.
+ //
+ if(pUSBRequest->wIndex != psInst->ucInterface)
+ {
+ return;
+ }
+
+ //
+ // 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_SET_REPORT:
+ {
+ //
+ // Ask the application for a buffer large enough to hold the
+ // report we are to be sent.
+ //
+ psInst->usOutReportSize = pUSBRequest->wLength;
+ psInst->pucOutReportData =
+ (unsigned char *)psDevice->pfnRxCallback(
+ psDevice->pvRxCBData,
+ USBD_HID_EVENT_GET_REPORT_BUFFER,
+ pUSBRequest->wValue,
+ (void *)(unsigned long)(pUSBRequest->wLength));
+
+ //
+ // Did the client provide us a buffer?
+ //
+ if(!psInst->pucOutReportData)
+ {
+ //
+ // The application couldn't 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->eHIDRxState = HID_STATE_WAIT_DATA;
+
+ //
+ // Now read the payload of the request. We handle the actual
+ // operation in the data callback once this data is received.
+ //
+ USBDCDRequestDataEP0(0, psInst->pucOutReportData,
+ (unsigned long)pUSBRequest->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->ulUSBBase, 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:
+ {
+ unsigned long ulSize;
+ unsigned char *pucReport;
+
+ //
+ // Get the latest report from the application.
+ //
+ ulSize = psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USBD_HID_EVENT_GET_REPORT,
+ pUSBRequest->wValue, &pucReport);
+
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
+
+ //
+ // ..then send back the requested report.
+ //
+ psInst->bGetRequestPending = true;
+ USBDCDSendDataEP0(0, pucReport, ulSize);
+
+ 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(psDevice, pUSBRequest->wValue & 0xFF,
+ (pUSBRequest->wValue >> 8) & 0xFF);
+
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, 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:
+ {
+ unsigned long ulTimeout;
+
+ //
+ // Determine the timeout for the requested report.
+ //
+ ulTimeout = GetIdleTimeout(psDevice, pUSBRequest->wValue);
+
+ if(ulTimeout != HID_NOT_FOUND)
+ {
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (unsigned char *)&ulTimeout, 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(psDevice->ucSubclass == USB_HID_SCLASS_BOOT)
+ {
+ //
+ // We need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
+
+ //
+ // We are a boot subclass device so pass this on to the
+ // application.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USBD_HID_EVENT_SET_PROTOCOL,
+ pUSBRequest->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(psDevice->ucSubclass == USB_HID_SCLASS_BOOT)
+ {
+ //
+ // We need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
+
+ //
+ // We are a boot subclass device so pass this on to the
+ // application callback to get the answer.
+ //
+ ucProtocol = (unsigned char)psDevice->pfnRxCallback(
+ psDevice->pvRxCBData, USBD_HID_EVENT_GET_PROTOCOL, 0,
+ (void *)0);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (unsigned char *)&ucProtocol, 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 *pvInstance, unsigned long ulDataSize)
+{
+ tHIDInstance *psInst;
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psDevice = pvInstance;
+
+ //
+ // If we were not passed any data, just return.
+ //
+ if(ulDataSize == 0)
+ {
+ return;
+ }
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // Make sure we are actually expecting something.
+ //
+ if(psInst->eHIDRxState != HID_STATE_WAIT_DATA)
+ {
+ return;
+ }
+
+ //
+ // Change the endpoint state back to idle now that we have been passed
+ // the data we were waiting for.
+ //
+ psInst->eHIDRxState = HID_STATE_IDLE;
+
+ //
+ // 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.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData, USBD_HID_EVENT_SET_REPORT,
+ psInst->usOutReportSize,
+ psInst->pucOutReportData);
+}
+
+//*****************************************************************************
+//
+// 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 *pvInstance, unsigned long ulInfo)
+{
+ tHIDInstance *psInst;
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psDevice = pvInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // 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;
+
+ psDevice->pfnRxCallback(psDevice->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 *pvInstance)
+{
+ ASSERT(pvInstance != 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(pvInstance);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvInstance)
+{
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDHIDDevice *)pvInstance;
+
+ //
+ // Pass the event on to the client.
+ //
+ psDevice->pfnRxCallback(psDevice->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 *pvInstance)
+{
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDHIDDevice *)pvInstance;
+
+ //
+ // Pass the event on to the client.
+ //
+ psDevice->pfnRxCallback(psDevice->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 pvInstance is the instance data for this request.
+// \param ulTimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HIDTickHandler(void *pvInstance, unsigned long ulTimemS)
+{
+ tHIDInstance *psInst;
+ unsigned long ulSize;
+ const tUSBDHIDDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDHIDDevice *)pvInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateHIDData;
+
+ //
+ // If we are connected, process our idle timers.
+ //
+ if(psInst->bConnected)
+ {
+ ProcessIdleTimers(psDevice, ulTimemS);
+ }
+
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->usDeferredOpFlags & (1 << HID_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ulSize = MAP_USBEndpointDataAvail(USB0_BASE, psInst->ucOUTEndpoint);
+
+ //
+ // Tell the client that there is a packet waiting for it.
+ //
+ psDevice->pfnRxCallback(psDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ulSize, (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes HID device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for HID device operation.
+//! \param psDevice 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 psDevice 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 64 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
+//! 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 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, 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 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 psDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDInit(unsigned long ulIndex, const tUSBDHIDDevice *psDevice)
+{
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateHIDData);
+ ASSERT(psDevice->pfnRxCallback);
+ ASSERT(psDevice->pfnTxCallback);
+ ASSERT(psDevice->ppClassDescriptors);
+ ASSERT(psDevice->psHIDDescriptor);
+ ASSERT((psDevice->ucNumInputReports == 0) || psDevice->psReportIdle);
+
+ USBDHIDCompositeInit(ulIndex, psDevice);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the HID device on the bus.
+ //
+ USBDCDInit(ulIndex, psDevice->psPrivateHIDData->psDevInfo);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for HID device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the HID device.
+//!
+//!
+//! \return Returns NULL on failure or the \e psDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDCompositeInit(unsigned long ulIndex, const tUSBDHIDDevice *psDevice)
+{
+ tHIDInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+ tInterfaceDescriptor *psDevIf;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateHIDData);
+ ASSERT(psDevice->pfnRxCallback);
+ ASSERT(psDevice->pfnTxCallback);
+ ASSERT(psDevice->ppClassDescriptors);
+ ASSERT(psDevice->psHIDDescriptor);
+ ASSERT((psDevice->ucNumInputReports == 0) || psDevice->psReportIdle);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateHIDData;
+ psInst->psConfDescriptor = (tConfigDescriptor *)g_pHIDDescriptor;
+ psInst->psDevInfo = &g_sHIDDeviceInfo;
+ psInst->ulUSBBase = USB0_BASE;
+ psInst->eHIDRxState = HID_STATE_UNCONFIGURED;
+ psInst->eHIDTxState = HID_STATE_UNCONFIGURED;
+ psInst->usDeferredOpFlags = 0;
+ psInst->bConnected = false;
+ psInst->bGetRequestPending = false;
+ psInst->bSendInProgress = false;
+ psInst->usInReportIndex = 0;
+ psInst->usInReportSize = 0;
+ psInst->pucInReportData = (unsigned char *)0;
+ psInst->usOutReportSize = 0;
+ psInst->pucOutReportData = (unsigned char *)0;
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ucINEndpoint = INT_IN_ENDPOINT;
+ psInst->ucOUTEndpoint = INT_OUT_ENDPOINT;
+ psInst->ucInterface = 0;
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
+ psDevDesc->idVendor = psDevice->usVID;
+ psDevDesc->idProduct = psDevice->usPID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
+ psInst->psConfDescriptor->bMaxPower =
+ (unsigned char)(psDevice->usMaxPowermA / 2);
+
+ //
+ // Slot the client's HID descriptor into our standard configuration
+ // descriptor.
+ //
+ g_sHIDDescriptorSection.usSize = psDevice->psHIDDescriptor->bLength;
+ g_sHIDDescriptorSection.pucData =
+ (unsigned char *)psDevice->psHIDDescriptor;
+
+ //
+ // Fix up the interface and endpoint descriptors depending upon client
+ // choices.
+ //
+ psDevIf = (tInterfaceDescriptor *)g_pHIDInterface;
+ psDevIf->bNumEndpoints = psDevice->bUseOutEndpoint ? 2 : 1;
+ psDevIf->bInterfaceSubClass = psDevice->ucSubclass;
+ psDevIf->bInterfaceProtocol = psDevice->ucProtocol;
+
+ //
+ // If necessary, remove the interrupt OUT endpoint from the configuration
+ // descriptor.
+ //
+ if(psDevice->bUseOutEndpoint == false)
+ {
+ g_sHIDConfigHeader.ucNumSections = (NUM_HID_SECTIONS - 1);
+ }
+ else
+ {
+ g_sHIDConfigHeader.ucNumSections = NUM_HID_SECTIONS;
+ }
+
+ //
+ // Plug in the client's string table to the device information
+ // structure.
+ //
+ psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psInst->psDevInfo->ulNumStringDescriptors
+ = psDevice->ulNumStringDescriptors;
+ psInst->psDevInfo->pvInstance = (void *)psDevice;
+
+ //
+ // Initialize the input report idle timers if any input reports exist.
+ //
+ ClearIdleTimers(psDevice);
+
+ //
+ // 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 *)psDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID device.
+//!
+//! \param pvInstance 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 pvInstance instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDTerm(void *pvInstance)
+{
+ tHIDInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USB_BASE_TO_INDEX(psInst->ulUSBBase));
+
+ psInst->ulUSBBase = 0;
+ psInst->psDevInfo = (tDeviceInfo *)0;
+ psInst->psConfDescriptor = (tConfigDescriptor *)0;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the receive channel
+//! callback.
+//!
+//! \param pvInstance 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 pvInstance 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 *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDHIDDevice *)pvInstance)->pvRxCBData;
+ ((tUSBDHIDDevice *)pvInstance)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data pointer for the transmit callback.
+//!
+//! \param pvInstance 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 pvInstance 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 *pvInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvInstance);
+
+ //
+ // Set the callback data for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDHIDDevice *)pvInstance)->pvTxCBData;
+ ((tUSBDHIDDevice *)pvInstance)->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 pvInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pcData points to the first byte of data which is to be transmitted.
+//! \param ulLength 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 pucData 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.
+//
+//*****************************************************************************
+unsigned long
+USBDHIDReportWrite(void *pvInstance, unsigned char *pcData,
+ unsigned long ulLength, tBoolean bLast)
+{
+ tHIDInstance *psInst;
+ long lRetcode;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
+
+ //
+ // 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->eHIDTxState != HID_STATE_IDLE)
+ {
+ //
+ // 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(ulLength)
+ {
+ ClearReportTimer(pvInstance, *pcData);
+ }
+
+ //
+ // Keep track of the whereabouts of the report so that we can send it in
+ // multiple packets if necessary.
+ //
+ psInst->pucInReportData = pcData;
+ psInst->usInReportIndex = 0;
+ psInst->usInReportSize = ulLength;
+
+ //
+ // Schedule transmission of the first packet of the report.
+ //
+ psInst->eHIDTxState = HID_STATE_WAIT_DATA;
+ lRetcode = 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(lRetcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ulLength);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we couldn't send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the interrupt OUT
+//! endpoint (if in use).
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pcData points to a buffer into which the received data will be
+//! written.
+//! \param ulLength is the size of the buffer pointed to by pcData.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to ulLength 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.
+//
+//*****************************************************************************
+unsigned long
+USBDHIDPacketRead(void *pvInstance, unsigned char *pcData,
+ unsigned long ulLength, tBoolean bLast)
+{
+ unsigned long ulEPStatus, ulCount, ulPkt;
+ tHIDInstance *psInst;
+ long lRetcode;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+ if(ulEPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // How many bytes are available for us to receive?
+ //
+ ulPkt = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ulCount = ulLength;
+ lRetcode = MAP_USBEndpointDataGet(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint,
+ pcData, &ulCount);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ulCount == ulPkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint,
+ ulEPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase, psInst->ucOUTEndpoint,
+ true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->usDeferredOpFlags,
+ HID_DO_PACKET_RX, false);
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(lRetcode != -1)
+ {
+ return(ulCount);
+ }
+ }
+
+ //
+ // 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 pvInstance 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 (64) 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 64
+//! if no transmission is currently in progress.
+//
+//*****************************************************************************
+unsigned long
+USBDHIDTxPacketAvailable(void *pvInstance)
+{
+ tHIDInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->eHIDTxState != HID_STATE_IDLE)
+ {
+ //
+ // 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(INT_IN_EP_MAX_SIZE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvInstance 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.
+//
+//*****************************************************************************
+unsigned long
+USBDHIDRxPacketAvailable(void *pvInstance)
+{
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+ tHIDInstance *psInst;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ulEPStatus = MAP_USBEndpointStatus(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+ if(ulEPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ulSize = MAP_USBEndpointDataAvail(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint);
+
+ return(ulSize);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvInstance is the pointer to the HID device instance structure.
+//! \param ucPower 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 *pvInstance, unsigned char ucPower)
+{
+ ASSERT(pvInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ucPower);
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvInstance 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.
+//
+//*****************************************************************************
+tBoolean
+USBDHIDRemoteWakeupRequest(void *pvInstance)
+{
+ ASSERT(pvInstance);
+
+ //
+ // 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..80b1126
--- /dev/null
+++ b/usblib/device/usbdhid.h
@@ -0,0 +1,974 @@
+//*****************************************************************************
+//
+// usbdhid.h - Definitions used by HID class devices.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris 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
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! 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.
+//
+// For reference this is
+// sizeof(g_sHIDInterfaceSection) + sizeof(g_sHIDDescriptorSection) +
+// sizeof(g_sHIDInEndpointSection) + sizeof(g_sHIDOutEndpointSection)
+//
+//*****************************************************************************
+#define COMPOSITE_DHID_SIZE (32)
+
+//*****************************************************************************
+//
+// Macros used to create the static Report Descriptors.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Page entries in HID report
+//! descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x05, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage entries in HID report descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x09, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Minimum entries in HID report
+//! descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x19, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Maximum entries in HID report
+//! descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x29, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Logical Minimum entries in HID report
+//! descriptors.
+//!
+//! \param cValue 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(cValue) 0x15, ((cValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Logical Maximum entries in HID report
+//! descriptors.
+//!
+//! \param cValue 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(cValue) 0x25, ((cValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Physical Minimum entries in HID report
+//! descriptors.
+//!
+//! \param sValue 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(sValue) 0x36, ((sValue) & 0xFF), \
+ (((sValue) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Physical Maximum entries in HID report
+//! descriptors.
+//!
+//! \param sValue 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(sValue) 0x46, ((sValue) & 0xFF), \
+ (((sValue) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Collection entries in HID report
+//! descriptors.
+//!
+//! \param ucValue 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(ucValue) 0xa1, ((ucValue) & 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 ucValue 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(ucValue) 0x95, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report ID entries in HID report
+//! descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x85, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report Size entries in HID report
+//! descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x75, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Input entries in HID report descriptors.
+//!
+//! \param ucValue 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(ucValue) 0x81, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Input entries in HID report descriptors.
+//!
+//! \param usValue 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(usValue) 0x82, ((usValue) & 0xff), \
+ (((usValue) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Feature entries in HID report descriptors.
+//!
+//! \param ucValue is bit mask to specify the type of a set of feature report
+//! items. Note that if the 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(ucValue) 0xB1, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Feature entries in HID report descriptors.
+//!
+//! \param usValue 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 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(usValue) 0xB2, ((usValue) & 0xff), \
+ (((usValue) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Output entries in HID report descriptors.
+//!
+//! \param ucValue is bit mask to specify the type of a set of output report
+//! items. Note that if the 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(ucValue) 0x91, ((ucValue) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Output entries in HID report descriptors.
+//!
+//! \param usValue 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 USB_HID_OUTPUT_BITF (bit 8) 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(usValue) 0x92, ((usValue) & 0xff), \
+ (((usValue) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Unit Exponent entries in HID report
+//! descriptors.
+//!
+//! \param cValue 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(cValue) 0x55, ((cValue) & 0x0f)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Unit entries for uncommon units in HID
+//! report descriptors.
+//!
+//! \param ulValue 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(ulValue) 0x67, (ulValue) & 0x0f), \
+ (((ulValue) >> 8) & 0xFF), \
+ (((ulValue) >> 16) & 0xFF), \
+ (((ulValue) >> 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.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ HID_STATE_UNCONFIGURED,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ HID_STATE_IDLE,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ HID_STATE_WAIT_DATA
+}
+tHIDState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for
+// HID devices. The memory for this structure is pointed to by the
+// psPrivateHIDData field in the tUSBDHIDDevice structure passed in the
+// USBDHIDInit() function.
+//
+//*****************************************************************************
+typedef struct
+{
+ unsigned long ulUSBBase;
+ tDeviceInfo *psDevInfo;
+ tConfigDescriptor *psConfDescriptor;
+ volatile tHIDState eHIDRxState;
+ volatile tHIDState eHIDTxState;
+ volatile unsigned short usDeferredOpFlags;
+ unsigned short usInReportSize;
+ unsigned short usInReportIndex;
+ unsigned short usOutReportSize;
+ unsigned char *pucInReportData;
+ unsigned char *pucOutReportData;
+ volatile tBoolean bConnected;
+ volatile tBoolean bSendInProgress;
+ tBoolean bGetRequestPending;
+ unsigned char ucINEndpoint;
+ unsigned char ucOUTEndpoint;
+ unsigned char ucInterface;
+}
+tHIDInstance;
+
+#ifndef DEPRECATED
+//*****************************************************************************
+//
+// The number of bytes of workspace required by the HID device class driver.
+// The client must provide a block of RAM of at least this size in the
+// pvWorkspace field of the tUSBDHIDDevice structure passed on USBDHIDInit.
+//
+//*****************************************************************************
+#define USB_HID_WORKSPACE_SIZE sizeof(tHIDInstance)
+#endif
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned char ucDuration4mS;
+
+ //
+ //! 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.
+ //
+ unsigned char ucReportID;
+
+ //
+ //! 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 USBD_HID_EVENT_IDLE_TIMEOUT.
+ //
+ unsigned short usTimeTillNextmS;
+
+ //
+ //! 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.
+ //
+ unsigned long ulTimeSinceReportmS;
+}
+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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! The interface subclass to publish to the server for this HID device.
+ //
+ unsigned char ucSubclass;
+
+ //
+ //! The interface protocol to publish to the server for this HID device.
+ //
+ unsigned char ucProtocol;
+
+ //
+ //! 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 psReportIdle below.
+ //
+ unsigned char ucNumInputReports;
+
+ //
+ //! 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
+ //! ucDuration4mS and ucReportID 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 will update 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 ucNumInputReports field above.
+ //
+ tHIDReportIdle *psReportIdle;
+
+ //! A pointer to the callback function which will be 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 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 transmission of Input reports
+ //! via the interrupt IN endpoint.
+ //
+ 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;
+
+ //
+ //! 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 USB_EVENT_RX_AVAILABLE events. If false,
+ //! reports from the host are received via endpoint zero and passed to the
+ //! application via USBD_HID_EVENT_REPORT_SENT events.
+ //
+ tBoolean 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 psHIDDescriptor.
+ //
+ const unsigned char * const *ppClassDescriptors;
+
+ //
+ //! 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (num HID strings)) * (num languages)).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! A pointer to 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 *psPrivateHIDData;
+}
+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 ulMsgValue 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
+//! 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
+//! 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 ulMsgValue 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 "unsigned long" 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 ulMsgValue field indicates the
+//! size of the report and pvMsgData points to the first byte of the report.
+//! The report buffer will previously have been returned in response to an
+//! earlier USBD_HID_EVENT_GET_REPORT_BUFFER callback. The HID device class
+//! driver will 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,
+//! USB_HID_PROTOCOL_BOOT or 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 ulMsgData value will contain the requested protocol,
+//! USB_HID_PROTOCOL_BOOT or 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 ulMsgData value will contain 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)
+
+extern tDeviceInfo g_sHIDDeviceInfo;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDInit(unsigned long ulIndex,
+ const tUSBDHIDDevice *psHIDDevice);
+extern void *USBDHIDCompositeInit(unsigned long ulIndex,
+ const tUSBDHIDDevice *psDevice);
+
+extern void USBDHIDTerm(void *pvInstance);
+extern void *USBDHIDSetRxCBData(void *pvInstance, void *pvCBData);
+extern void *USBDHIDSetTxCBData(void *pvInstance, void *pvCBData);
+extern unsigned long USBDHIDReportWrite(void *pvInstance,
+ unsigned char *pcData,
+ unsigned long ulLength,
+ tBoolean bLast);
+extern unsigned long USBDHIDPacketRead(void *pvInstance,
+ unsigned char *pcData,
+ unsigned long ulLength,
+ tBoolean bLast);
+extern unsigned long USBDHIDTxPacketAvailable(void *pvInstance);
+extern unsigned long USBDHIDRxPacketAvailable(void *pvInstance);
+extern void USBDHIDPowerStatusSet(void *pvInstance, unsigned char ucPower);
+extern tBoolean USBDHIDRemoteWakeupRequest(void *pvInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHID_H__
diff --git a/usblib/device/usbdhidkeyb.c b/usblib/device/usbdhidkeyb.c
new file mode 100644
index 0000000..8b4aa95
--- /dev/null
+++ b/usblib/device/usbdhidkeyb.c
@@ -0,0 +1,1119 @@
+//*****************************************************************************
+//
+// usbdhidkeyb.c - USB HID Keyboard device class driver.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.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
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following is the HID report structure definition that is passed back
+// to the host.
+//
+//*****************************************************************************
+static const unsigned char g_pucKeybReportDescriptor[]=
+{
+ 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 class descriptor table. For the keyboard class, we have only a
+// single report descriptor.
+//
+//*****************************************************************************
+static const unsigned char * const g_pKeybClassDescriptors[] =
+{
+ g_pucKeybReportDescriptor
+};
+
+//*****************************************************************************
+//
+// 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_pucKeybReportDescriptor) // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// Forward references for keyboard device callback functions.
+//
+//*****************************************************************************
+static unsigned long HIDKeyboardRxHandler(void *pvCBData,
+ unsigned long ulEvent,
+ unsigned long ulMsgData,
+ void *pvMsgData);
+static unsigned long HIDKeyboardTxHandler(void *pvCBData,
+ unsigned long ulEvent,
+ unsigned long ulMsgData,
+ void *pvMsgData);
+
+//*****************************************************************************
+//
+// Main HID device class event handler function.
+//
+// \param pvCBData is the event callback pointer provided during USBDHIDInit().
+// This is a pointer to our HID device structure (&g_sHIDKeybDevice).
+// \param ulEvent identifies the event we are being called back for.
+// \param ulMsgData 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 unsigned long
+HIDKeyboardRxHandler(void *pvCBData, unsigned long ulEvent,
+ unsigned long ulMsgData, void *pvMsgData)
+{
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psDevice;
+
+ //
+ // Make sure we didn't get a NULL pointer.
+ //
+ ASSERT(pvCBData);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psDevice = (tUSBDHIDKeyboardDevice *)pvCBData;
+ psInst = psDevice->psPrivateHIDKbdData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ulEvent)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ psInst->ucUSBConfigured = true;
+
+ //
+ // Pass the information on to the client.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData, USB_EVENT_CONNECTED,
+ 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->ucUSBConfigured = false;
+
+ //
+ // Pass the information on to the client.
+ //
+ psDevice->pfnCallback(psDevice->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 ulMsgValue parameter in this case. Set the report pointer
+ // in *pvMsgData and return the length of the report in bytes.
+ //
+ *(unsigned char **)pvMsgData = psInst->pucReport;
+ 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((unsigned long)pvMsgData == KEYB_OUT_REPORT_SIZE )
+ {
+ //
+ // Yes - return our pointer.
+ //
+ return((unsigned long)psInst->pucDataBuffer);
+ }
+ 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->ucLEDStates != psInst->pucDataBuffer[0])
+ {
+ //
+ // Note the new LED states.
+ //
+ psInst->ucLEDStates = psInst->pucDataBuffer[0];
+
+ //
+ // Pass the information on to the client.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData,
+ USBD_HID_KEYB_EVENT_SET_LEDS,
+ psInst->pucDataBuffer[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->ucProtocol = ulMsgData;
+ 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->ucProtocol);
+ }
+
+ //
+ // Pass ERROR, SUSPEND and RESUME to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ {
+ return(psDevice->pfnCallback(psDevice->pvCBData, ulEvent,
+ ulMsgData, pvMsgData));
+ }
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// HID device class transmit channel event handler function.
+//
+// \param pvCBData is the event callback pointer provided during USBDHIDInit().
+// This is a pointer to our HID device structure (&g_sHIDKeybDevice).
+// \param ulEvent identifies the event we are being called back for.
+// \param ulMsgData 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 unsigned long
+HIDKeyboardTxHandler(void *pvCBData, unsigned long ulEvent,
+ unsigned long ulMsgData, void *pvMsgData)
+{
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+ unsigned long ulCount;
+
+ //
+ // Make sure we didn't get a NULL pointer.
+ //
+ ASSERT(pvCBData);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psDevice = (tUSBDHIDKeyboardDevice *)pvCBData;
+ psInst = psDevice->psPrivateHIDKbdData;
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->sHIDDevice;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ulEvent)
+ {
+ //
+ // 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.
+ //
+ ulCount = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pucReport,
+ KEYB_IN_REPORT_SIZE, true);
+
+ //
+ // If we scheduled the report for transmission, clear the
+ // change flag.
+ //
+ if(ulCount != 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.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData, USB_EVENT_TX_COMPLETE,
+ ulMsgData, (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 ucUsageCode 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 tBoolean
+AddKeyToPressedList(tHIDKeyboardInstance *psInst, unsigned char ucUsageCode)
+{
+ unsigned long ulLoop;
+ tBoolean 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(ulLoop = 0; ulLoop < (unsigned long)psInst->ucKeyCount; ulLoop++)
+ {
+ //
+ // Is this key already included in the list of keys in the pressed
+ // state?
+ //
+ if(ucUsageCode == psInst->pucKeysPressed[ulLoop])
+ {
+ //
+ // 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(ulLoop >= psInst->ucKeyCount)
+ {
+ if(psInst->ucKeyCount < KEYB_MAX_CHARS_PER_REPORT)
+ {
+ //
+ // We have room so store the new key press in the list.
+ //
+ psInst->pucKeysPressed[psInst->ucKeyCount] = ucUsageCode;
+ psInst->ucKeyCount++;
+ 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 ucUsageCode 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 will have 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 will not have
+// changed.
+//
+//*****************************************************************************
+static tBoolean
+RemoveKeyFromPressedList(tHIDKeyboardInstance *psInst,
+ unsigned char ucUsageCode)
+{
+ unsigned long ulLoop;
+ unsigned long ulPos;
+
+ //
+ // Keep the compiler happy by setting ulPos to something.
+ //
+ ulPos = 0;
+
+ //
+ // Find the usage code in the current list.
+ //
+ for(ulLoop = 0; ulLoop < KEYB_MAX_CHARS_PER_REPORT; ulLoop++)
+ {
+ if(psInst->pucKeysPressed[ulLoop] == ucUsageCode)
+ {
+ ulPos = ulLoop;
+ break;
+ }
+ }
+
+ //
+ // If we dropped out at the end of the loop, we couldn't find the code so
+ // just return false.
+ //
+ if(ulLoop == 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(ulLoop = (ulPos + 1); ulLoop < KEYB_MAX_CHARS_PER_REPORT; ulLoop++)
+ {
+ psInst->pucKeysPressed[ulLoop - 1] = psInst->pucKeysPressed[ulLoop];
+ }
+
+ //
+ // Clear the last entry in the array and adjust the number of keys in the
+ // array.
+ //
+ psInst->pucKeysPressed[KEYB_MAX_CHARS_PER_REPORT - 1] =
+ HID_KEYB_USAGE_RESERVED;
+ psInst->ucKeyCount--;
+
+ //
+ // Tell the caller we were successful.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID keyboard device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for HID keyboard device operation.
+//! \param psDevice 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 will return the \e psDevice 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
+//! will receive \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 will cause unpredictable (though almost certainly
+//! unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the psDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardInit(unsigned long ulIndex,
+ const tUSBDHIDKeyboardDevice *psDevice)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateHIDKbdData);
+ ASSERT(psDevice->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->sHIDDevice;
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDKeyboardCompositeInit(ulIndex, psDevice);
+
+ //
+ // 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(ulIndex, psHIDDevice);
+
+ return((void *)psDevice);
+ }
+ else
+ {
+ return((void *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID keyboard device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for HID keyboard device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the HID keyboard device.
+//!
+//! This call is very similar to USBDKeyboardInit() except that it is used for
+//! initializing an instance of the HID keyboard device for use in a composite
+//! device.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID Keyboard APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardCompositeInit(unsigned long ulIndex,
+ const tUSBDHIDKeyboardDevice *psDevice)
+{
+ tHIDKeyboardInstance *psInst;
+ unsigned long ulLoop;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateHIDKbdData);
+ ASSERT(psDevice->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = psDevice->psPrivateHIDKbdData;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->ucUSBConfigured = 0;
+ psInst->ucProtocol = USB_HID_PROTOCOL_REPORT;
+ psInst->sReportIdle.ucDuration4mS = 125;
+ psInst->sReportIdle.ucReportID = 0;
+ psInst->sReportIdle.ulTimeSinceReportmS = 0;
+ psInst->sReportIdle.usTimeTillNextmS = 0;
+ psInst->ucLEDStates = 0;
+ psInst->ucKeyCount = 0;
+ for(ulLoop = 0; ulLoop < KEYB_MAX_CHARS_PER_REPORT; ulLoop++)
+ {
+ psInst->pucKeysPressed[ulLoop] = HID_KEYB_USAGE_RESERVED;
+ }
+
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_UNCONFIGURED;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->sHIDDevice;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->usPID = psDevice->usPID;
+ psHIDDevice->usVID = psDevice->usVID;
+ psHIDDevice->usMaxPowermA = psDevice->usMaxPowermA;
+ psHIDDevice->ucPwrAttributes = psDevice->ucPwrAttributes;
+ psHIDDevice->ucSubclass = USB_HID_SCLASS_BOOT;
+ psHIDDevice->ucProtocol = USB_HID_PROTOCOL_KEYB;
+ psHIDDevice->ucNumInputReports = 1;
+ psHIDDevice->psReportIdle = 0;
+ psHIDDevice->pfnRxCallback = HIDKeyboardRxHandler;
+ psHIDDevice->pvRxCBData = (void *)psDevice;
+ psHIDDevice->pfnTxCallback = HIDKeyboardTxHandler;
+ psHIDDevice->pvTxCBData = (void *)psDevice;
+ psHIDDevice->bUseOutEndpoint = false,
+ psHIDDevice->psHIDDescriptor = &g_sKeybHIDDescriptor;
+ psHIDDevice->ppClassDescriptors = g_pKeybClassDescriptors;
+ psHIDDevice->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psHIDDevice->ulNumStringDescriptors = psDevice->ulNumStringDescriptors;
+ psHIDDevice->psPrivateHIDData = &psInst->sHIDInstance;
+ 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(ulIndex, psHIDDevice));
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID keyboard device.
+//!
+//! \param pvInstance 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
+//! pvInstance instance may not me used in any other call to the HID keyboard
+//! device other than USBDHIDKeyboardInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDKeyboardTerm(void *pvInstance)
+{
+ tUSBDHIDKeyboardDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to the device.
+ //
+ psDevice = (tUSBDHIDKeyboardDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->sHIDDevice;
+
+ //
+ // Mark the device as no longer configured.
+ //
+ psDevice->psPrivateHIDKbdData->ucUSBConfigured = 0;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the keyboard callback.
+//!
+//! \param pvInstance 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 pvInstance structure passed to USBDHIDKeyboardInit() resides
+//! in RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was set for this
+//! instance.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardSetCBData(void *pvInstance, void *pvCBData)
+{
+ void *pvOldCBData;
+ tUSBDHIDKeyboardDevice *psKeyboard;
+
+ //
+ // Check for a NULL pointer in the device parameter.
+ //
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to our keyboard device.
+ //
+ psKeyboard = (tUSBDHIDKeyboardDevice *)pvInstance;
+
+ //
+ // 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 pvInstance is the pointer to the device instance structure as
+//! returned by USBDHIDKeyboardInit().
+//! \param ucModifiers 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 ucUsageCode 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 will contain the
+//! rollover error code, HID_KEYB_USAGE_ROLLOVER instead of key usage codes
+//! and the caller will receive return code 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.
+//
+//*****************************************************************************
+unsigned long
+USBDHIDKeyboardKeyStateChange(void *pvInstance, unsigned char ucModifiers,
+ unsigned char ucUsageCode, tBoolean bPress)
+{
+ tBoolean bRetcode;
+ unsigned long ulLoop;
+ unsigned long ulCount;
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ psDevice = (tUSBDHIDKeyboardDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->sHIDDevice;
+
+ //
+ // Assume all is well until we determine otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = psDevice->psPrivateHIDKbdData;
+
+ //
+ // Update the global keyboard report with the information passed.
+ //
+ psInst->pucReport[0] = ucModifiers;
+ psInst->pucReport[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(ucUsageCode != 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, ucUsageCode);
+ }
+ else
+ {
+ //
+ // A key has been released - remove it from the list.
+ //
+ bRetcode = RemoveKeyFromPressedList(psInst, ucUsageCode);
+
+ //
+ // 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(ulLoop = 0; ulLoop < KEYB_MAX_CHARS_PER_REPORT; ulLoop++)
+ {
+ psInst->pucReport[2 + ulLoop] = (bRetcode ?
+ psInst->pucKeysPressed[ulLoop] : HID_KEYB_USAGE_ROLLOVER);
+ }
+ }
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(!psInst->ucUSBConfigured)
+ {
+ 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;
+ ulCount = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pucReport, KEYB_IN_REPORT_SIZE,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(!ulCount)
+ {
+ //
+ // 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);
+}
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus or self powered) to the USB library.
+//!
+//! \param pvInstance is the pointer to the keyboard device instance structure.
+//! \param ucPower 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 *pvInstance, unsigned char ucPower)
+{
+ tUSBDHIDKeyboardDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psDevice = (tUSBDHIDKeyboardDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDHIDPowerStatusSet((void *)psHIDDevice, ucPower);
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvInstance 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 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.
+//
+//*****************************************************************************
+tBoolean
+USBDHIDKeyboardRemoteWakeupRequest(void *pvInstance)
+{
+ tUSBDHIDKeyboardDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psDevice = (tUSBDHIDKeyboardDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDKbdData->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..1f03332
--- /dev/null
+++ b/usblib/device/usbdhidkeyb.h
@@ -0,0 +1,382 @@
+//*****************************************************************************
+//
+// usbdhidkeyb.h - Definitions used by HID keyboard class devices.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris 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 will result 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.
+ //
+ unsigned char ucUSBConfigured;
+
+ //
+ // The protocol requested by the host, USB_HID_PROTOCOL_BOOT or
+ // USB_HID_PROTOCOL_REPORT.
+ //
+ unsigned char ucProtocol;
+
+ //
+ // The current states that the keyboard LEDs are to be set to.
+ //
+ volatile unsigned char ucLEDStates;
+
+ //
+ // The total number of keys currently pressed. This indicates the number
+ // of key press entries in the pucKeysPressed array.
+ //
+ unsigned char ucKeyCount;
+
+ //
+ // 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 tBoolean bChangeMade;
+
+ //
+ // A buffer used to receive output reports from the host.
+ //
+ unsigned char pucDataBuffer[KEYB_OUT_REPORT_SIZE];
+
+ //
+ // A buffer used to hold the last input report sent to the host.
+ //
+ unsigned char pucReport[KEYB_IN_REPORT_SIZE];
+
+ //
+ // A buffer containing the usage codes of all non-modifier keys currently
+ // in the pressed state.
+ //
+ unsigned char pucKeysPressed[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;
+
+ //
+ // The lower level HID driver's instance data.
+ //
+ tHIDInstance sHIDInstance;
+
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+}
+tHIDKeyboardInstance;
+
+#ifndef DEPRECATED
+//*****************************************************************************
+//
+// The number of bytes of workspace required by the HID keyboard driver.
+// The client must provide a block of RAM of at least this size in the
+// psPrivateHIDKbdData field of the tUSBHIDKeyboardDevice structure passed on
+// USBDHIDKeyboardInit().
+//
+// This value is deprecated and should not be used, any new code should just
+// pass in a psPrivateHIDKbdData structure in the psPrivateHIDKbdData field.
+//
+//*****************************************************************************
+#define USB_HID_KEYB_WORKSPACE_SIZE (sizeof(tHIDKeyboardInstance))
+#endif
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //! A pointer to the callback function which will be called to notify
+ //! the application of general events and those related to reception of
+ //! Output and Feature reports via the (optional) interrupt OUT endpoint.
+ //
+ tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which will be 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be (1 + (5 * (num languages))).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! A pointer to 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 *psPrivateHIDKbdData;
+}
+tUSBDHIDKeyboardDevice;
+
+//*****************************************************************************
+//
+// Keyboard-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the keyboard LED states are to be set. The
+//! ulMsgValue 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 HID_KEYB_NUM_LOCK,
+//! HID_KEYB_CAPS_LOCK, HID_KEYB_SCROLL_LOCK, HID_KEYB_COMPOSE and
+//! 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 will report 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 ucUsageCode 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 will be stored and passed to the host once configuration completes.
+//
+//*****************************************************************************
+#define KEYB_ERR_NOT_CONFIGURED 4
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDKeyboardInit(unsigned long ulIndex,
+ const tUSBDHIDKeyboardDevice *psDevice);
+extern void *USBDHIDKeyboardCompositeInit(unsigned long ulIndex,
+ const tUSBDHIDKeyboardDevice *psDevice);
+extern void USBDHIDKeyboardTerm(void *pvInstance);
+extern void *USBDHIDKeyboardSetCBData(void *pvInstance, void *pvCBData);
+extern unsigned long USBDHIDKeyboardKeyStateChange(void *pvInstance,
+ unsigned char ucModifiers,
+ unsigned char ucUsageCode,
+ tBoolean bPressed);
+extern void USBDHIDKeyboardPowerStatusSet(void *pvInstance,
+ unsigned char ucPower);
+extern tBoolean USBDHIDKeyboardRemoteWakeupRequest(void *pvInstance);
+
+//*****************************************************************************
+//
+// 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..ebf7a9f
--- /dev/null
+++ b/usblib/device/usbdhidmouse.c
@@ -0,0 +1,843 @@
+//*****************************************************************************
+//
+// usbdhidmouse.c - USB HID Mouse device class driver.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.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
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The report descriptor for the mouse class device.
+//
+//*****************************************************************************
+static const unsigned char g_pucMouseReportDescriptor[]=
+{
+ 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),
+
+ //
+ // 2 - 8 bit Values for x and y. // Padding
+ //
+ ReportSize(8),
+ ReportCount(MOUSE_REPORT_SIZE - 3),
+ Input(USB_HID_INPUT_CONSTANT | USB_HID_INPUT_ARRAY |
+ USB_HID_INPUT_ABS),
+
+ EndCollection,
+ EndCollection,
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the mouse class, we have only a single
+// report descriptor.
+//
+//*****************************************************************************
+static const unsigned char * const g_pMouseClassDescriptors[] =
+{
+ g_pucMouseReportDescriptor
+};
+
+//*****************************************************************************
+//
+// 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_pucMouseReportDescriptor) // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// Forward references for mouse device callback functions.
+//
+//*****************************************************************************
+static unsigned long HIDMouseRxHandler(void *pvCBData,
+ unsigned long ulEvent,
+ unsigned long ulMsgData,
+ void *pvMsgData);
+static unsigned long HIDMouseTxHandler(void *pvCBData,
+ unsigned long ulEvent,
+ unsigned long ulMsgData,
+ 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 pvCBData is the event callback pointer provided during USBDHIDInit().
+// This is a pointer to our HID device structure (&g_sHIDMouseDevice).
+// \param ulEvent identifies the event we are being called back for.
+// \param ulMsgData 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 unsigned long
+HIDMouseRxHandler(void *pvCBData, unsigned long ulEvent,
+ unsigned long ulMsgData, void *pvMsgData)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psDevice;
+
+ //
+ // Make sure we didn't get a NULL pointer.
+ //
+ ASSERT(pvCBData);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psDevice = (tUSBDHIDMouseDevice *)pvCBData;
+ psInst = psDevice->psPrivateHIDMouseData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ulEvent)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ psInst->ucUSBConfigured = true;
+
+ //
+ // Pass the information on to the client.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData, USB_EVENT_CONNECTED,
+ 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->ucUSBConfigured = false;
+
+ //
+ // Pass the information on to the client.
+ //
+ psDevice->pfnCallback(psDevice->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 ulMsgValue parameter in this case. Set the report pointer
+ // in *pvMsgData and return the length of the report in bytes.
+ //
+ *(unsigned char **)pvMsgData = psInst->pucReport;
+ 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->ucProtocol = ulMsgData;
+ 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->ucProtocol);
+ }
+
+ //
+ // Pass ERROR, SUSPEND and RESUME to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ {
+ return(psDevice->pfnCallback(psDevice->pvCBData, ulEvent,
+ ulMsgData, pvMsgData));
+ }
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// HID device class transmit channel event handler function.
+//
+// \param pvCBData is the event callback pointer provided during USBDHIDInit().
+// This is a pointer to our HID device structure (&g_sHIDMouseDevice).
+// \param ulEvent identifies the event we are being called back for.
+// \param ulMsgData 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 unsigned long
+HIDMouseTxHandler(void *pvCBData, unsigned long ulEvent,
+ unsigned long ulMsgData, void *pvMsgData)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psDevice;
+
+ //
+ // Make sure we didn't get a NULL pointer.
+ //
+ ASSERT(pvCBData);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psDevice = (tUSBDHIDMouseDevice *)pvCBData;
+ psInst = psDevice->psPrivateHIDMouseData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ulEvent)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // Our last transmission is complete.
+ //
+ psInst->eMouseState = HID_MOUSE_STATE_IDLE;
+
+ //
+ // Pass the event on to the client.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData, USB_EVENT_TX_COMPLETE,
+ ulMsgData, (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 ulIndex is the index of the USB controller which is to be
+//! initialized for HID mouse device operation.
+//! \param psDevice 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 will return the \e psDevice 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
+//! will receive \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 will cause unpredictable (though almost certainly unpleasant)
+//! behavior.
+//!
+//! \return Returns NULL on failure or the psDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseInit(unsigned long ulIndex, const tUSBDHIDMouseDevice *psDevice)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateHIDMouseData);
+ ASSERT(psDevice->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDMouseData->sHIDDevice;
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDMouseCompositeInit(ulIndex, psDevice);
+
+ //
+ // 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(ulIndex, psHIDDevice);
+
+ return((void *)psDevice);
+ }
+ else
+ {
+ return((void *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID mouse device operation for a given USB controller.
+//!
+//! \param ulIndex is the index of the USB controller which is to be
+//! initialized for HID mouse device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the HID mouse 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.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID Mouse APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseCompositeInit(unsigned long ulIndex,
+ const tUSBDHIDMouseDevice *psDevice)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateHIDMouseData);
+ ASSERT(psDevice->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = psDevice->psPrivateHIDMouseData;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDMouseData->sHIDDevice;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->ucUSBConfigured = 0;
+ psInst->ucProtocol = USB_HID_PROTOCOL_REPORT;
+ psInst->sReportIdle.ucDuration4mS = 0;
+ psInst->sReportIdle.ucReportID = 0;
+ psInst->sReportIdle.ulTimeSinceReportmS = 0;
+ psInst->sReportIdle.usTimeTillNextmS = 0;
+ psInst->eMouseState = HID_MOUSE_STATE_UNCONFIGURED;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->usPID = psDevice->usPID;
+ psHIDDevice->usVID = psDevice->usVID;
+ psHIDDevice->usMaxPowermA = psDevice->usMaxPowermA;
+ psHIDDevice->ucPwrAttributes = psDevice->ucPwrAttributes;
+ psHIDDevice->ucSubclass = USB_HID_SCLASS_BOOT;
+ psHIDDevice->ucProtocol = USB_HID_PROTOCOL_MOUSE;
+ psHIDDevice->ucNumInputReports = 1;
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+ psHIDDevice->pfnRxCallback = HIDMouseRxHandler;
+ psHIDDevice->pvRxCBData = (void *)psDevice;
+ psHIDDevice->pfnTxCallback = HIDMouseTxHandler;
+ psHIDDevice->pvTxCBData = (void *)psDevice;
+ psHIDDevice->bUseOutEndpoint = false;
+ psHIDDevice->psHIDDescriptor = &g_sMouseHIDDescriptor;
+ psHIDDevice->ppClassDescriptors= g_pMouseClassDescriptors;
+ psHIDDevice->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psHIDDevice->ulNumStringDescriptors = psDevice->ulNumStringDescriptors;
+ psHIDDevice->psPrivateHIDData = &psInst->sHIDInstance;
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a keyboard.
+ //
+ return(USBDHIDCompositeInit(ulIndex, psHIDDevice));
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID mouse device.
+//!
+//! \param pvInstance 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
+//! pvInstance instance may not me used in any other call to the HID mouse
+//! device other than USBDHIDMouseInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDMouseTerm(void *pvInstance)
+{
+ tUSBDHIDMouseDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to the device.
+ //
+ psDevice = (tUSBDHIDMouseDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDMouseData->sHIDDevice;
+
+ //
+ // Mark our device as no longer configured.
+ //
+ psDevice->psPrivateHIDMouseData->ucUSBConfigured = 0;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the mouse callback.
+//!
+//! \param pvInstance 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 pvInstance structure passed to USBDHIDMouseInit() resides
+//! in RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was set for this
+//! instance.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseSetCBData(void *pvInstance, void *pvCBData)
+{
+ void *pvOldCBData;
+ tUSBDHIDMouseDevice *psMouse;
+
+ //
+ // Check for a NULL pointer in the device parameter.
+ //
+ ASSERT(pvInstance);
+
+ //
+ // Get a pointer to our mouse device.
+ //
+ psMouse = (tUSBDHIDMouseDevice *)pvInstance;
+
+ //
+ // 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 pvInstance is the pointer to the mouse device instance structure.
+//! \param cDeltaX 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 cDeltaY 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 ucButtons is a bit mask indicating which (if any) of the three
+//! mouse buttons is pressed. Valid values are logical OR combinations of
+//! \e MOUSE_REPORT_BUTTON_1, \e MOUSE_REPORT_BUTTON_2 and \e
+//! 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 will be returned
+//! and the state change will be 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.
+//
+//*****************************************************************************
+unsigned long
+USBDHIDMouseStateChange(void *pvInstance, char cDeltaX, char cDeltaY,
+ unsigned char ucButtons)
+{
+ unsigned long ulRetcode;
+ unsigned long ulCount;
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Get a pointer to the device.
+ //
+ psDevice = (tUSBDHIDMouseDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDMouseData->sHIDDevice;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = psDevice->psPrivateHIDMouseData;
+
+ //
+ // Update the global mouse report with the information passed.
+ //
+ psInst->pucReport[HID_REPORT_BUTTONS] = ucButtons;
+ psInst->pucReport[HID_REPORT_X] = (unsigned char)cDeltaX;
+ psInst->pucReport[HID_REPORT_Y] = (unsigned char)cDeltaY;
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(!psInst->ucUSBConfigured)
+ {
+ 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->eMouseState = HID_MOUSE_STATE_SEND;
+ ulCount = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pucReport, MOUSE_REPORT_SIZE,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(!ulCount)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ ulRetcode = MOUSE_ERR_TX_ERROR;
+ }
+ else
+ {
+ ulRetcode = MOUSE_SUCCESS;
+ }
+ }
+ else
+ {
+ ulRetcode = MOUSE_ERR_TX_ERROR;
+ }
+ //
+ // Return the relevant error code to the caller.
+ //
+ return(ulRetcode);
+}
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvInstance is the pointer to the mouse device instance structure.
+//! \param ucPower 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 *pvInstance, unsigned char ucPower)
+{
+ tUSBDHIDMouseDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psDevice = (tUSBDHIDMouseDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDMouseData->sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDHIDPowerStatusSet((void *)psHIDDevice, ucPower);
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvInstance 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 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.
+//
+//*****************************************************************************
+tBoolean
+USBDHIDMouseRemoteWakeupRequest(void *pvInstance)
+{
+ tUSBDHIDMouseDevice *psDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvInstance);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psDevice = (tUSBDHIDMouseDevice *)pvInstance;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psDevice->psPrivateHIDMouseData->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..8ca80e6
--- /dev/null
+++ b/usblib/device/usbdhidmouse.h
@@ -0,0 +1,321 @@
+//*****************************************************************************
+//
+// usbdhidmouse.h - Public header file for the USB HID Mouse device class
+// driver
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris 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.
+ //
+ HID_MOUSE_STATE_UNCONFIGURED,
+
+ //
+ // No keys to send and not waiting on data.
+ //
+ HID_MOUSE_STATE_IDLE,
+
+ //
+ // Waiting on report data from the host.
+ //
+ HID_MOUSE_STATE_WAIT_DATA,
+
+ //
+ // Waiting on data to be sent out.
+ //
+ HID_MOUSE_STATE_SEND
+}
+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.
+ //
+ unsigned char ucUSBConfigured;
+
+ //
+ // The protocol requested by the host, USB_HID_PROTOCOL_BOOT or
+ // USB_HID_PROTOCOL_REPORT.
+ //
+ unsigned char ucProtocol;
+
+ //
+ // A buffer used to hold the last input report sent to the host.
+ //
+ unsigned char pucReport[MOUSE_REPORT_SIZE];
+
+ //
+ // The current state of the mouse interrupt IN endpoint.
+ //
+ volatile tMouseState eMouseState;
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+
+ //
+ // The lower level HID driver's instance data.
+ //
+ tHIDInstance sHIDInstance;
+
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+}
+tHIDMouseInstance;
+
+#ifdef DEPRECATED
+//*****************************************************************************
+//
+// The number of bytes of workspace required by the HID mouse driver.
+// The client must provide a block of RAM of at least this size in the
+// tHIDMouseInstance field of the tUSBHIDMouseDevice structure passed on
+// USBDHIDMouseInit(). The HID mouse driver needs space for the generic HID
+// interface + the Mouse Report Buffer + HID mouse interface.
+//
+// This value is deprecated and should not be used, any new code should just
+// pass in a tHIDMouseInstance structure in the psPrivateHIDMouseData field.
+//
+//*****************************************************************************
+#define USB_HID_MOUSE_WORKSPACE_SIZE \
+ (sizeof(tHIDMouseInstance))
+#endif
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the mouse.
+ //
+ tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which will be 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be (1 + (5 * (num languages))).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! A pointer to 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 *psPrivateHIDMouseData;
+}
+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 will have been ignored.
+//
+//*****************************************************************************
+#define MOUSE_ERR_NOT_CONFIGURED \
+ 4
+
+//*****************************************************************************
+//
+//! Setting this bit in the ucButtons 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 ucButtons 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 ucButtons 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(unsigned long ulIndex,
+ const tUSBDHIDMouseDevice *psDevice);
+extern void *USBDHIDMouseCompositeInit(unsigned long ulIndex,
+ const tUSBDHIDMouseDevice *psDevice);
+extern void USBDHIDMouseTerm(void *pvInstance);
+extern void *USBDHIDMouseSetCBData(void *pvInstance, void *pvCBData);
+extern unsigned long USBDHIDMouseStateChange(void *pvInstance, char cDeltaX,
+ char cDeltaY,
+ unsigned char ucButtons);
+extern void USBDHIDMousePowerStatusSet(void *pvInstance,
+ unsigned char ucPower);
+extern tBoolean USBDHIDMouseRemoteWakeupRequest(void *pvInstance);
+
+//*****************************************************************************
+//
+// 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..e563423
--- /dev/null
+++ b/usblib/device/usbdmsc.c
@@ -0,0 +1,2130 @@
+//*****************************************************************************
+//
+// usbdmsc.c - USB mass storage device class driver.
+//
+// Copyright (c) 2009-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#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 "driverlib/udma.h"
+#include "usblib/usblib.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 ulFlags member variable.
+//
+//*****************************************************************************
+#define USBD_FLAG_DMA_IN 0x00000001
+#define USBD_FLAG_DMA_OUT 0x00000002
+
+//*****************************************************************************
+//
+// 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_IN_DMA_CHANNEL UDMA_CHANNEL_USBEP1TX
+#define DATA_OUT_ENDPOINT USB_EP_1
+#define DATA_OUT_DMA_CHANNEL UDMA_CHANNEL_USBEP1RX
+
+//*****************************************************************************
+//
+// 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 sizes of USB transfers for data and commands.
+//
+//*****************************************************************************
+#define MAX_TRANSFER_SIZE 512
+#define COMMAND_BUFFER_SIZE 64
+
+//*****************************************************************************
+//
+// The local buffer used to read in commands and process them.
+//
+//*****************************************************************************
+static unsigned char g_pucCommand[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.ucSCSIState 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 unsigned char g_pMSCDeviceDescriptor[] =
+{
+ 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 unsigned char g_pMSCDescriptor[] =
+{
+ //
+ // 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 unsigned char g_pMSCInterface[] =
+{
+ //
+ // 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 | USB_EP_TO_INDEX(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 | USB_EP_TO_INDEX(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_pMSCDescriptor),
+ g_pMSCDescriptor
+};
+
+const tConfigSection g_sMSCInterfaceSection =
+{
+ sizeof(g_pMSCInterface),
+ g_pMSCInterface
+};
+
+//*****************************************************************************
+//
+// 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(tConfigSection *))
+
+//*****************************************************************************
+//
+// 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_pMSCConfigDescriptors[] =
+{
+ &g_sMSCConfigHeader
+};
+
+//*****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//*****************************************************************************
+static void HandleDisconnect(void *pvInstance);
+static void ConfigChangeHandler(void *pvInstance, unsigned long ulValue);
+static void HandleEndpoints(void *pvInstance, unsigned long ulStatus);
+static void HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest);
+static void USBDSCSISendStatus(const tUSBDMSCDevice *psDevice);
+unsigned long USBDSCSICommand(const tUSBDMSCDevice *psDevice,
+ tMSCCBW *pSCSICBW);
+static void HandleDevice(void *pvInstance, unsigned long ulRequest,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The FIFO configuration for USB mass storage class device.
+//
+//*****************************************************************************
+const tFIFOConfig g_sUSBMSCFIFOConfig =
+{
+ //
+ // IN endpoints.
+ //
+ {
+ { false, USB_EP_DEV_IN | USB_EP_DMA_MODE_1 | USB_EP_AUTO_SET },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN },
+ { false, USB_EP_DEV_IN }
+ },
+
+ //
+ // OUT endpoints.
+ //
+ {
+ { false, USB_EP_DEV_OUT | USB_EP_DMA_MODE_1 | USB_EP_AUTO_CLEAR },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT },
+ { false, USB_EP_DEV_OUT }
+ },
+};
+
+//*****************************************************************************
+//
+// The device information structure for the USB MSC device.
+//
+//*****************************************************************************
+tDeviceInfo g_sMSCDeviceInfo =
+{
+ //
+ // Device event handler callbacks.
+ //
+ {
+ //
+ // 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
+ },
+ g_pMSCDeviceDescriptor,
+ g_pMSCConfigDescriptors,
+ 0,
+ 0,
+ &g_sUSBMSCFIFOConfig
+};
+
+//*****************************************************************************
+//
+//! This function is used by an application if it can detect insertion or
+//! removal of the media.
+//!
+//! \param pvInstance is the mass storage device instance that had a media
+//! change.
+//! \param eMediaStatus 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 eMediaStatus 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 eMediaStatus
+//! parameter:
+//! - USBDMSC_MEDIA_PRESENT indicates that the media is present or has been
+//! added.
+//! - USBDMSC_MEDIA_NOTPRESENT indicates that the media is not present or was
+//! removed.
+//! - USBDMSC_MEDIA_UNKNOWN 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 USBDMSC_MEDIA_UNKNOWN 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 *pvInstance, tUSBDMSCMediaStatus eMediaStatus)
+{
+ const tUSBDMSCDevice *psDevice;
+
+ //
+ // Create a device instance pointer.
+ //
+ psDevice = pvInstance;
+
+ //
+ // Save the current media status.
+ //
+ psDevice->psPrivateData->eMediaStatus = eMediaStatus;
+}
+
+//*****************************************************************************
+//
+// This function is called to handle the interrupts on the Bulk endpoints for
+// the mass storage class.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvInstance, unsigned long ulStatus)
+{
+ const tUSBDMSCDevice *psDevice;
+ tMSCInstance *psInst;
+ tMSCCBW *pSCSICBW;
+ unsigned long ulEPStatus;
+ unsigned long ulSize;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ulIndex is different in both cases.
+ //
+ psDevice = pvInstance;
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Get the endpoints status.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ucOUTEndpoint);
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if((ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucINEndpoint))) ||
+ ((psInst->ulFlags & USBD_FLAG_DMA_IN) &&
+ (MAP_uDMAChannelModeGet(psInst->ucINDMA) == UDMA_MODE_STOP)))
+ {
+ switch(psInst->ucSCSIState)
+ {
+ //
+ // 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->ulBytesToTransfer -= MAX_TRANSFER_SIZE;
+
+ //
+ // If we are done then move on to the status phase.
+ //
+ if(psInst->ulBytesToTransfer == 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->ulFlags &= ~USBD_FLAG_DMA_IN;
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, psInst->ucINEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Send back the status once this transfer is complete.
+ //
+ psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
+
+ if(psDevice->pfnEventCallback)
+ {
+ psDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE, 0,
+ 0);
+ }
+
+ //
+ // The transfer is complete so don't read anymore data.
+ //
+ break;
+ }
+
+ //
+ // Move on to the next Logical Block.
+ //
+ psInst->ulCurrentLBA++;
+
+ //
+ // Read the new data and send it out.
+ //
+ if(psDevice->sMediaFunctions.BlockRead(psInst->pvMedia,
+ (unsigned char *)psInst->pulBuffer,
+ psInst->ulCurrentLBA, 1) == 0)
+ {
+ }
+
+ //
+ // Reset the DMA transfer and enable the DMA channel.
+ //
+ MAP_uDMAChannelTransferSet(psInst->ucINDMA,
+ UDMA_MODE_BASIC,
+ psInst->pulBuffer,
+ (void *)USBFIFOAddrGet(USB0_BASE,
+ psInst->ucINEndpoint),
+ (MAX_TRANSFER_SIZE >> 2));
+ MAP_uDMAChannelEnable(psInst->ucINDMA);
+
+ break;
+ }
+
+ //
+ // Handle sending status.
+ //
+ case STATE_SCSI_SEND_STATUS:
+ {
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psDevice);
+
+ break;
+ }
+
+ //
+ // Handle completing sending status.
+ //
+ case STATE_SCSI_SENT_STATUS:
+ {
+ psInst->ucSCSIState = 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((ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucOUTEndpoint))) ||
+ ((psInst->ulFlags & USBD_FLAG_DMA_OUT) &&
+ (MAP_uDMAChannelModeGet(psInst->ucOUTDMA) == UDMA_MODE_STOP)))
+ {
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ulEPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ucOUTEndpoint);
+
+ switch(psInst->ucSCSIState)
+ {
+ //
+ // Receiving and writing bytes to the storage device.
+ //
+ case STATE_SCSI_RECEIVE_BLOCKS:
+ {
+ //
+ // Update the current status for the buffer.
+ //
+ psInst->ulBytesToTransfer -= MAX_TRANSFER_SIZE;
+
+ //
+ // Write the new data.
+ //
+ psDevice->sMediaFunctions.BlockWrite(psInst->pvMedia,
+ (unsigned char *)psInst->pulBuffer,
+ psInst->ulCurrentLBA, 1);
+
+ //
+ // Move on to the next Logical Block.
+ //
+ psInst->ulCurrentLBA++;
+
+ //
+ // Check if all bytes have been received.
+ //
+ if(psInst->ulBytesToTransfer == 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->ulFlags &= ~USBD_FLAG_DMA_OUT;
+
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psDevice);
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, psInst->ucOUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // If there is an event callback then call it to notify
+ // that last operation has completed.
+ //
+ if(psDevice->pfnEventCallback)
+ {
+ psDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE, 0,
+ 0);
+ }
+ }
+ else
+ {
+ //
+ // Configure and enable DMA for the OUT transfer.
+ //
+ MAP_uDMAChannelTransferSet(psInst->ucOUTDMA,
+ UDMA_MODE_BASIC,
+ (void *)USBFIFOAddrGet(USB0_BASE,
+ psInst->ucOUTEndpoint),
+ psInst->pulBuffer,
+ (MAX_TRANSFER_SIZE >> 2));
+
+ //
+ // Start the DMA transfer.
+ //
+ MAP_uDMAChannelEnable(psInst->ucOUTDMA);
+ }
+
+ 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.
+ //
+ ulSize = COMMAND_BUFFER_SIZE;
+ MAP_USBEndpointDataGet(psInst->ulUSBBase, psInst->ucOUTEndpoint,
+ g_pucCommand, &ulSize);
+ pSCSICBW = (tMSCCBW *)g_pucCommand;
+
+ //
+ // Acknowledge the OUT data packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ulUSBBase,
+ psInst->ucOUTEndpoint,
+ false);
+
+ //
+ // If this is a valid CBW then handle it.
+ //
+ if(pSCSICBW->dCBWSignature == CBW_SIGNATURE)
+ {
+ g_sSCSICSW.dCSWSignature = CSW_SIGNATURE;
+ g_sSCSICSW.dCSWTag = pSCSICBW->dCBWTag;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ g_sSCSICSW.bCSWStatus = 0;
+
+ USBDSCSICommand(psDevice, pSCSICBW);
+ }
+ 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->ucSCSIState = STATE_SCSI_IDLE;
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ucOUTEndpoint,
+ ulEPStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvInstance, unsigned long ulRequest, void *pvRequestData)
+{
+ tMSCInstance *psInst;
+ unsigned char *pucData;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = ((tUSBDMSCDevice *)pvInstance)->psPrivateData;
+
+ //
+ // Create the char array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pucData = (unsigned char *)pvRequestData;
+
+ switch(ulRequest)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ucInterface = pucData[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(pucData[0] & USB_EP_DESC_IN)
+ {
+ psInst->ucINEndpoint = INDEX_TO_USB_EP((pucData[1] & 0x7f));
+
+ psInst->ucINDMA = UDMA_CHANNEL_USBEP1TX +
+ (((pucData[1] & 0x7f) - 1) * 2);
+
+ //
+ // Basic configuration for DMA on the IN endpoint.
+ //
+ MAP_uDMAChannelControlSet(psInst->ucINDMA,
+ (UDMA_SIZE_32 | UDMA_SRC_INC_32|
+ UDMA_DST_INC_NONE | UDMA_ARB_16));
+
+ //
+ // Select this channel for this endpoint, this only affects
+ // devices that have this feature.
+ //
+ MAP_USBEndpointDMAChannel(USB0_BASE, psInst->ucINEndpoint,
+ psInst->ucINDMA);
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ucOUTEndpoint = INDEX_TO_USB_EP(pucData[1] & 0x7f);
+ psInst->ucOUTDMA = UDMA_CHANNEL_USBEP1RX +
+ (((pucData[1] & 0x7f) - 1) * 2);
+
+ //
+ // Basic configuration for DMA on the OUT endpoint.
+ //
+ MAP_uDMAChannelControlSet(psInst->ucOUTDMA,
+ (UDMA_SIZE_32 | UDMA_SRC_INC_NONE|
+ UDMA_DST_INC_32 | UDMA_ARB_16));
+
+ //
+ // Select this channel for this endpoint, this only affects
+ // devices that have this feature.
+ //
+ MAP_USBEndpointDMAChannel(USB0_BASE, psInst->ucOUTEndpoint,
+ psInst->ucOUTDMA);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvInstance)
+{
+ const tUSBDMSCDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDMSCDevice *)pvInstance;
+
+ //
+ // Close the drive requested.
+ //
+ if(psDevice->psPrivateData->pvMedia != 0)
+ {
+ psDevice->psPrivateData->pvMedia = 0;
+ psDevice->sMediaFunctions.Close(0);
+ }
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psDevice->pfnEventCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psDevice->pfnEventCallback(pvInstance, USB_EVENT_DISCONNECTED, 0, 0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes.
+//
+//*****************************************************************************
+static void
+ConfigChangeHandler(void *pvInstance, unsigned long ulValue)
+{
+ tMSCInstance *psInst;
+ const tUSBDMSCDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psDevice = (const tUSBDMSCDevice *)pvInstance;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Insure that DMA is disable whenever the configuration is set.
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, psInst->ucINEndpoint, USB_EP_DEV_IN);
+ MAP_USBEndpointDMADisable(USB0_BASE, psInst->ucOUTEndpoint, USB_EP_DEV_OUT);
+
+ //
+ // Basic configuration for DMA on the OUT endpoint.
+ //
+ MAP_uDMAChannelControlSet(psInst->ucOUTDMA, UDMA_SIZE_32 |
+ UDMA_SRC_INC_NONE|
+ UDMA_DST_INC_32 |
+ UDMA_ARB_16);
+
+ //
+ // Select this channel for this endpoint, this only affects devices that
+ // have this feature.
+ //
+ MAP_USBEndpointDMAChannel(USB0_BASE, psInst->ucOUTEndpoint, psInst->ucOUTDMA);
+
+ //
+ // Basic configuration for DMA on the IN endpoint.
+ //
+ MAP_uDMAChannelControlSet(psInst->ucINDMA, UDMA_SIZE_32 | UDMA_SRC_INC_32|
+ UDMA_DST_INC_NONE | UDMA_ARB_16);
+
+ //
+ // Select this channel for this endpoint, this only affects devices that
+ // have this feature.
+ //
+ MAP_USBEndpointDMAChannel(USB0_BASE, psInst->ucINEndpoint, psInst->ucINDMA);
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psDevice->pfnEventCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psDevice->pfnEventCallback(pvInstance, 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 ulIndex is the index of the USB controller to initialize for
+//! mass storage class device operation.
+//! \param psDevice 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 psDevice 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(unsigned long ulIndex, const tUSBDMSCDevice *psDevice)
+{
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateData);
+
+ USBDMSCCompositeInit(ulIndex, psDevice);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ulIndex, psDevice->psPrivateData->psDevInfo);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the mass storage class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ulIndex is the index of the USB controller to initialize for
+//! mass storage class device operation.
+//! \param psDevice 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 psDevice 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 *
+USBDMSCCompositeInit(unsigned long ulIndex, const tUSBDMSCDevice *psDevice)
+{
+ tMSCInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ulIndex == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppStringDescriptors);
+ ASSERT(psDevice->psPrivateData);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = psDevice->psPrivateData;
+ psInst->psConfDescriptor = (tConfigDescriptor *)g_pMSCDescriptor;
+ psInst->psDevInfo = &g_sMSCDeviceInfo;
+ psInst->ulUSBBase = USB0_BASE;
+ psInst->bConnected = false;
+ psInst->eMediaStatus = USBDMSC_MEDIA_UNKNOWN;
+
+ //
+ // Set the initial interface and endpoints.
+ //
+ psInst->ucInterface = 0;
+ psInst->ucOUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ucOUTDMA = DATA_OUT_DMA_CHANNEL;
+ psInst->ucINEndpoint = DATA_IN_ENDPOINT;
+ psInst->ucINDMA = DATA_IN_DMA_CHANNEL;
+
+ //
+ // Set the initial SCSI state to idle.
+ //
+ psInst->ucSCSIState = STATE_SCSI_IDLE;
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
+ psDevDesc->idVendor = psDevice->usVID;
+ psDevDesc->idProduct = psDevice->usPID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
+ psInst->psConfDescriptor->bMaxPower =
+ (unsigned char)(psDevice->usMaxPowermA / 2);
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
+ psInst->psDevInfo->ulNumStringDescriptors
+ = psDevice->ulNumStringDescriptors;
+ psInst->psDevInfo->pvInstance = (void *)psDevice;
+
+ //
+ // If DMA is in use then clear all DMA attributes.
+ //
+ MAP_uDMAChannelAttributeDisable(psInst->ucINDMA, UDMA_ATTR_ALL);
+ MAP_uDMAChannelAttributeDisable(psInst->ucOUTDMA, UDMA_ATTR_ALL);
+
+ //
+ // Open the drive requested.
+ //
+ psInst->pvMedia = psDevice->sMediaFunctions.Open(0);
+
+ if(psInst->pvMedia == 0)
+ {
+ //
+ // There is no media currently present.
+ //
+ psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+ else
+ {
+ //
+ // Media is now ready for use.
+ //
+ psInst->ucSenseKey = SCSI_RS_KEY_UNIT_ATTN;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOTRDY2RDY;
+ }
+
+ //
+ // Enable Clocking to the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the mass storage device.
+//!
+//! \param pvInstance is the pointer to the device instance structure as
+//! returned by USBDMSCInit() or USBDMSCInitComposite().
+//!
+//! This function terminates mass storage operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e psDevice instance may not me used in any other call to the mass storage
+//! device other than USBDMSCInit() or USBDMSCInitComposite().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDMSCTerm(void *pvInstance)
+{
+ const tUSBDMSCDevice *psDevice;
+
+ ASSERT(pvInstance != 0);
+
+ //
+ // Cleanly exit device mode.
+ //
+ USBDCDTerm(0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psDevice = pvInstance;
+
+ //
+ // If the media was opened the close it out.
+ //
+ if(psDevice->psPrivateData->pvMedia != 0)
+ {
+ psDevice->psPrivateData->pvMedia = 0;
+ psDevice->sMediaFunctions.Close(0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvInstance 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 *pvInstance, tUSBRequest *pUSBRequest)
+{
+ //
+ // This class only support a single LUN.
+ //
+ const static unsigned char ucMaxLun = 0;
+
+ ASSERT(pvInstance != 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:
+ {
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (unsigned char *)&ucMaxLun, 1);
+
+ 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(const tUSBDMSCDevice *psDevice)
+{
+ long lIdx;
+ tMSCInstance *psInst;
+ unsigned long *pulData;
+
+ //
+ // Create a local unsigned long pointer to the command.
+ //
+ pulData = (unsigned long *)g_pucCommand;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Direct Access device, Removable storage and SCSI 1 responses.
+ //
+ pulData[0] = SCSI_INQ_PDT_SBC | (SCSI_INQ_RMB << 8);
+
+ //
+ // Additional Length is fixed at 31 bytes.
+ //
+ pulData[1] = 31;
+
+ //
+ // Copy the Vendor string.
+ //
+ for(lIdx = 0; lIdx < 8; lIdx++)
+ {
+ g_pucCommand[lIdx + 8] = psDevice->pucVendor[lIdx];
+ }
+
+ //
+ // Copy the Product string.
+ //
+ for(lIdx = 0; lIdx < 16; lIdx++)
+ {
+ g_pucCommand[lIdx + 16] = psDevice->pucProduct[lIdx];
+ }
+
+ //
+ // Copy the Version string.
+ //
+ for(lIdx = 0; lIdx < 4; lIdx++)
+ {
+ g_pucCommand[lIdx + 32] = psDevice->pucVersion[lIdx];
+ }
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ucINEndpoint, g_pucCommand, 36);
+
+ //
+ // Send the data to the host.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ucINEndpoint, 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->ucSCSIState = 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(const tUSBDMSCDevice *psDevice)
+{
+ unsigned long ulBlocks;
+ tMSCInstance *psInst;
+ unsigned long *pulData;
+
+ //
+ // Create a local unsigned long pointer to the command.
+ //
+ pulData = (unsigned long *)g_pucCommand;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ if(psInst->pvMedia != 0)
+ {
+ ulBlocks = psDevice->sMediaFunctions.NumBlocks(psInst->pvMedia);
+
+ pulData[0] = 0x08000000;
+
+ //
+ // Fill in the number of blocks, the bytes endianness must be changed.
+ //
+ g_pucCommand[4] = ulBlocks >> 24;
+ g_pucCommand[5] = 0xff & (ulBlocks >> 16);
+ g_pucCommand[6] = 0xff & (ulBlocks >> 8);
+ g_pucCommand[7] = 0xff & (ulBlocks);
+
+ //
+ // Current media capacity
+ //
+ g_pucCommand[8] = 0x2;
+
+ //
+ // Fill in the block size, which is fixed at DEVICE_BLOCK_SIZE.
+ //
+ g_pucCommand[9] = 0xff & (DEVICE_BLOCK_SIZE >> 16);
+ g_pucCommand[10] = 0xff & (DEVICE_BLOCK_SIZE >> 8);
+ g_pucCommand[11] = 0xff & DEVICE_BLOCK_SIZE;
+
+ //
+ // Send out the 12 bytes that are in this response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ucINEndpoint, g_pucCommand,
+ 12);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ucINEndpoint, 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->ucINEndpoint, USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ucSCSIState = 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(const tUSBDMSCDevice *psDevice)
+{
+ unsigned long ulBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ ulBlocks = psDevice->sMediaFunctions.NumBlocks(psInst->pvMedia);
+
+ //
+ // Only decrement if any blocks were found.
+ //
+ if(ulBlocks != 0)
+ {
+ //
+ // One less than the maximum number is the last addressable
+ // block.
+ //
+ ulBlocks--;
+ }
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Fill in the number of blocks, the bytes endianness must be changed.
+ //
+ g_pucCommand[0] = 0xff & (ulBlocks >> 24);
+ g_pucCommand[1] = 0xff & (ulBlocks >> 16);
+ g_pucCommand[2] = 0xff & (ulBlocks >> 8);
+ g_pucCommand[3] = 0xff & (ulBlocks);
+
+ g_pucCommand[4] = 0;
+
+ //
+ // Fill in the block size, which is fixed at DEVICE_BLOCK_SIZE.
+ //
+ g_pucCommand[5] = 0xff & (DEVICE_BLOCK_SIZE >> 16);
+ g_pucCommand[6] = 0xff & (DEVICE_BLOCK_SIZE >> 8);
+ g_pucCommand[7] = 0xff & DEVICE_BLOCK_SIZE;
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ucINEndpoint, g_pucCommand,
+ 8);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ucINEndpoint, 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->ucINEndpoint, USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ucSCSIState = 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(const tUSBDMSCDevice *psDevice)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // The request sense response.
+ //
+ g_pucCommand[0] = psInst->ucErrorCode;
+ g_pucCommand[1] = 0;
+ g_pucCommand[2] = psInst->ucSenseKey;
+ *(unsigned long *)&g_pucCommand[3] = 0;
+
+ //
+ // There are 10 more bytes of data.
+ //
+ g_pucCommand[7] = 10;
+
+ *(unsigned long *)&g_pucCommand[8] = 0;
+
+ //
+ // Transition from not ready to ready.
+ //
+ *(unsigned short *)&g_pucCommand[12] = psInst->usAddSenseCode;
+ *(unsigned long *)&g_pucCommand[14] = 0;
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ucINEndpoint, g_pucCommand, 18);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ucINEndpoint, USB_TRANS_IN);
+
+ //
+ // Reset the valid flag on errors.
+ //
+ psInst->ucErrorCode = 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->ucSCSIState = 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(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW)
+{
+ unsigned short usNumBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Default the number of blocks.
+ //
+ usNumBlocks = 0;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Get the logical block from the CBW structure. This switching
+ // is required to convert from big to little endian.
+ //
+ psInst->ulCurrentLBA = (pSCSICBW->CBWCB[2] << 24) |
+ (pSCSICBW->CBWCB[3] << 16) |
+ (pSCSICBW->CBWCB[4] << 8) |
+ (pSCSICBW->CBWCB[5] << 0);
+
+ //
+ // More bytes to read.
+ //
+ usNumBlocks = (pSCSICBW->CBWCB[7] << 8) | pSCSICBW->CBWCB[8];
+
+ //
+ // Read the next logical block from the storage device.
+ //
+ if(psDevice->sMediaFunctions.BlockRead(psInst->pvMedia,
+ (unsigned char *)psInst->pulBuffer,
+ psInst->ulCurrentLBA, 1) == 0)
+ {
+ psInst->pvMedia = 0;
+ psDevice->sMediaFunctions.Close(0);
+ }
+ }
+
+ //
+ // If there is media present then start transferring the data.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Enable DMA on the endpoint
+ //
+ MAP_USBEndpointDMAEnable(USB0_BASE, psInst->ucINEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Configure and DMA for the IN transfer.
+ //
+ MAP_uDMAChannelTransferSet(psInst->ucINDMA,
+ UDMA_MODE_BASIC,
+ psInst->pulBuffer,
+ (void *)USBFIFOAddrGet(USB0_BASE,
+ psInst->ucINEndpoint),
+ (MAX_TRANSFER_SIZE >> 2));
+
+ //
+ // Remember that a DMA is in progress.
+ //
+ psInst->ulFlags |= USBD_FLAG_DMA_IN;
+
+ //
+ // Schedule the remaining bytes to send.
+ //
+ psInst->ulBytesToTransfer = (DEVICE_BLOCK_SIZE * usNumBlocks);
+
+ //
+ // Start the DMA transfer.
+ //
+ MAP_uDMAChannelEnable(psInst->ucINDMA);
+
+ //
+ // Move on and start sending blocks.
+ //
+ psInst->ucSCSIState = STATE_SCSI_SEND_BLOCKS;
+
+ if(psDevice->pfnEventCallback)
+ {
+ psDevice->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->ucINEndpoint, USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+
+ psInst->ucSCSIState = 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(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW)
+{
+ unsigned short usNumBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // 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->ulCurrentLBA = (pSCSICBW->CBWCB[2] << 24) |
+ (pSCSICBW->CBWCB[3] << 16) |
+ (pSCSICBW->CBWCB[4] << 8) |
+ (pSCSICBW->CBWCB[5] << 0);
+
+ //
+ // More bytes to read.
+ //
+ usNumBlocks = (pSCSICBW->CBWCB[7] << 8) | pSCSICBW->CBWCB[8];
+
+ psInst->ulBytesToTransfer = DEVICE_BLOCK_SIZE * usNumBlocks;
+
+ //
+ // Start sending logical blocks, these are always multiples of
+ // DEVICE_BLOCK_SIZE bytes.
+ //
+ psInst->ucSCSIState = STATE_SCSI_RECEIVE_BLOCKS;
+
+ //
+ // Enable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMAEnable(USB0_BASE, psInst->ucOUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // Configure the DMA for the OUT transfer.
+ //
+ MAP_uDMAChannelTransferSet(psInst->ucOUTDMA,
+ UDMA_MODE_BASIC,
+ (void *)USBFIFOAddrGet(USB0_BASE,
+ psInst->ucOUTEndpoint),
+ psInst->pulBuffer,
+ (MAX_TRANSFER_SIZE >> 2));
+
+ //
+ // Remember that a DMA is in progress.
+ //
+ psInst->ulFlags |= USBD_FLAG_DMA_OUT;
+
+ //
+ // Enable the OUT DMA transfer.
+ //
+ MAP_uDMAChannelEnable(psInst->ucOUTDMA);
+
+ //
+ // Notify the application of the write event.
+ //
+ if(psDevice->pfnEventCallback)
+ {
+ psDevice->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->ucOUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+
+ psInst->ucSCSIState = 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(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Three extra bytes in this response.
+ //
+ g_pucCommand[0] = 3;
+ g_pucCommand[1] = 0;
+ g_pucCommand[2] = 0;
+ g_pucCommand[3] = 0;
+
+ //
+ // Manually send the response back to the host.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ucINEndpoint, g_pucCommand,
+ 4);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ucINEndpoint, 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 = pSCSICBW->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->ucINEndpoint, USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ucSCSIState = 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(const tUSBDMSCDevice *psDevice)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Respond with the requested status.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ucINEndpoint,
+ (unsigned char *)&g_sSCSICSW, 13);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ucINEndpoint, USB_TRANS_IN);
+
+ //
+ // Move the state to status sent so that the next interrupt will move the
+ // statue to idle.
+ //
+ psInst->ucSCSIState = STATE_SCSI_SENT_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle all SCSI commands.
+//
+//*****************************************************************************
+unsigned long
+USBDSCSICommand(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW)
+{
+ unsigned long ulRetCode;
+ unsigned long ulTransferLength;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = psDevice->psPrivateData;
+
+ //
+ // Initialize the return code.
+ //
+ ulRetCode = 1;
+
+ //
+ // Save the transfer length because it may be overwritten by some calls.
+ //
+ ulTransferLength = pSCSICBW->dCBWDataTransferLength;
+
+ switch(pSCSICBW->CBWCB[0])
+ {
+ //
+ // Respond to the SCSI Inquiry command.
+ //
+ case SCSI_INQUIRY_CMD:
+ {
+ USBDSCSIInquiry(psDevice);
+
+ 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
+ {
+ //
+ // Since there was no media, check for media here.
+ //
+ psInst->pvMedia = psDevice->sMediaFunctions.Open(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(psDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Read Capacity command.
+ //
+ case SCSI_READ_CAPACITY:
+ {
+ USBDSCSIReadCapacity(psDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Request Sense command.
+ //
+ case SCSI_REQUEST_SENSE:
+ {
+ USBDSCSIRequestSense(psDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Read 10 command.
+ //
+ case SCSI_READ_10:
+ {
+ USBDSCSIRead10(psDevice, pSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Write 10 command.
+ //
+ case SCSI_WRITE_10:
+ {
+ USBDSCSIWrite10(psDevice, pSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Mode Sense 6 command.
+ //
+ case SCSI_MODE_SENSE_6:
+ {
+ USBDSCSIModeSense6(psDevice, pSCSICBW);
+
+ 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 = pSCSICBW->dCBWDataTransferLength;
+
+ //
+ // If there is data then there is more work to do.
+ //
+ if(pSCSICBW->dCBWDataTransferLength != 0)
+ {
+ if(pSCSICBW->bmCBWFlags & CBWFLAGS_DIR_IN)
+ {
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ucINEndpoint,
+ USB_EP_DEV_IN);
+ }
+ else
+ {
+ //
+ // Stall the OUT endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ucOUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ }
+ //
+ // Send the status once the stall occurs.
+ //
+ psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
+ }
+
+ //
+ // Set the sense codes.
+ //
+ psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ucSenseKey = SCSI_RS_KEY_ILGL_RQST;
+ psInst->usAddSenseCode = SCSI_RS_PV_INVALID;
+
+ break;
+ }
+ }
+
+ //
+ // If there is no data then send out the current status.
+ //
+ if(ulTransferLength == 0)
+ {
+ USBDSCSISendStatus(psDevice);
+ }
+ return(ulRetCode);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdmsc.h b/usblib/device/usbdmsc.h
new file mode 100644
index 0000000..6719827
--- /dev/null
+++ b/usblib/device/usbdmsc.h
@@ -0,0 +1,391 @@
+//*****************************************************************************
+//
+// usbdmsc.h - USB mass storage device class driver.
+//
+// Copyright (c) 2009-2012 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 9453 of the Stellaris 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
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// USBDMSCMediaChange() ulStatus values.
+//
+//*****************************************************************************
+typedef enum
+{
+ USBDMSC_MEDIA_PRESENT,
+ USBDMSC_MEDIA_NOTPRESENT,
+ USBDMSC_MEDIA_UNKNOWN
+}
+tUSBDMSCMediaStatus;
+
+//*****************************************************************************
+//
+//! Media Access functions.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This function is used to initialize and open the physical drive number
+ //! associated with the parameter ulDrive. The function will return zero if
+ //! the drive could not be opened for some reason. In the case of removable
+ //! device like an SD card this function should return zero if the SD card
+ //! is not present.
+ //! The function returns a pointer to data that should be passed to other
+ //! APIs or it will return 0 if no drive was found.
+ //
+ void *(* Open)(unsigned long ulDrive);
+
+ //*****************************************************************************
+ //
+ // This function close the drive number in use by the mass storage class device.
+ //
+ // /param pvDrive is the pointer that was returned from a call to
+ // USBDMSCStorageOpen().
+ //
+ // This function is used to close the physical drive number associated with the
+ // parameter /e pvDrive. This function will return 0 if the drive was closed
+ // successfully and any other value will indicate a failure.
+ //
+ // /return Returns 0 if the drive was successfully closed or non-zero for a
+ // failure.
+ //
+ //*****************************************************************************
+ void (* Close)(void * pvDrive);
+
+ //*****************************************************************************
+ //
+ // This function will read a block from a device opened by the
+ // USBDMSCStorageOpen() call.
+ //
+ // /param pvDrive is the pointer that was returned from a call to
+ // USBDMSCStorageOpen().
+ // /param pucData is the buffer that data will be written into.
+ // /param ulSector is the block address to read.
+ // /param ulNumBlocks is the number of blocks to read.
+ //
+ // This function is use to read blocks from a physical device and return them
+ // in the /e pucData buffer. The data area pointed to by /e pucData should be
+ // at least /e ulNumBlocks * Block Size bytes to prevent overwriting data.
+ //
+ // /return Returns the number of bytes that were read from the device.
+ //
+ //*****************************************************************************
+ unsigned long (* BlockRead)(void * pvDrive, unsigned char *pucData,
+ unsigned long ulSector,
+ unsigned long ulNumBlocks);
+
+ //*****************************************************************************
+ //
+ // This function will write a block to a device opened by the
+ // USBDMSCStorageOpen() call.
+ //
+ // /param pvDrive is the pointer that was returned from a call to
+ // USBDMSCStorageOpen().
+ // /param pucData is the buffer that data will be used for writing.
+ // /param ulNumBlocks is the number of blocks to write.
+ //
+ // This function is use to write blocks to a physical device from the buffer
+ // pointed to by the /e pucData buffer. If the number of blocks is greater than
+ // one then the block address will increment and write to the next block until
+ // /e ulNumBlocks * Block Size bytes have been written.
+ //
+ // /return Returns the number of bytes that were written to the device.
+ //
+ //*****************************************************************************
+ unsigned long (* BlockWrite)(void * pvDrive, unsigned char *pucData,
+ unsigned long ulSector,
+ unsigned long ulNumBlocks);
+
+ //*****************************************************************************
+ //
+ // This function will return the number of blocks present on a device.
+ //
+ // /param pvDrive is the pointer that was returned from a call to
+ // USBDMSCStorageOpen().
+ //
+ // This function is used to return the total number of blocks on a physical
+ // device based on the /e pvDrive parameter.
+ //
+ // /return Returns the number of blocks that are present in a device.
+ //
+ //*****************************************************************************
+ unsigned long (* NumBlocks)(void * pvDrive);
+
+}
+tMSCDMedia;
+
+//*****************************************************************************
+//
+// These defines control the sizes of USB transfers for data and commands.
+//
+//*****************************************************************************
+#define DEVICE_BLOCK_SIZE 512
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// mass storage class. The memory for this structure is pointed to by
+// the psPrivateData 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
+{
+ unsigned long ulUSBBase;
+ tDeviceInfo *psDevInfo;
+ tConfigDescriptor *psConfDescriptor;
+
+ //
+ // These three values are used to return the current sense data for an
+ // instance of the mass storage class.
+ //
+ unsigned char ucErrorCode;
+ unsigned char ucSenseKey;
+ unsigned short usAddSenseCode;
+
+ //
+ // The pointer to the instance returned from the Open call to the media.
+ //
+ void *pvMedia;
+
+ volatile tBoolean bConnected;
+
+ //
+ // Holds the flag settings for this instance.
+ //
+ unsigned long ulFlags;
+
+ tUSBDMSCMediaStatus eMediaStatus;
+
+ unsigned long pulBuffer[DEVICE_BLOCK_SIZE>>2];
+ unsigned long ulBytesToTransfer;
+ unsigned long ulCurrentLBA;
+
+ unsigned char ucINEndpoint;
+ unsigned char ucINDMA;
+ unsigned char ucOUTEndpoint;
+ unsigned char ucOUTDMA;
+ unsigned char ucInterface;
+ unsigned char ucSCSIState;
+}
+tMSCInstance;
+
+//*****************************************************************************
+//
+//
+//*****************************************************************************
+#ifdef DEPRECATED
+//*****************************************************************************
+//
+// This is the size in bytes of the private data for the mass storage class.
+//
+// This value is deprecated and should not be used, any new code should just
+// pass in a tMSCInstance structure in the psPrivateData field.
+//
+//*****************************************************************************
+#define USB_MSC_WORKSPACE_SIZE sizeof(tMSCInstance);
+#endif
+
+//*****************************************************************************
+//
+//! 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.
+//
+// For reference this is sizeof(g_pAudioControlInterface) +
+// sizeof(g_pAudioStreamInterface
+//
+//*****************************************************************************
+#define COMPOSITE_DMSC_SIZE (23)
+
+//*****************************************************************************
+//
+//! 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.
+ //
+ unsigned short usVID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ unsigned short usPID;
+
+ //
+ //! 8 byte vendor string.
+ //
+ unsigned char pucVendor[8];
+
+ //
+ //! 16 byte vendor string.
+ //
+ unsigned char pucProduct[16];
+
+ //
+ //! 4 byte vendor string.
+ //
+ unsigned char pucVersion[4];
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ unsigned short usMaxPowermA;
+
+ //
+ //! 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.
+ //
+ unsigned char ucPwrAttributes;
+
+ //
+ //! 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 unsigned char * const *ppStringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (num HID strings)) * (num languages)).
+ //
+ unsigned long ulNumStringDescriptors;
+
+ //
+ //! 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.
+ //
+ tMSCDMedia sMediaFunctions;
+
+ //
+ //! This is the callback function for various events that occur during
+ //! mass storage class operation.
+ //
+ tUSBCallback pfnEventCallback;
+
+ //
+ //! A pointer to 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 *psPrivateData;
+}
+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)
+
+extern tDeviceInfo g_sMSCDeviceInfo;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDMSCInit(unsigned long ulIndex,
+ const tUSBDMSCDevice *psMSCDevice);
+extern void *USBDMSCCompositeInit(unsigned long ulIndex,
+ const tUSBDMSCDevice *psMSCDevice);
+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