/***************************************************************************//**
* \file CDC_std.c
* \version 3.20
*
* \brief
*  This file contains the USB Standard request handler.
*
********************************************************************************
* \copyright
* Copyright 2008-2016, Cypress Semiconductor Corporation.  All rights reserved.
* You may use this file only in accordance with the license, terms, conditions,
* disclaimers, and limitations in the end user license agreement accompanying
* the software package with which this file was provided.
*******************************************************************************/

#include "CDC_pvt.h"

/***************************************
*   Static data allocation
***************************************/

#if defined(CDC_ENABLE_FWSN_STRING)
    static volatile uint8* CDC_fwSerialNumberStringDescriptor;
    static volatile uint8  CDC_snStringConfirm = CDC_FALSE;
#endif  /* (CDC_ENABLE_FWSN_STRING) */

#if defined(CDC_ENABLE_FWSN_STRING)
    /***************************************************************************
    * Function Name: CDC_SerialNumString
    ************************************************************************//**
    *
    *  This function is available only when the User Call Back option in the 
    *  Serial Number String descriptor properties is selected. Application 
    *  firmware can provide the source of the USB device serial number string 
    *  descriptor during run time. The default string is used if the application 
    *  firmware does not use this function or sets the wrong string descriptor.
    *
    *  \param snString:  Pointer to the user-defined string descriptor. The 
    *  string descriptor should meet the Universal Serial Bus Specification 
    *  revision 2.0 chapter 9.6.7
    *  Offset|Size|Value|Description
    *  ------|----|------|---------------------------------
    *  0     |1   |N     |Size of this descriptor in bytes
    *  1     |1   |0x03  |STRING Descriptor Type
    *  2     |N-2 |Number|UNICODE encoded string
    *  
    * *For example:* uint8 snString[16]={0x0E,0x03,'F',0,'W',0,'S',0,'N',0,'0',0,'1',0};
    *
    * \reentrant
    *  No.
    *
    ***************************************************************************/
    void  CDC_SerialNumString(uint8 snString[]) 
    {
        CDC_snStringConfirm = CDC_FALSE;
        
        if (snString != NULL)
        {
            /* Check descriptor validation */
            if ((snString[0u] > 1u) && (snString[1u] == CDC_DESCR_STRING))
            {
                CDC_fwSerialNumberStringDescriptor = snString;
                CDC_snStringConfirm = CDC_TRUE;
            }
        }
    }
#endif  /* CDC_ENABLE_FWSN_STRING */


