//****************************************************************************
//
//! 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);
}
//****************************************************************************
//
//! This function should be called once for the composite class device to
//! initialized 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 int ulIndex, tUSBDCompositeDevice *psDevice,
        unsigned int ulSize, unsigned char *pucData)
{
    tCompositeInstance *psInst;
    int iIdx;
    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;

    //
    // 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(iIdx = 0; iIdx < g_pCompConfigDescriptor[0]; iIdx++)
    {
        pucTemp[iIdx] = g_pCompConfigDescriptor[iIdx];
    }

    //
    // Create a byte pointer to use with the copy.
    //
    pucTemp = (unsigned char *)&psInst->sDeviceDescriptor;

    //
    // Copy the default configuration descriptor into the instance data.
    //
    for(iIdx = 0; iIdx < g_pCompDeviceDescriptor[0]; iIdx++)
    {
        pucTemp[iIdx] = g_pCompDeviceDescriptor[iIdx];
    }

    //
    // 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 stable to the device information
    // structure.
    //
    psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
    psInst->psDevInfo->ulNumStringDescriptors =
        psDevice->ulNumStringDescriptors;

    //
    // 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);
}