diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2014-03-16 14:41:11 +0200 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2014-03-16 14:41:11 +0200 |
| commit | 990090a4cc9070837d31e66b58d40f0c3d038741 (patch) | |
| tree | cf1b905082c364e9b223e0c5058566103138dae5 /usblib/device/usbdcomp.c | |
| parent | 7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff) | |
Add usblib and utils
Diffstat (limited to 'usblib/device/usbdcomp.c')
| -rw-r--r-- | usblib/device/usbdcomp.c | 1544 |
1 files changed, 1544 insertions, 0 deletions
diff --git a/usblib/device/usbdcomp.c b/usblib/device/usbdcomp.c new file mode 100644 index 0000000..727ed42 --- /dev/null +++ b/usblib/device/usbdcomp.c @@ -0,0 +1,1544 @@ +//****************************************************************************
+//
+// usbdcomp.c - USB composite device class driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usb-ids.h"
+#include "usblib/usbcdc.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdcdc.h"
+#include "usblib/device/usbdcomp.h"
+
+//****************************************************************************
+//
+//! \addtogroup composite_device_class_api
+//! @{
+//
+//****************************************************************************
+
+//****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//****************************************************************************
+static uint8_t g_pui8CompDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_MISC, // USB Device Class (spec 5.1.1)
+ USB_MISC_SUBCLASS_COMMON, // USB Device Sub-class (spec 5.1.1)
+ USB_MISC_PROTOCOL_IAD, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during USBDCompositeInit).
+ USBShort(0), // Product ID (filled in during USBDCompositeInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//****************************************************************************
+//
+// Composite class device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//****************************************************************************
+static const uint8_t g_pui8CompConfigDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(0), // The total size of this full structure.
+ 0, // The number of interfaces in this
+ // configuration, this will be filled by
+ // the class as it discovers all classes
+ // supported.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_BUS_PWR, // .
+ 250, // The maximum power in 2mA increments.
+};
+
+//****************************************************************************
+//
+// Byte offsets used to access various fields in our index/interface/endpoint
+// lookup table (tUSBDCompositeDevice.pui32DeviceWorkspace). This workspace
+// contains one 4 byte entry per device. The LSB is the device index, next byte
+// is the number of the first interface not within this device, next byte is
+// the number of the first IN endpoint not within this device and the final
+// byte is the number of the first OUT endpoint not within this device. Using
+// this simple table we can reasonably quickly cross-reference index with
+// interface and endpoint numbers.
+//
+//****************************************************************************
+#define LOOKUP_INDEX_BYTE 0
+#define LOOKUP_INTERFACE_BYTE 1
+#define LOOKUP_IN_END_BYTE 2
+#define LOOKUP_OUT_END_BYTE 3
+
+//****************************************************************************
+//
+// A marker used to indicate an invalid index into the device table.
+//
+//****************************************************************************
+#define INVALID_DEVICE_INDEX 0xFFFFFFFF
+
+//****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//****************************************************************************
+static void HandleDisconnect(void *pvCompositeInstance);
+static void InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting);
+static void ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value);
+static void DataSent(void *pvCompositeInstance, uint32_t ui32Info);
+static void DataReceived(void *pvCompositeInstance, uint32_t ui32Info);
+static void HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status);
+static void HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest);
+static void SuspendHandler(void *pvCompositeInstance);
+static void ResumeHandler(void *pvCompositeInstance);
+static void ResetHandler(void *pvCompositeInstance);
+static void HandleDevice(void *pvCompositeInstance, uint32_t ui32Request,
+ void *pvRequestData);
+static void GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest);
+
+//****************************************************************************
+//
+// Configuration Descriptor.
+//
+//****************************************************************************
+tConfigHeader *g_ppCompConfigDescriptors[1];
+
+//****************************************************************************
+//
+// The device information structure for the USB Composite device.
+//
+//****************************************************************************
+const tCustomHandlers g_sCompHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ GetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ InterfaceChange,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ DataSent,
+
+ //
+ // ResetHandler
+ //
+ ResetHandler,
+
+ //
+ // SuspendHandler
+ //
+ SuspendHandler,
+
+ //
+ // ResumeHandler
+ //
+ ResumeHandler,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // DeviceHandler
+ //
+ HandleDevice,
+};
+
+//****************************************************************************
+//
+// Use the lookup table from the field pui32DeviceWorkspace in the
+// tUSBDCompositeDevice structure to determine which device to call given a
+// particular composite device interface number.
+//
+// The returned value is the index into psDevice->tCompositeEntry indicating
+// the device which contains this interface or INVALID_DEVICE_INDEX if no
+// device contains the passed interface number.
+//
+//****************************************************************************
+static uint32_t
+InterfaceToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Interface)
+{
+ uint32_t ui32Loop;
+ uint32_t ui32Lookup;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++)
+ {
+ //
+ // Get the look up value from the device.
+ //
+ ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace;
+ ui32Lookup = (ui32Lookup >> (8 * LOOKUP_INTERFACE_BYTE)) & 0xff;
+
+ //
+ // If the desired interface number is lower than the value in the
+ // current lookup table entry, we have found the desired device so
+ // return its index.
+ //
+ if(ui32Interface < ui32Lookup)
+ {
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we get here, an invalid interface number was passed so return a
+ // marker to indicate this.
+ //
+ return(INVALID_DEVICE_INDEX);
+}
+
+//****************************************************************************
+//
+// Use the lookup table from the field pui32DeviceWorkspace in the
+// tUSBDCompositeDevice structure to determine which device to call given a
+// particular composite device endpoint number.
+//
+// The returned value is the index into psDevice->tCompositeEntry indicating
+// the device which contains this endpoint or INVALID_DEVICE_INDEX if no
+// device contains the passed endpoint number.
+//
+//****************************************************************************
+static uint32_t
+EndpointToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Endpoint,
+ bool bInEndpoint)
+{
+ uint32_t ui32Loop, ui32EndpointByte, ui32Lookup;
+
+ //
+ // Are we considering an IN or OUT endpoint?
+ //
+ ui32EndpointByte = bInEndpoint ? LOOKUP_IN_END_BYTE : LOOKUP_OUT_END_BYTE;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++)
+ {
+ //
+ // Get the look up byte from the device.
+ //
+ ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace;
+ ui32Lookup = (ui32Lookup >> (ui32EndpointByte * 8)) & 0xff;
+
+ //
+ // If the desired endpoint number is lower than the value in the
+ // current lookup table entry, we have found the desired device so
+ // return its index.
+ //
+ if(ui32Endpoint < ui32Lookup)
+ {
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we get here, an invalid endpoint number was passed so return a
+ // marker to indicate this.
+ //
+ return(INVALID_DEVICE_INDEX);
+}
+
+
+//****************************************************************************
+//
+// This function will check if any device classes need a get descriptor
+// handler called.
+//
+//****************************************************************************
+static void
+GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the composite device pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Determine which device this request is intended for. We have to be
+ // careful here to send this to the callback for the correct device
+ // depending upon whether it is a request sent to the device, the interface
+ // or the endpoint.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ui32Idx = InterfaceToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ui32Idx = EndpointToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0x0F),
+ (psUSBRequest->wIndex & 0x80) ? true : false);
+ break;
+ }
+
+ //
+ // Requests sent to the device or any other recipient can't be
+ // handled here since we have no way of telling where they are
+ // supposed to be handled. As a result, we just stall them.
+ //
+ // If your composite device has some device-specific descriptors,
+ // you should add code here to handle them.
+ //
+ case USB_RTYPE_DEVICE:
+ case USB_RTYPE_OTHER:
+ default:
+ {
+ ui32Idx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ //
+ // Does this device have a GetDescriptor callback?
+ //
+ if(psDeviceInfo->psCallbacks->pfnGetDescriptor)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx;
+
+ //
+ // Call the device to retrieve the descriptor.
+ //
+ psDeviceInfo->psCallbacks->pfnGetDescriptor(
+ psCompDevice->psDevices[ui32Idx].pvInstance, psUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an suspend handler
+// called.
+//
+//****************************************************************************
+static void
+SuspendHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_SUSPEND,
+ 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnSuspendHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnSuspendHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an resume handler
+// called.
+//
+//****************************************************************************
+static void
+ResumeHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_RESUME,
+ 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnResumeHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnResumeHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an reset handler
+// called.
+//
+//****************************************************************************
+static void
+ResetHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has been connected.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance,
+ USB_EVENT_CONNECTED, 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnResetHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnResetHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called to handle data being set to the host so that the
+// application callback can be called when the data has been transferred.
+//
+//****************************************************************************
+static void
+DataSent(void *pvCompositeInstance, uint32_t ui32Info)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner;
+
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDataSent)
+ {
+ psDeviceInfo->psCallbacks->pfnDataSent(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called to handle data being received back from the host so
+// that the application callback can be called when the new data is ready.
+//
+//****************************************************************************
+static void
+DataReceived(void *pvCompositeInstance, uint32_t ui32Info)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner;
+
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDataReceived)
+ {
+ psDeviceInfo->psCallbacks->pfnDataReceived(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an endpoint handler
+// called.
+//
+//****************************************************************************
+static void
+HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Call each of the endpoint handlers. This may seem odd since we should
+ // only call the handler whose endpoint needs service. Unfortunately, if
+ // the device class driver is using uDMA, we have no way of knowing which
+ // handler to call (since ui32Status will be 0). Since the handlers are
+ // set up to ignore any callback that is not for them, this is safe.
+ //
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnEndpointHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnEndpointHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Status);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvCompositeInstance, uint32_t ui32Request,
+ void *pvRequestData)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDeviceHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Request,
+ pvRequestData);
+ }
+ }
+
+ if(psCompDevice->pfnCallback)
+ {
+ switch(ui32Request)
+ {
+ case USB_EVENT_LPM_RESUME:
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//****************************************************************************
+static void
+HandleDisconnect(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance,
+ USB_EVENT_DISCONNECTED, 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDisconnectHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnDisconnectHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// interface changes. It will be passed on to the device classes if they have
+// a handler for this function.
+//
+//****************************************************************************
+static void
+InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnInterfaceChange)
+ {
+ psDeviceInfo->psCallbacks->pfnInterfaceChange(
+ psCompDevice->psDevices[ui32Idx].pvInstance,
+ ui8InterfaceNum, ui8AlternateSetting);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes. It will be passed on to the device classes if they
+// have a handler for this function.
+//
+//****************************************************************************
+static void
+ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnConfigChange)
+ {
+ psDeviceInfo->psCallbacks->pfnConfigChange(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Value);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvCompositeInstance
+// \param psUSBRequest points to the request received.
+//
+// This call will be passed on to the device classes if they have a handler
+// for this function.
+//
+// \return None.
+//
+//****************************************************************************
+static void
+HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Determine which device this request is intended for. We have to be
+ // careful here to send this to the callback for the correct device
+ // depending upon whether it is a request sent to the device, the interface
+ // or the endpoint.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ui32Idx = InterfaceToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ui32Idx = EndpointToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0x0F),
+ (psUSBRequest->wIndex & 0x80) ? true : false);
+ break;
+ }
+
+ //
+ // Requests sent to the device or any other recipient can't be
+ // handled here since we have no way of telling where they are
+ // supposed to be handled. As a result, we just stall them.
+ //
+ // If your composite device has some device-specific requests that need
+ // to be handled at the device (rather than interface or endpoint)
+ // level, you should add code here to handle them.
+ //
+ case USB_RTYPE_DEVICE:
+ case USB_RTYPE_OTHER:
+ default:
+ {
+ ui32Idx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ //
+ // Does this device have a RequestHandler callback?
+ //
+ if(psDeviceInfo->psCallbacks->pfnRequestHandler)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx;
+
+ //
+ // Yes - call the device to retrieve the descriptor.
+ //
+ psDeviceInfo->psCallbacks->pfnRequestHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance,
+ psUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending interface number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeIfaceChange(tCompositeEntry *psCompDevice, uint8_t ui8Old,
+ uint8_t ui8New)
+{
+ uint8_t pui8Interfaces[2];
+
+ if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pui8Interfaces[0] = ui8Old;
+ pui8Interfaces[1] = ui8New;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->pvInstance, USB_EVENT_COMP_IFACE_CHANGE,
+ (void *)pui8Interfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending endpoint number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeEPChange(tCompositeEntry *psCompDevice, uint8_t ui8Old,
+ uint8_t ui8New)
+{
+ uint8_t pui8Interfaces[2];
+
+ if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pui8Interfaces[0] = ui8Old;
+ pui8Interfaces[1] = ui8New;
+
+ ui8New--;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->pvInstance, USB_EVENT_COMP_EP_CHANGE,
+ (void *)pui8Interfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function merges the configuration descriptors into a single multiple
+// instance device.
+//
+//****************************************************************************
+uint32_t
+BuildCompositeDescriptor(tUSBDCompositeDevice *psCompDevice)
+{
+ uint32_t ui32Idx, ui32Offset, ui32CPIdx, ui32FixINT, ui32Dev;
+ uint16_t ui16TotalLength, ui16Bytes;
+ uint8_t ui8Interface, ui8INEndpoint, ui8OUTEndpoint;
+ uint8_t *pui8Data, *pui8Config;
+ const tConfigHeader *psConfigHeader;
+ tDescriptorHeader *psHeader;
+ const uint8_t *pui8Descriptor;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ const tDeviceInfo *psDevice;
+
+ //
+ // Save the number of devices to look through.
+ //
+ ui32Dev = 0;
+ ui32Idx = 0;
+ ui8Interface = 0;
+ ui8INEndpoint = 1;
+ ui8OUTEndpoint = 1;
+ ui32Offset = 0;
+ ui32FixINT = 0;
+
+ //
+ // This puts the first section pointer in the first entry in the list
+ // of sections.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[0] =
+ &psCompDevice->sPrivateData.psCompSections[0];
+
+ //
+ // Put the pointer to this instances configuration descriptor into the
+ // front of the list.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[0]->pui8Data =
+ (uint8_t *)&psCompDevice->sPrivateData.sConfigDescriptor;
+
+ psCompDevice->sPrivateData.ppsCompSections[0]->ui16Size =
+ psCompDevice->sPrivateData.sConfigDescriptor.bLength;
+
+ //
+ // The configuration descriptor is 9 bytes so initialize the total length
+ // to 9 bytes.
+ //
+ ui16TotalLength = 9;
+
+ //
+ // Copy the section pointer into the section array for the composite
+ // device. This is awkward but is required given the definition
+ // of the structures.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[1] =
+ &psCompDevice->sPrivateData.psCompSections[1];
+
+ //
+ // Copy the pointer to the application supplied space into the section
+ // list.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = 0;
+ psCompDevice->sPrivateData.ppsCompSections[1]->pui8Data =
+ psCompDevice->sPrivateData.pui8Data;
+
+ //
+ // Create a local pointer to the data that is used to copy data from
+ // the other devices into the composite descriptor.
+ //
+ pui8Data = psCompDevice->sPrivateData.pui8Data;
+
+ //
+ // Consider each device in turn.
+ //
+ while(ui32Dev < psCompDevice->ui32NumDevices)
+ {
+ //
+ // Save the current starting address of this descriptor.
+ //
+ pui8Config = pui8Data + ui32Offset;
+
+ //
+ // Create a local pointer to the configuration header.
+ //
+ psDevice = psCompDevice->psDevices[ui32Dev].psDevInfo;
+ psConfigHeader = psDevice->ppsConfigDescriptors[0];
+
+ //
+ // Loop through each of the sections in this device's configuration
+ // descriptor.
+ //
+ for(ui32Idx = 0; ui32Idx < psConfigHeader->ui8NumSections; ui32Idx++)
+ {
+ //
+ // Initialize the local offset in this descriptor. We include
+ // a special case here to ignore the initial 9 byte configuration
+ // descriptor since this has already been handled.
+ //
+ if(ui32Idx)
+ {
+ //
+ // This is not the first section so we handle everything in
+ // it.
+ //
+ ui16Bytes = 0;
+ }
+ else
+ {
+ //
+ // This is the first section for this device so skip the 9
+ // byte configuration descriptor since we've already handled
+ // this.
+ //
+ ui16Bytes = 9;
+
+ //
+ // If this section includes only the configuration descriptor,
+ // skip it entirely.
+ //
+ if(psConfigHeader->psSections[ui32Idx]->ui16Size <= ui16Bytes)
+ {
+ continue;
+ }
+ }
+
+ //
+ // Get a pointer to the configuration descriptor.
+ //
+ pui8Descriptor = psConfigHeader->psSections[ui32Idx]->pui8Data;
+
+ //
+ // Bounds check the allocated space and return if there is not
+ // enough space.
+ //
+ if(ui32Offset > psCompDevice->sPrivateData.ui32DataSize)
+ {
+ return(1);
+ }
+
+ //
+ // Copy the descriptor from the device into the descriptor list.
+ //
+ for(ui32CPIdx = 0;
+ ui32CPIdx < psConfigHeader->psSections[ui32Idx]->ui16Size;
+ ui32CPIdx++)
+ {
+ pui8Data[ui32CPIdx + ui32Offset] = pui8Descriptor[ui32CPIdx];
+ }
+
+ //
+ // Read out the descriptors in this section.
+ //
+ while(ui16Bytes < psConfigHeader->psSections[ui32Idx]->ui16Size)
+ {
+ //
+ // Create a descriptor header pointer.
+ //
+ psHeader = (tDescriptorHeader *)&pui8Data[ui32Offset +
+ ui16Bytes];
+
+ //
+ // Check for interface descriptors and modify the numbering to
+ // match the composite device.
+ //
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // See if this is an alternate setting or the initial
+ // setting.
+ //
+ if(psInterface->bAlternateSetting != 0)
+ {
+ //
+ // If this is an alternate setting then use the
+ // previous interface number because the current one
+ // has already been incremented.
+ //
+ psInterface->bInterfaceNumber = ui8Interface - 1;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeIfaceChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psInterface->bInterfaceNumber,
+ ui8Interface);
+ //
+ // This was the non-alternate setting so save the
+ // value and move to the next interface number.
+ //
+ psInterface->bInterfaceNumber = ui8Interface;
+
+ //
+ // No strings allowed on interface descriptors for
+ // composite devices.
+ //
+ psInterface->iInterface = 0;
+
+ ui8Interface++;
+ }
+ }
+ //
+ // Check for endpoint descriptors and modify the numbering to
+ // match the composite device.
+ //
+ else if(psHeader->bDescriptorType == USB_DTYPE_ENDPOINT)
+ {
+ psEndpoint = (tEndpointDescriptor *)psHeader;
+
+ //
+ // Check if this is an IN or OUT endpoint.
+ //
+ if(psEndpoint->bEndpointAddress & USB_RTYPE_DIR_IN)
+ {
+ //
+ // Check if this is the special Fixed Interrupt class
+ // and this is the interrupt endpoint.
+ //
+ if(((psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT) &&
+ (psCompDevice->ui16PID == USB_PID_COMP_SERIAL))
+ {
+ //
+ // Check if the Fixed Interrupt endpoint has been
+ // set yet.
+ //
+ if(ui32FixINT == 0)
+ {
+ //
+ // Allocate the fixed interrupt endpoint and
+ // save its number.
+ //
+ ui32FixINT = ui8INEndpoint++;
+ }
+
+ CompositeEPChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui32FixINT);
+
+ psEndpoint->bEndpointAddress = ui32FixINT |
+ USB_RTYPE_DIR_IN;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui8INEndpoint);
+
+ psEndpoint->bEndpointAddress = ui8INEndpoint++ |
+ USB_RTYPE_DIR_IN;
+ }
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(&psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui8OUTEndpoint);
+ psEndpoint->bEndpointAddress = ui8OUTEndpoint++;
+ }
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui16Bytes += psHeader->bLength;
+ }
+
+ ui32Offset += psConfigHeader->psSections[ui32Idx]->ui16Size;
+
+ ui16TotalLength += ui16Bytes;
+ }
+
+ //
+ // Allow the device class to make adjustments to the configuration
+ // descriptor.
+ //
+ psCompDevice->psDevices[ui32Dev].psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->psDevices[ui32Dev].pvInstance,
+ USB_EVENT_COMP_CONFIG, (void *)pui8Config);
+
+ //
+ // Add an entry into the device workspace array to allow us to quickly
+ // map interface and endpoint numbers to device instances later.
+ //
+ psCompDevice->psDevices[ui32Dev].ui32DeviceWorkspace =
+ (ui32Dev << (LOOKUP_INDEX_BYTE * 8)) |
+ (ui8Interface << (LOOKUP_INTERFACE_BYTE * 8)) |
+ (ui8OUTEndpoint << (LOOKUP_OUT_END_BYTE * 8)) |
+ (ui8INEndpoint << (LOOKUP_IN_END_BYTE * 8));
+
+ //
+ // Move on to the next device.
+ //
+ ui32Dev++;
+ }
+
+ //
+ // Modify the configuration descriptor to match the number of interfaces
+ // and the new total size.
+ //
+ psCompDevice->sPrivateData.sCompConfigHeader.ui8NumSections = 2;
+ psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = ui32Offset;
+ psCompDevice->sPrivateData.sConfigDescriptor.bNumInterfaces =
+ ui8Interface;
+ psCompDevice->sPrivateData.sConfigDescriptor.wTotalLength =
+ ui16TotalLength;
+
+
+ return(0);
+}
+
+//****************************************************************************
+//
+//! This function should be called once for the composite class device to
+//! initialize basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! composite device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the composite device.
+//! \param ui32Size is the size in bytes of the data pointed to by the
+//! \e pui8Data parameter.
+//! \param pui8Data is the data area that the composite class can use to build
+//! up descriptors.
+//!
+//! In order for an application to initialize the USB composite device class,
+//! it must first call this function with the a valid composite device class
+//! structure in the \e psDevice parameter. This allows this function to
+//! initialize the USB controller and device code to be prepared to enumerate
+//! and function as a USB composite device. The \e ui32Size and \e pui8Data
+//! parameters should be large enough to hold all of the class instances
+//! passed in via the \e psDevice structure. This is typically the full size
+//! of the configuration descriptor for a device minus its configuration
+//! header(9 bytes).
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the composite class.
+//!
+//! See the documentation on the tUSBDCompositeDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return This function returns 0 on failure or a non-zero void pointer on
+//! success.
+//
+//****************************************************************************
+void *
+USBDCompositeInit(uint32_t ui32Index, tUSBDCompositeDevice *psDevice,
+ uint32_t ui32Size, uint8_t *pui8Data)
+{
+ tCompositeInstance *psInst;
+ int32_t i32Idx;
+ uint8_t *pui8Temp;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppui8StringDescriptors);
+
+ //
+ // Initialize the work space in the passed instance structure.
+ //
+ psInst = &psDevice->sPrivateData;
+ psInst->ui32DataSize = ui32Size;
+ psInst->pui8Data = pui8Data;
+
+ //
+ // Save the base address of the USB controller.
+ //
+ psInst->ui32USBBase = USBIndexToBase(ui32Index);
+
+ //
+ // No device is currently transferring data on EP0.
+ //
+ psInst->ui32EP0Owner = INVALID_DEVICE_INDEX;
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sCompHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8CompDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors =
+ (const tConfigHeader * const *)g_ppCompConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the composite device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ g_ppCompConfigDescriptors[0] = &psInst->sCompConfigHeader;
+ g_ppCompConfigDescriptors[0]->ui8NumSections = 0;
+ g_ppCompConfigDescriptors[0]->psSections =
+ (const tConfigSection * const *)psDevice->sPrivateData.ppsCompSections;
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pui8Temp = (uint8_t *)&psInst->sConfigDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(i32Idx = 0; i32Idx < g_pui8CompConfigDescriptor[0]; i32Idx++)
+ {
+ pui8Temp[i32Idx] = g_pui8CompConfigDescriptor[i32Idx];
+ }
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pui8Temp = (uint8_t *)&psInst->sDeviceDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(i32Idx = 0; i32Idx < g_pui8CompDeviceDescriptor[0]; i32Idx++)
+ {
+ pui8Temp[i32Idx] = g_pui8CompDeviceDescriptor[i32Idx];
+ }
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psInst->sDeviceDescriptor.idVendor = psDevice->ui16VID;
+ psInst->sDeviceDescriptor.idProduct = psDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->sConfigDescriptor.bmAttributes = psDevice->ui8PwrAttributes;
+ psInst->sConfigDescriptor.bMaxPower =
+ (uint8_t)(psDevice->ui16MaxPowermA>>1);
+
+ psInst->sDevInfo.pui8DeviceDescriptor =
+ (const uint8_t *)&psInst->sDeviceDescriptor;
+
+ //
+ // Plug in the client's string table to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psDevice->ui32NumStringDescriptors;
+
+ //
+ // Enable Clocking to the USB controller so that changes to the USB
+ // controller can be made in the BuildCompositeDescriptor() function.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Create the combined descriptors.
+ //
+ if(BuildCompositeDescriptor(psDevice))
+ {
+ return(0);
+ }
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psInst->sDevInfo, (void *)psDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went
+ // well.
+ //
+ return((void *)psDevice);
+}
+
+//****************************************************************************
+//
+//! Shuts down the composite device.
+//!
+//! \param pvCompositeInstance is the pointer to the device instance structure
+//! as returned by USBDCompositeInit().
+//!
+//! This function terminates composite device interface for the instance
+//! not me supplied. Following this call, the \e pvCompositeInstance instance
+//! should not be used in any other calls.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+USBDCompositeTerm(void *pvCompositeInstance)
+{
+ ASSERT(pvCompositeInstance != 0);
+
+}
+
+//****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//****************************************************************************
+
|