/*******************************************************************************
* Function Name: CDC_HandleStandardRqst
****************************************************************************//**
*
*  This Routine dispatches standard requests
*
*
* \return
*  TRUE if request handled.
*
* \reentrant
*  No.
*
*******************************************************************************/
uint8 CDC_HandleStandardRqst(void) 
{
    uint8 requestHandled = CDC_FALSE;
    uint8 interfaceNumber;
    uint8 configurationN;
    uint8 bmRequestType = CDC_bmRequestTypeReg;

#if defined(CDC_ENABLE_STRINGS)
    volatile uint8 *pStr = 0u;
    #if defined(CDC_ENABLE_DESCRIPTOR_STRINGS)
        uint8 nStr;
        uint8 descrLength;
    #endif /* (CDC_ENABLE_DESCRIPTOR_STRINGS) */
#endif /* (CDC_ENABLE_STRINGS) */
    
    static volatile uint8 CDC_tBuffer[CDC_STATUS_LENGTH_MAX];
    const T_CDC_LUT CYCODE *pTmp;

    CDC_currentTD.count = 0u;

    if (CDC_RQST_DIR_D2H == (bmRequestType & CDC_RQST_DIR_MASK))
    {
        /* Control Read */
        switch (CDC_bRequestReg)
        {
            case CDC_GET_DESCRIPTOR:
                if (CDC_DESCR_DEVICE ==CDC_wValueHiReg)
                {
                    pTmp = CDC_GetDeviceTablePtr();
                    CDC_currentTD.pData = (volatile uint8 *)pTmp->p_list;
                    CDC_currentTD.count = CDC_DEVICE_DESCR_LENGTH;
                    
                    requestHandled  = CDC_InitControlRead();
                }
                else if (CDC_DESCR_CONFIG == CDC_wValueHiReg)
                {
                    pTmp = CDC_GetConfigTablePtr((uint8) CDC_wValueLoReg);
                    
                    /* Verify that requested descriptor exists */
                    if (pTmp != NULL)
                    {
                        CDC_currentTD.pData = (volatile uint8 *)pTmp->p_list;
                        CDC_currentTD.count = (uint16)((uint16)(CDC_currentTD.pData)[CDC_CONFIG_DESCR_TOTAL_LENGTH_HI] << 8u) | \
                                                                            (CDC_currentTD.pData)[CDC_CONFIG_DESCR_TOTAL_LENGTH_LOW];
                        requestHandled  = CDC_InitControlRead();
                    }
                }
                
            #if(CDC_BOS_ENABLE)
                else if (CDC_DESCR_BOS == CDC_wValueHiReg)
                {
                    pTmp = CDC_GetBOSPtr();
                    
                    /* Verify that requested descriptor exists */
                    if (pTmp != NULL)
                    {
                        CDC_currentTD.pData = (volatile uint8 *)pTmp;
                        CDC_currentTD.count = ((uint16)((uint16)(CDC_currentTD.pData)[CDC_BOS_DESCR_TOTAL_LENGTH_HI] << 8u)) | \
                                                                             (CDC_currentTD.pData)[CDC_BOS_DESCR_TOTAL_LENGTH_LOW];
                        requestHandled  = CDC_InitControlRead();
                    }
                }
            #endif /*(CDC_BOS_ENABLE)*/
            
            #if defined(CDC_ENABLE_STRINGS)
                else if (CDC_DESCR_STRING == CDC_wValueHiReg)
                {
                /* Descriptor Strings */
                #if defined(CDC_ENABLE_DESCRIPTOR_STRINGS)
                    nStr = 0u;
                    pStr = (volatile uint8 *) &CDC_STRING_DESCRIPTORS[0u];
                    
                    while ((CDC_wValueLoReg > nStr) && (*pStr != 0u))
                    {
                        /* Read descriptor length from 1st byte */
                        descrLength = *pStr;
                        /* Move to next string descriptor */
                        pStr = &pStr[descrLength];
                        nStr++;
                    }
                #endif /* (CDC_ENABLE_DESCRIPTOR_STRINGS) */
                
                /* Microsoft OS String */
                #if defined(CDC_ENABLE_MSOS_STRING)
                    if (CDC_STRING_MSOS == CDC_wValueLoReg)
                    {
                        pStr = (volatile uint8 *)& CDC_MSOS_DESCRIPTOR[0u];
                    }
                #endif /* (CDC_ENABLE_MSOS_STRING) */
                
                /* SN string */
                #if defined(CDC_ENABLE_SN_STRING)
                    if ((CDC_wValueLoReg != 0u) && 
                        (CDC_wValueLoReg == CDC_DEVICE0_DESCR[CDC_DEVICE_DESCR_SN_SHIFT]))
                    {
                    #if defined(CDC_ENABLE_IDSN_STRING)
                        /* Read DIE ID and generate string descriptor in RAM */
                        CDC_ReadDieID(CDC_idSerialNumberStringDescriptor);
                        pStr = CDC_idSerialNumberStringDescriptor;
                    #elif defined(CDC_ENABLE_FWSN_STRING)
                        
                        if(CDC_snStringConfirm != CDC_FALSE)
                        {
                            pStr = CDC_fwSerialNumberStringDescriptor;
                        }
                        else
                        {
                            pStr = (volatile uint8 *)&CDC_SN_STRING_DESCRIPTOR[0u];
                        }
                    #else
                        pStr = (volatile uint8 *)&CDC_SN_STRING_DESCRIPTOR[0u];
                    #endif  /* (CDC_ENABLE_IDSN_STRING) */
                    }
                #endif /* (CDC_ENABLE_SN_STRING) */
                
                    if (*pStr != 0u)
                    {
                        CDC_currentTD.count = *pStr;
                        CDC_currentTD.pData = pStr;
                        requestHandled  = CDC_InitControlRead();
                    }
                }
            #endif /*  CDC_ENABLE_STRINGS */
                else
                {
                    requestHandled = CDC_DispatchClassRqst();
                }
                break;
                
            case CDC_GET_STATUS:
                switch (bmRequestType & CDC_RQST_RCPT_MASK)
                {
                    case CDC_RQST_RCPT_EP:
                        CDC_currentTD.count = CDC_EP_STATUS_LENGTH;
                        CDC_tBuffer[0u]     = CDC_EP[CDC_wIndexLoReg & CDC_DIR_UNUSED].hwEpState;
                        CDC_tBuffer[1u]     = 0u;
                        CDC_currentTD.pData = &CDC_tBuffer[0u];
                        
                        requestHandled  = CDC_InitControlRead();
                        break;
                    case CDC_RQST_RCPT_DEV:
                        CDC_currentTD.count = CDC_DEVICE_STATUS_LENGTH;
                        CDC_tBuffer[0u]     = CDC_deviceStatus;
                        CDC_tBuffer[1u]     = 0u;
                        CDC_currentTD.pData = &CDC_tBuffer[0u];
                        
                        requestHandled  = CDC_InitControlRead();
                        break;
                    default:    /* requestHandled is initialized as FALSE by default */
                        break;
                }
                break;
                
            case CDC_GET_CONFIGURATION:
                CDC_currentTD.count = 1u;
                CDC_currentTD.pData = (volatile uint8 *) &CDC_configuration;
                requestHandled  = CDC_InitControlRead();
                break;
                
            case CDC_GET_INTERFACE:
                CDC_currentTD.count = 1u;
                CDC_currentTD.pData = (volatile uint8 *) &CDC_interfaceSetting[CDC_wIndexLoReg];
                requestHandled  = CDC_InitControlRead();
                break;
                
            default: /* requestHandled is initialized as FALSE by default */
                break;
        }
    }
    else
    {
        /* Control Write */
        switch (CDC_bRequestReg)
        {
            case CDC_SET_ADDRESS:
                /* Store address to be set in CDC_NoDataControlStatusStage(). */
                CDC_deviceAddress = (uint8) CDC_wValueLoReg;
                requestHandled = CDC_InitNoDataControlTransfer();
                break;
                
            case CDC_SET_CONFIGURATION:
                configurationN = CDC_wValueLoReg;
                
                /* Verify that configuration descriptor exists */
                if(configurationN > 0u)
                {
                    pTmp = CDC_GetConfigTablePtr((uint8) configurationN - 1u);
                }
                
                /* Responds with a Request Error when configuration number is invalid */
                if (((configurationN > 0u) && (pTmp != NULL)) || (configurationN == 0u))
                {
                    /* Set new configuration if it has been changed */
                    if(configurationN != CDC_configuration)
                    {
                        CDC_configuration = (uint8) configurationN;
                        CDC_configurationChanged = CDC_TRUE;
                        CDC_Config(CDC_TRUE);
                    }
                    requestHandled = CDC_InitNoDataControlTransfer();
                }
                break;
                
            case CDC_SET_INTERFACE:
                if (0u != CDC_ValidateAlternateSetting())
                {
                    /* Get interface number from the request. */
                    interfaceNumber = CDC_wIndexLoReg;
                    CDC_interfaceNumber = (uint8) CDC_wIndexLoReg;
                     
                    /* Check if alternate settings is changed for interface. */
                    if (CDC_interfaceSettingLast[interfaceNumber] != CDC_interfaceSetting[interfaceNumber])
                    {
                        CDC_configurationChanged = CDC_TRUE;
                    
                        /* Change alternate setting for the endpoints. */
                    #if (CDC_EP_MANAGEMENT_MANUAL && CDC_EP_ALLOC_DYNAMIC)
                        CDC_Config(CDC_FALSE);
                    #else
                        CDC_ConfigAltChanged();
                    #endif /* (CDC_EP_MANAGEMENT_MANUAL && CDC_EP_ALLOC_DYNAMIC) */
                    }
                    
                    requestHandled = CDC_InitNoDataControlTransfer();
                }
                break;
                
            case CDC_CLEAR_FEATURE:
                switch (bmRequestType & CDC_RQST_RCPT_MASK)
                {
                    case CDC_RQST_RCPT_EP:
                        if (CDC_wValueLoReg == CDC_ENDPOINT_HALT)
                        {
                            requestHandled = CDC_ClearEndpointHalt();
                        }
                        break;
                    case CDC_RQST_RCPT_DEV:
                        /* Clear device REMOTE_WAKEUP */
                        if (CDC_wValueLoReg == CDC_DEVICE_REMOTE_WAKEUP)
                        {
                            CDC_deviceStatus &= (uint8)~CDC_DEVICE_STATUS_REMOTE_WAKEUP;
                            requestHandled = CDC_InitNoDataControlTransfer();
                        }
                        break;
                    case CDC_RQST_RCPT_IFC:
                        /* Validate interfaceNumber */
                        if (CDC_wIndexLoReg < CDC_MAX_INTERFACES_NUMBER)
                        {
                            CDC_interfaceStatus[CDC_wIndexLoReg] &= (uint8) ~CDC_wValueLoReg;
                            requestHandled = CDC_InitNoDataControlTransfer();
                        }
                        break;
                    default:    /* requestHandled is initialized as FALSE by default */
                        break;
                }
                break;
                
            case CDC_SET_FEATURE:
                switch (bmRequestType & CDC_RQST_RCPT_MASK)
                {
                    case CDC_RQST_RCPT_EP:
                        if (CDC_wValueLoReg == CDC_ENDPOINT_HALT)
                        {
                            requestHandled = CDC_SetEndpointHalt();
                        }
                        break;
                        
                    case CDC_RQST_RCPT_DEV:
                        /* Set device REMOTE_WAKEUP */
                        if (CDC_wValueLoReg == CDC_DEVICE_REMOTE_WAKEUP)
                        {
                            CDC_deviceStatus |= CDC_DEVICE_STATUS_REMOTE_WAKEUP;
                            requestHandled = CDC_InitNoDataControlTransfer();
                        }
                        break;
                        
                    case CDC_RQST_RCPT_IFC:
                        /* Validate interfaceNumber */
                        if (CDC_wIndexLoReg < CDC_MAX_INTERFACES_NUMBER)
                        {
                            CDC_interfaceStatus[CDC_wIndexLoReg] &= (uint8) ~CDC_wValueLoReg;
                            requestHandled = CDC_InitNoDataControlTransfer();
                        }
                        break;
                    
                    default:    /* requestHandled is initialized as FALSE by default */
                        break;
                }
                break;
                
            default:    /* requestHandled is initialized as FALSE by default */
                break;
        }
    }
    
    return (requestHandled);
}


