summaryrefslogtreecommitdiff
path: root/usblib/device/usbdcomp.c
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/usbdcomp.c
parent4ba8614c006f9828f0796c140bc3e13c9e67938c (diff)
Added usblib
Diffstat (limited to 'usblib/device/usbdcomp.c')
-rw-r--r--usblib/device/usbdcomp.c1543
1 files changed, 1543 insertions, 0 deletions
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.
+//! @}
+//
+//****************************************************************************
+