#if defined(CDC_ENABLE_IDSN_STRING)
    /***************************************************************************
    * Function Name: CDC_ReadDieID
    ************************************************************************//**
    *
    *  This routine read Die ID and generate Serial Number string descriptor.
    *
    *  \param descr:  pointer on string descriptor. This string size has to be equal or
    *          greater than CDC_IDSN_DESCR_LENGTH.
    *
    *
    * \reentrant
    *  No.
    *
    ***************************************************************************/
    void CDC_ReadDieID(uint8 descr[]) 
    {
        const char8 CYCODE hex[] = "0123456789ABCDEF";
        uint8 i;
        uint8 j = 0u;
        uint8 uniqueId[8u];

        if (NULL != descr)
        {
            /* Initialize descriptor header. */
            descr[0u] = CDC_IDSN_DESCR_LENGTH;
            descr[1u] = CDC_DESCR_STRING;
            
            /* Unique ID size is 8 bytes. */
            CyGetUniqueId((uint32 *) uniqueId);

            /* Fill descriptor with unique device ID. */
            for (i = 2u; i < CDC_IDSN_DESCR_LENGTH; i += 4u)
            {
                descr[i]      = (uint8) hex[(uniqueId[j] >> 4u)];
                descr[i + 1u] = 0u;
                descr[i + 2u] = (uint8) hex[(uniqueId[j] & 0x0Fu)];
                descr[i + 3u] = 0u;
                ++j;
            }
        }
    }
#endif /* (CDC_ENABLE_IDSN_STRING) */


/*******************************************************************************
* Function Name: CDC_ConfigReg
****************************************************************************//**
*
*  This routine configures hardware registers from the variables.
*  It is called from CDC_Config() function and from RestoreConfig
*  after Wakeup.
*
*******************************************************************************/
void CDC_ConfigReg(void) 
{
    uint8 ep;

#if (CDC_EP_MANAGEMENT_DMA_AUTO)
    uint8 epType = 0u;
#endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */

    /* Go thought all endpoints and set hardware configuration */
    for (ep = CDC_EP1; ep < CDC_MAX_EP; ++ep)
    {
        CDC_ARB_EP_BASE.arbEp[ep].epCfg = CDC_ARB_EPX_CFG_DEFAULT;
        
    #if (CDC_EP_MANAGEMENT_DMA)
        /* Enable arbiter endpoint interrupt sources */
        CDC_ARB_EP_BASE.arbEp[ep].epIntEn = CDC_ARB_EPX_INT_MASK;
    #endif /* (CDC_EP_MANAGEMENT_DMA) */
    
        if (CDC_EP[ep].epMode != CDC_MODE_DISABLE)
        {
            if (0u != (CDC_EP[ep].addr & CDC_DIR_IN))
            {
                CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_NAK_IN;
                
            #if (CDC_EP_MANAGEMENT_DMA_AUTO && CY_PSOC4)
                /* Clear DMA_TERMIN for IN endpoint. */
                CDC_ARB_EP_BASE.arbEp[ep].epIntEn &= (uint32) ~CDC_ARB_EPX_INT_DMA_TERMIN;
            #endif /* (CDC_EP_MANAGEMENT_DMA_AUTO && CY_PSOC4) */
            }
            else
            {
                CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_NAK_OUT;

            #if (CDC_EP_MANAGEMENT_DMA_AUTO)
                /* (CY_PSOC4): DMA_TERMIN for OUT endpoint is set above. */
                
                /* Prepare endpoint type mask. */
                epType |= (uint8) (0x01u << (ep - CDC_EP1));
            #endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */
            }
        }
        else
        {
            CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_STALL_DATA_EP;
        }
        
    #if (!CDC_EP_MANAGEMENT_DMA_AUTO)
        #if (CY_PSOC4)
            CDC_ARB_EP16_BASE.arbEp[ep].rwRa16  = (uint32) CDC_EP[ep].buffOffset;
            CDC_ARB_EP16_BASE.arbEp[ep].rwWa16  = (uint32) CDC_EP[ep].buffOffset;
        #else
            CDC_ARB_EP_BASE.arbEp[ep].rwRa    = LO8(CDC_EP[ep].buffOffset);
            CDC_ARB_EP_BASE.arbEp[ep].rwRaMsb = HI8(CDC_EP[ep].buffOffset);
            CDC_ARB_EP_BASE.arbEp[ep].rwWa    = LO8(CDC_EP[ep].buffOffset);
            CDC_ARB_EP_BASE.arbEp[ep].rwWaMsb = HI8(CDC_EP[ep].buffOffset);
        #endif /* (CY_PSOC4) */
    #endif /* (!CDC_EP_MANAGEMENT_DMA_AUTO) */
    }

#if (CDC_EP_MANAGEMENT_DMA_AUTO)
     /* BUF_SIZE depend on DMA_THRESS value:0x55-32 bytes  0x44-16 bytes 0x33-8 bytes 0x22-4 bytes 0x11-2 bytes */
    CDC_BUF_SIZE_REG = CDC_DMA_BUF_SIZE;

    /* Configure DMA burst threshold */
#if (CY_PSOC4)
    CDC_DMA_THRES16_REG   = CDC_DMA_BYTES_PER_BURST;
#else
    CDC_DMA_THRES_REG     = CDC_DMA_BYTES_PER_BURST;
    CDC_DMA_THRES_MSB_REG = 0u;
#endif /* (CY_PSOC4) */
    CDC_EP_ACTIVE_REG = CDC_DEFAULT_ARB_INT_EN;
    CDC_EP_TYPE_REG   = epType;
    
    /* Cfg_cmp bit set to 1 once configuration is complete. */
    /* Lock arbiter configtuation */
    CDC_ARB_CFG_REG |= (uint8)  CDC_ARB_CFG_CFG_CMP;
    /* Cfg_cmp bit set to 0 during configuration of PFSUSB Registers. */
    CDC_ARB_CFG_REG &= (uint8) ~CDC_ARB_CFG_CFG_CMP;

#endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */

    /* Enable interrupt SIE interurpt source from EP0-EP1 */
    CDC_SIE_EP_INT_EN_REG = (uint8) CDC_DEFAULT_SIE_EP_INT_EN;
}


/*******************************************************************************
* Function Name: CDC_EpStateInit
****************************************************************************//**
*
*  This routine initialize state of Data end points based of its type: 
*   IN  - CDC_IN_BUFFER_EMPTY (CDC_EVENT_PENDING)
*   OUT - CDC_OUT_BUFFER_EMPTY (CDC_NO_EVENT_PENDING)
*
*******************************************************************************/
void CDC_EpStateInit(void) 
{
    uint8 i;

    for (i = CDC_EP1; i < CDC_MAX_EP; i++)
    { 
        if (0u != (CDC_EP[i].addr & CDC_DIR_IN))
        {
            /* IN Endpoint */
            CDC_EP[i].apiEpState = CDC_EVENT_PENDING;
        }
        else
        {
            /* OUT Endpoint */
            CDC_EP[i].apiEpState = CDC_NO_EVENT_PENDING;
        }
    }
                    
}


/*******************************************************************************
* Function Name: CDC_Config
****************************************************************************//**
*
*  This routine configures endpoints for the entire configuration by scanning
*  the configuration descriptor.
*
*  \param clearAltSetting: It configures the bAlternateSetting 0 for each interface.
*
* CDC_interfaceClass - Initialized class array for each interface.
*   It is used for handling Class specific requests depend on interface class.
*   Different classes in multiple Alternate settings does not supported.
*
* \reentrant
*  No.
*
*******************************************************************************/
void CDC_Config(uint8 clearAltSetting) 
{
    uint8 ep;
    uint8 curEp;
    uint8 i;
    uint8 epType;
    const uint8 *pDescr;
    
    #if (!CDC_EP_MANAGEMENT_DMA_AUTO)
        uint16 buffCount = 0u;
    #endif /* (!CDC_EP_MANAGEMENT_DMA_AUTO) */

    const T_CDC_LUT CYCODE *pTmp;
    const T_CDC_EP_SETTINGS_BLOCK CYCODE *pEP;

    /* Clear endpoints settings */
    for (ep = 0u; ep < CDC_MAX_EP; ++ep)
    {
        CDC_EP[ep].attrib     = 0u;
        CDC_EP[ep].hwEpState  = 0u;
        CDC_EP[ep].epToggle   = 0u;
        CDC_EP[ep].bufferSize = 0u;
        CDC_EP[ep].interface  = 0u;
        CDC_EP[ep].apiEpState = CDC_NO_EVENT_PENDING;
        CDC_EP[ep].epMode     = CDC_MODE_DISABLE;   
    }

    /* Clear Alternate settings for all interfaces. */
    if (0u != clearAltSetting)
    {
        for (i = 0u; i < CDC_MAX_INTERFACES_NUMBER; ++i)
        {
            CDC_interfaceSetting[i]     = 0u;
            CDC_interfaceSettingLast[i] = 0u;
        }
    }

    /* Init Endpoints and Device Status if configured */
    if (CDC_configuration > 0u)
    {
        #if defined(CDC_ENABLE_CDC_CLASS)
            uint8 cdcComNums = 0u;
        #endif  /* (CDC_ENABLE_CDC_CLASS) */  

        pTmp = CDC_GetConfigTablePtr(CDC_configuration - 1u);
        
        /* Set Power status for current configuration */
        pDescr = (const uint8 *)pTmp->p_list;
        if ((pDescr[CDC_CONFIG_DESCR_ATTRIB] & CDC_CONFIG_DESCR_ATTRIB_SELF_POWERED) != 0u)
        {
            CDC_deviceStatus |= (uint8)  CDC_DEVICE_STATUS_SELF_POWERED;
        }
        else
        {
            CDC_deviceStatus &= (uint8) ~CDC_DEVICE_STATUS_SELF_POWERED;
        }
        
        /* Move to next element */
        pTmp = &pTmp[1u];
        ep = pTmp->c;  /* For this table, c is the number of endpoints configurations  */

        #if (CDC_EP_MANAGEMENT_MANUAL && CDC_EP_ALLOC_DYNAMIC)
            /* Configure for dynamic EP memory allocation */
            /* p_list points the endpoint setting table. */
            pEP = (T_CDC_EP_SETTINGS_BLOCK *) pTmp->p_list;
            
            for (i = 0u; i < ep; i++)
            {     
                /* Compare current Alternate setting with EP Alt */
                if (CDC_interfaceSetting[pEP->interface] == pEP->altSetting)
                {                                                          
                    curEp  = pEP->addr & CDC_DIR_UNUSED;
                    epType = pEP->attributes & CDC_EP_TYPE_MASK;
                    
                    CDC_EP[curEp].addr       = pEP->addr;
                    CDC_EP[curEp].attrib     = pEP->attributes;
                    CDC_EP[curEp].bufferSize = pEP->bufferSize;

                    if (0u != (pEP->addr & CDC_DIR_IN))
                    {
                        /* IN Endpoint */
                        CDC_EP[curEp].epMode     = CDC_GET_ACTIVE_IN_EP_CR0_MODE(epType);
                        CDC_EP[curEp].apiEpState = CDC_EVENT_PENDING;
                    
                    #if (defined(CDC_ENABLE_MIDI_STREAMING) && (CDC_MIDI_IN_BUFF_SIZE > 0))
                        if ((pEP->bMisc == CDC_CLASS_AUDIO) && (epType == CDC_EP_TYPE_BULK))
                        {
                            CDC_midi_in_ep = curEp;
                        }
                    #endif  /* (CDC_ENABLE_MIDI_STREAMING) */
                    }
                    else
                    {
                        /* OUT Endpoint */
                        CDC_EP[curEp].epMode     = CDC_GET_ACTIVE_OUT_EP_CR0_MODE(epType);
                        CDC_EP[curEp].apiEpState = CDC_NO_EVENT_PENDING;
                        
                    #if (defined(CDC_ENABLE_MIDI_STREAMING) && (CDC_MIDI_OUT_BUFF_SIZE > 0))
                        if ((pEP->bMisc == CDC_CLASS_AUDIO) && (epType == CDC_EP_TYPE_BULK))
                        {
                            CDC_midi_out_ep = curEp;
                        }
                    #endif  /* (CDC_ENABLE_MIDI_STREAMING) */
                    }

                #if(defined (CDC_ENABLE_CDC_CLASS))
                    if((pEP->bMisc == CDC_CLASS_CDC_DATA) ||(pEP->bMisc == CDC_CLASS_CDC))
                    {
                        cdcComNums = CDC_Cdc_EpInit(pEP, curEp, cdcComNums);
                    }
                #endif  /* (CDC_ENABLE_CDC_CLASS) */
                }
                
                pEP = &pEP[1u];
            }
            
        #else
            for (i = CDC_EP1; i < CDC_MAX_EP; ++i)
            {
                /* p_list points the endpoint setting table. */
                pEP = (const T_CDC_EP_SETTINGS_BLOCK CYCODE *) pTmp->p_list;
                /* Find max length for each EP and select it (length could be different in different Alt settings) */
                /* but other settings should be correct with regards to Interface alt Setting */
                
                for (curEp = 0u; curEp < ep; ++curEp)
                {
                    if (i == (pEP->addr & CDC_DIR_UNUSED))
                    {
                        /* Compare endpoint buffers size with current size to find greater. */
                        if (CDC_EP[i].bufferSize < pEP->bufferSize)
                        {
                            CDC_EP[i].bufferSize = pEP->bufferSize;
                        }
                        
                        /* Compare current Alternate setting with EP Alt */
                        if (CDC_interfaceSetting[pEP->interface] == pEP->altSetting)
                        {                            
                            CDC_EP[i].addr = pEP->addr;
                            CDC_EP[i].attrib = pEP->attributes;
                            
                            epType = pEP->attributes & CDC_EP_TYPE_MASK;
                            
                            if (0u != (pEP->addr & CDC_DIR_IN))
                            {
                                /* IN Endpoint */
                                CDC_EP[i].epMode     = CDC_GET_ACTIVE_IN_EP_CR0_MODE(epType);
                                CDC_EP[i].apiEpState = CDC_EVENT_PENDING;
                                
                            #if (defined(CDC_ENABLE_MIDI_STREAMING) && (CDC_MIDI_IN_BUFF_SIZE > 0))
                                if ((pEP->bMisc == CDC_CLASS_AUDIO) && (epType == CDC_EP_TYPE_BULK))
                                {
                                    CDC_midi_in_ep = i;
                                }
                            #endif  /* (CDC_ENABLE_MIDI_STREAMING) */
                            }
                            else
                            {
                                /* OUT Endpoint */
                                CDC_EP[i].epMode     = CDC_GET_ACTIVE_OUT_EP_CR0_MODE(epType);
                                CDC_EP[i].apiEpState = CDC_NO_EVENT_PENDING;
                                
                            #if (defined(CDC_ENABLE_MIDI_STREAMING) && (CDC_MIDI_OUT_BUFF_SIZE > 0))
                                if ((pEP->bMisc == CDC_CLASS_AUDIO) && (epType == CDC_EP_TYPE_BULK))
                                {
                                    CDC_midi_out_ep = i;
                                }
                            #endif  /* (CDC_ENABLE_MIDI_STREAMING) */
                            }

                        #if (defined(CDC_ENABLE_CDC_CLASS))
                            if((pEP->bMisc == CDC_CLASS_CDC_DATA) ||(pEP->bMisc == CDC_CLASS_CDC))
                            {
                                cdcComNums = CDC_Cdc_EpInit(pEP, i, cdcComNums);
                            }
                        #endif  /* (CDC_ENABLE_CDC_CLASS) */

                            #if (CDC_EP_MANAGEMENT_DMA_AUTO)
                                break;  /* Use first EP setting in Auto memory management */
                            #endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */
                        }
                    }
                    
                    pEP = &pEP[1u];
                }
            }
        #endif /*  (CDC_EP_MANAGEMENT_MANUAL && CDC_EP_ALLOC_DYNAMIC) */

        /* Init class array for each interface and interface number for each EP.
        *  It is used for handling Class specific requests directed to either an
        *  interface or the endpoint.
        */
        /* p_list points the endpoint setting table. */
        pEP = (const T_CDC_EP_SETTINGS_BLOCK CYCODE *) pTmp->p_list;
        for (i = 0u; i < ep; i++)
        {
            /* Configure interface number for each EP */
            CDC_EP[pEP->addr & CDC_DIR_UNUSED].interface = pEP->interface;
            pEP = &pEP[1u];
        }
        
        /* Init pointer on interface class table */
        CDC_interfaceClass = CDC_GetInterfaceClassTablePtr();
        
    /* Set the endpoint buffer addresses */
    #if (!CDC_EP_MANAGEMENT_DMA_AUTO)
        buffCount = 0u;
        for (ep = CDC_EP1; ep < CDC_MAX_EP; ++ep)
        {
            CDC_EP[ep].buffOffset = buffCount;        
            buffCount += CDC_EP[ep].bufferSize;
            
        #if (CDC_GEN_16BITS_EP_ACCESS)
            /* Align EP buffers to be event size to access 16-bits DR register. */
            buffCount += (0u != (buffCount & 0x01u)) ? 1u : 0u;
        #endif /* (CDC_GEN_16BITS_EP_ACCESS) */            
        }
    #endif /* (!CDC_EP_MANAGEMENT_DMA_AUTO) */

        /* Configure hardware registers */
        CDC_ConfigReg();
    }
}


/*******************************************************************************
* Function Name: CDC_ConfigAltChanged
****************************************************************************//**
*
*  This routine update configuration for the required endpoints only.
*  It is called after SET_INTERFACE request when Static memory allocation used.
*
* \reentrant
*  No.
*
*******************************************************************************/
void CDC_ConfigAltChanged(void) 
{
    uint8 ep;
    uint8 curEp;
    uint8 epType;
    uint8 i;
    uint8 interfaceNum;

    const T_CDC_LUT CYCODE *pTmp;
    const T_CDC_EP_SETTINGS_BLOCK CYCODE *pEP;

    /* Init Endpoints and Device Status if configured */
    if (CDC_configuration > 0u)
    {
        /* Get number of endpoints configurations (ep). */
        pTmp = CDC_GetConfigTablePtr(CDC_configuration - 1u);
        pTmp = &pTmp[1u];
        ep = pTmp->c;

        /* Get pointer to endpoints setting table (pEP). */
        pEP = (const T_CDC_EP_SETTINGS_BLOCK CYCODE *) pTmp->p_list;
        
        /* Look through all possible endpoint configurations. Find endpoints 
        * which belong to current interface and alternate settings for 
        * re-configuration.
        */
        interfaceNum = CDC_interfaceNumber;
        for (i = 0u; i < ep; i++)
        {
            /* Find endpoints which belong to current interface and alternate settings. */
            if ((interfaceNum == pEP->interface) && 
                (CDC_interfaceSetting[interfaceNum] == pEP->altSetting))
            {
                curEp  = ((uint8) pEP->addr & CDC_DIR_UNUSED);
                epType = ((uint8) pEP->attributes & CDC_EP_TYPE_MASK);
                
                /* Change the SIE mode for the selected EP to NAK ALL */
                CDC_EP[curEp].epToggle   = 0u;
                CDC_EP[curEp].addr       = pEP->addr;
                CDC_EP[curEp].attrib     = pEP->attributes;
                CDC_EP[curEp].bufferSize = pEP->bufferSize;

                if (0u != (pEP->addr & CDC_DIR_IN))
                {
                    /* IN Endpoint */
                    CDC_EP[curEp].epMode     = CDC_GET_ACTIVE_IN_EP_CR0_MODE(epType);
                    CDC_EP[curEp].apiEpState = CDC_EVENT_PENDING;
                }
                else
                {
                    /* OUT Endpoint */
                    CDC_EP[curEp].epMode     = CDC_GET_ACTIVE_OUT_EP_CR0_MODE(epType);
                    CDC_EP[curEp].apiEpState = CDC_NO_EVENT_PENDING;
                }
                
                /* Make SIE to NAK any endpoint requests */
                CDC_SIE_EP_BASE.sieEp[curEp].epCr0 = CDC_MODE_NAK_IN_OUT;

            #if (CDC_EP_MANAGEMENT_DMA_AUTO)
                /* Clear IN data ready. */
                CDC_ARB_EP_BASE.arbEp[curEp].epCfg &= (uint8) ~CDC_ARB_EPX_CFG_IN_DATA_RDY;

                /* Select endpoint number of reconfiguration */
                CDC_DYN_RECONFIG_REG = (uint8) ((curEp - 1u) << CDC_DYN_RECONFIG_EP_SHIFT);
                
                /* Request for dynamic re-configuration of endpoint. */
                CDC_DYN_RECONFIG_REG |= CDC_DYN_RECONFIG_ENABLE;
                
                /* Wait until block is ready for re-configuration */
                while (0u == (CDC_DYN_RECONFIG_REG & CDC_DYN_RECONFIG_RDY_STS))
                {
                }
                
                /* Once DYN_RECONFIG_RDY_STS bit is set, FW can change the EP configuration. */
                /* Change EP Type with new direction */
                if (0u != (pEP->addr & CDC_DIR_IN))
                {
                    /* Set endpoint type: 0 - IN and 1 - OUT. */
                    CDC_EP_TYPE_REG &= (uint8) ~(uint8)((uint8) 0x01u << (curEp - 1u));
                    
                #if (CY_PSOC4)
                    /* Clear DMA_TERMIN for IN endpoint */
                    CDC_ARB_EP_BASE.arbEp[curEp].epIntEn &= (uint32) ~CDC_ARB_EPX_INT_DMA_TERMIN;
                #endif /* (CY_PSOC4) */
                }
                else
                {
                    /* Set endpoint type: 0 - IN and 1- OUT. */
                    CDC_EP_TYPE_REG |= (uint8) ((uint8) 0x01u << (curEp - 1u));
                    
                #if (CY_PSOC4)
                    /* Set DMA_TERMIN for OUT endpoint */
                    CDC_ARB_EP_BASE.arbEp[curEp].epIntEn |= (uint32) CDC_ARB_EPX_INT_DMA_TERMIN;
                #endif /* (CY_PSOC4) */
                }
                
                /* Complete dynamic re-configuration: all endpoint related status and signals 
                * are set into the default state.
                */
                CDC_DYN_RECONFIG_REG &= (uint8) ~CDC_DYN_RECONFIG_ENABLE;

            #else
                CDC_SIE_EP_BASE.sieEp[curEp].epCnt0 = HI8(CDC_EP[curEp].bufferSize);
                CDC_SIE_EP_BASE.sieEp[curEp].epCnt1 = LO8(CDC_EP[curEp].bufferSize);
                
                #if (CY_PSOC4)
                    CDC_ARB_EP16_BASE.arbEp[curEp].rwRa16  = (uint32) CDC_EP[curEp].buffOffset;
                    CDC_ARB_EP16_BASE.arbEp[curEp].rwWa16  = (uint32) CDC_EP[curEp].buffOffset;
                #else
                    CDC_ARB_EP_BASE.arbEp[curEp].rwRa    = LO8(CDC_EP[curEp].buffOffset);
                    CDC_ARB_EP_BASE.arbEp[curEp].rwRaMsb = HI8(CDC_EP[curEp].buffOffset);
                    CDC_ARB_EP_BASE.arbEp[curEp].rwWa    = LO8(CDC_EP[curEp].buffOffset);
                    CDC_ARB_EP_BASE.arbEp[curEp].rwWaMsb = HI8(CDC_EP[curEp].buffOffset);
                #endif /* (CY_PSOC4) */                
            #endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */
            }
            
            pEP = &pEP[1u]; /* Get next EP element */
        }
        
        /* The main loop has to re-enable DMA and OUT endpoint */
    }
}


/*******************************************************************************
* Function Name: CDC_GetConfigTablePtr
****************************************************************************//**
*
*  This routine returns a pointer a configuration table entry
*
*  \param confIndex:  Configuration Index
*
* \return
*  Device Descriptor pointer or NULL when descriptor does not exist.
*
*******************************************************************************/
const T_CDC_LUT CYCODE *CDC_GetConfigTablePtr(uint8 confIndex)
                                                        
{
    /* Device Table */
    const T_CDC_LUT CYCODE *pTmp;

    pTmp = (const T_CDC_LUT CYCODE *) CDC_TABLE[CDC_device].p_list;

    /* The first entry points to the Device Descriptor,
    *  the second entry point to the BOS Descriptor
    *  the rest configuration entries.
    *  Set pointer to the first Configuration Descriptor
    */
    pTmp = &pTmp[2u];
    /* For this table, c is the number of configuration descriptors  */
    if(confIndex >= pTmp->c)   /* Verify that required configuration descriptor exists */
    {
        pTmp = (const T_CDC_LUT CYCODE *) NULL;
    }
    else
    {
        pTmp = (const T_CDC_LUT CYCODE *) pTmp[confIndex].p_list;
    }

    return (pTmp);
}


#if (CDC_BOS_ENABLE)
    /*******************************************************************************
    * Function Name: CDC_GetBOSPtr
    ****************************************************************************//**
    *
    *  This routine returns a pointer a BOS table entry
    *
    *  
    *
    * \return
    *  BOS Descriptor pointer or NULL when descriptor does not exist.
    *
    *******************************************************************************/
    const T_CDC_LUT CYCODE *CDC_GetBOSPtr(void)
                                                            
    {
        /* Device Table */
        const T_CDC_LUT CYCODE *pTmp;

        pTmp = (const T_CDC_LUT CYCODE *) CDC_TABLE[CDC_device].p_list;

        /* The first entry points to the Device Descriptor,
        *  the second entry points to the BOS Descriptor
        */
        pTmp = &pTmp[1u];
        pTmp = (const T_CDC_LUT CYCODE *) pTmp->p_list;
        return (pTmp);
    }
#endif /* (CDC_BOS_ENABLE) */


/*******************************************************************************
* Function Name: CDC_GetDeviceTablePtr
****************************************************************************//**
*
*  This routine returns a pointer to the Device table
*
* \return
*  Device Table pointer
*
*******************************************************************************/
const T_CDC_LUT CYCODE *CDC_GetDeviceTablePtr(void)
                                                            
{
    /* Device Table */
    return( (const T_CDC_LUT CYCODE *) CDC_TABLE[CDC_device].p_list );
}


/*******************************************************************************
* Function Name: USB_GetInterfaceClassTablePtr
****************************************************************************//**
*
*  This routine returns Interface Class table pointer, which contains
*  the relation between interface number and interface class.
*
* \return
*  Interface Class table pointer.
*
*******************************************************************************/
const uint8 CYCODE *CDC_GetInterfaceClassTablePtr(void)
                                                        
{
    const T_CDC_LUT CYCODE *pTmp;
    const uint8 CYCODE *pInterfaceClass;
    uint8 currentInterfacesNum;

    pTmp = CDC_GetConfigTablePtr(CDC_configuration - 1u);
    if (pTmp != NULL)
    {
        currentInterfacesNum  = ((const uint8 *) pTmp->p_list)[CDC_CONFIG_DESCR_NUM_INTERFACES];
        /* Third entry in the LUT starts the Interface Table pointers */
        /* The INTERFACE_CLASS table is located after all interfaces */
        pTmp = &pTmp[currentInterfacesNum + 2u];
        pInterfaceClass = (const uint8 CYCODE *) pTmp->p_list;
    }
    else
    {
        pInterfaceClass = (const uint8 CYCODE *) NULL;
    }

    return (pInterfaceClass);
}


/*******************************************************************************
* Function Name: CDC_TerminateEP
****************************************************************************//**
*
*  This function terminates the specified USBFS endpoint.
*  This function should be used before endpoint reconfiguration.
*
*  \param ep Contains the data endpoint number.
*
*  \reentrant
*  No.
*
* \sideeffect
* 
* The device responds with a NAK for any transactions on the selected endpoint.
*   
*******************************************************************************/
void CDC_TerminateEP(uint8 epNumber) 
{
    /* Get endpoint number */
    epNumber &= CDC_DIR_UNUSED;

    if ((epNumber > CDC_EP0) && (epNumber < CDC_MAX_EP))
    {
        /* Set the endpoint Halt */
        CDC_EP[epNumber].hwEpState |= CDC_ENDPOINT_STATUS_HALT;

        /* Clear the data toggle */
        CDC_EP[epNumber].epToggle = 0u;
        CDC_EP[epNumber].apiEpState = CDC_NO_EVENT_ALLOWED;

        if ((CDC_EP[epNumber].addr & CDC_DIR_IN) != 0u)
        {   
            /* IN Endpoint */
            CDC_SIE_EP_BASE.sieEp[epNumber].epCr0 = CDC_MODE_NAK_IN;
        }
        else
        {
            /* OUT Endpoint */
            CDC_SIE_EP_BASE.sieEp[epNumber].epCr0 = CDC_MODE_NAK_OUT;
        }
    }
}


/*******************************************************************************
* Function Name: CDC_SetEndpointHalt
****************************************************************************//**
*
*  This routine handles set endpoint halt.
*
* \return
*  requestHandled.
*
* \reentrant
*  No.
*
*******************************************************************************/
uint8 CDC_SetEndpointHalt(void) 
{
    uint8 requestHandled = CDC_FALSE;
    uint8 ep;
    
    /* Set endpoint halt */
    ep = CDC_wIndexLoReg & CDC_DIR_UNUSED;

    if ((ep > CDC_EP0) && (ep < CDC_MAX_EP))
    {
        /* Set the endpoint Halt */
        CDC_EP[ep].hwEpState |= (CDC_ENDPOINT_STATUS_HALT);

        /* Clear the data toggle */
        CDC_EP[ep].epToggle = 0u;
        CDC_EP[ep].apiEpState |= CDC_NO_EVENT_ALLOWED;

        if ((CDC_EP[ep].addr & CDC_DIR_IN) != 0u)
        {
            /* IN Endpoint */
            CDC_SIE_EP_BASE.sieEp[ep].epCr0 = (CDC_MODE_STALL_DATA_EP | 
                                                            CDC_MODE_ACK_IN);
        }
        else
        {
            /* OUT Endpoint */
            CDC_SIE_EP_BASE.sieEp[ep].epCr0 = (CDC_MODE_STALL_DATA_EP | 
                                                            CDC_MODE_ACK_OUT);
        }
        requestHandled = CDC_InitNoDataControlTransfer();
    }

    return (requestHandled);
}


/*******************************************************************************
* Function Name: CDC_ClearEndpointHalt
****************************************************************************//**
*
*  This routine handles clear endpoint halt.
*
* \return
*  requestHandled.
*
* \reentrant
*  No.
*
*******************************************************************************/
uint8 CDC_ClearEndpointHalt(void) 
{
    uint8 requestHandled = CDC_FALSE;
    uint8 ep;

    /* Clear endpoint halt */
    ep = CDC_wIndexLoReg & CDC_DIR_UNUSED;

    if ((ep > CDC_EP0) && (ep < CDC_MAX_EP))
    {
        /* Clear the endpoint Halt */
        CDC_EP[ep].hwEpState &= (uint8) ~CDC_ENDPOINT_STATUS_HALT;

        /* Clear the data toggle */
        CDC_EP[ep].epToggle = 0u;
        
        /* Clear toggle bit for already armed packet */
        CDC_SIE_EP_BASE.sieEp[ep].epCnt0 &= (uint8) ~(uint8)CDC_EPX_CNT_DATA_TOGGLE;
        
        /* Return API State as it was defined before */
        CDC_EP[ep].apiEpState &= (uint8) ~CDC_NO_EVENT_ALLOWED;

        if ((CDC_EP[ep].addr & CDC_DIR_IN) != 0u)
        {
            /* IN Endpoint */
            if(CDC_EP[ep].apiEpState == CDC_IN_BUFFER_EMPTY)
            {       
                /* Wait for next packet from application */
                CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_NAK_IN;
            }
            else    /* Continue armed transfer */
            {
                CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_ACK_IN;
            }
        }
        else
        {
            /* OUT Endpoint */
            if (CDC_EP[ep].apiEpState == CDC_OUT_BUFFER_FULL)
            {       
                /* Allow application to read full buffer */
                CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_NAK_OUT;
            }
            else    /* Mark endpoint as empty, so it will be reloaded */
            {
                CDC_SIE_EP_BASE.sieEp[ep].epCr0 = CDC_MODE_ACK_OUT;
            }
        }
        
        requestHandled = CDC_InitNoDataControlTransfer();
    }

    return(requestHandled);
}


/*******************************************************************************
* Function Name: CDC_ValidateAlternateSetting
****************************************************************************//**
*
*  Validates (and records) a SET INTERFACE request.
*
* \return
*  requestHandled.
*
* \reentrant
*  No.
*
*******************************************************************************/
uint8 CDC_ValidateAlternateSetting(void) 
{
    uint8 requestHandled = CDC_FALSE;
    
    uint8 interfaceNum;
    uint8 curInterfacesNum;
    const T_CDC_LUT CYCODE *pTmp;
    
    /* Get interface number from the request. */
    interfaceNum = (uint8) CDC_wIndexLoReg;
    
    /* Get number of interfaces for current configuration. */
    pTmp = CDC_GetConfigTablePtr(CDC_configuration - 1u);
    curInterfacesNum  = ((const uint8 *) pTmp->p_list)[CDC_CONFIG_DESCR_NUM_INTERFACES];

    /* Validate that interface number is within range. */
    if ((interfaceNum <= curInterfacesNum) || (interfaceNum <= CDC_MAX_INTERFACES_NUMBER))
    {
        /* Save current and new alternate settings (come with request) to make 
        * desicion about following endpoint re-configuration.
        */
        CDC_interfaceSettingLast[interfaceNum] = CDC_interfaceSetting[interfaceNum];
        CDC_interfaceSetting[interfaceNum]     = (uint8) CDC_wValueLoReg;
        
        requestHandled = CDC_TRUE;
    }

    return (requestHandled);
}


/* [] END OF FILE */
