/**
  * @brief  USBD_MSC_Init
  *         Initialize  the mass storage configuration
  * @param  pdev: device instance
  * @param  cfgidx: configuration index
  * @retval status
  */
uint8_t  USBD_MSC_Init (USBD_HandleTypeDef *pdev, 
                            uint8_t cfgidx)
{
  int16_t ret = 0;
   
  if(pdev->dev_speed == USBD_SPEED_HIGH  ) 
  {
    /* Open EP OUT */
    USBD_LL_OpenEP(pdev,
                   MSC_EPOUT_ADDR,
                   USBD_EP_TYPE_BULK,
                   MSC_MAX_HS_PACKET);
    
    /* Open EP IN */
    USBD_LL_OpenEP(pdev,
                   MSC_EPIN_ADDR,
                   USBD_EP_TYPE_BULK,
                   MSC_MAX_HS_PACKET);  
  }
  else
  {
    /* Open EP OUT */
    USBD_LL_OpenEP(pdev,
                   MSC_EPOUT_ADDR,
                   USBD_EP_TYPE_BULK,
                   MSC_MAX_FS_PACKET);
    
    /* Open EP IN */
    USBD_LL_OpenEP(pdev,
                   MSC_EPIN_ADDR,
                   USBD_EP_TYPE_BULK,
                   MSC_MAX_FS_PACKET);  
  }
  pdev->pClassData = USBD_malloc(sizeof (USBD_MSC_BOT_HandleTypeDef));
  
  if(pdev->pClassData == NULL)
  {
    ret = 1; 
  }
  else
  {
    /* Init the BOT  layer */
    MSC_BOT_Init(pdev); 
    ret = 0;
  }
  
  return ret;
}
/**
  * @brief  USBD_AUDIO_Init
  *         Initialize the AUDIO interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_AUDIO_Init (USBD_HandleTypeDef *pdev, 
                               uint8_t cfgidx)
{
  USBD_AUDIO_HandleTypeDef   *haudio;
  
  /* Open EP OUT */
  USBD_LL_OpenEP(pdev,
                 AUDIO_OUT_EP,
                 USBD_EP_TYPE_ISOC,
                 AUDIO_OUT_PACKET);
  
  /* Allocate Audio structure */
  pdev->pClassData = USBD_malloc(sizeof (USBD_AUDIO_HandleTypeDef));
  
  if(pdev->pClassData == NULL)
  {
    return USBD_FAIL; 
  }
  else
  {
    haudio = (USBD_AUDIO_HandleTypeDef*) pdev->pClassData;
    haudio->alt_setting = 0;
    haudio->offset = AUDIO_OFFSET_UNKNOWN;
    haudio->wr_ptr = 0; 
    haudio->rd_ptr = 0;  
    haudio->rd_enable = 0;
    
    /* Initialize the Audio output Hardware layer */
    if (((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->Init(USBD_AUDIO_FREQ, AUDIO_DEFAULT_VOLUME, 0) != USBD_OK)
    {
      return USBD_FAIL;
    }
    
    /* Prepare Out endpoint to receive 1st packet */ 
    USBD_LL_PrepareReceive(pdev,
                           AUDIO_OUT_EP,
                           haudio->buffer,                        
                           AUDIO_OUT_PACKET);      
  }
  return USBD_OK;
}
/**
  * @brief  USBD_DFU_Init
  *         Initialize the DFU interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_DFU_Init (USBD_HandleTypeDef *pdev, 
                               uint8_t cfgidx)
{
  USBD_DFU_HandleTypeDef   *hdfu;
  
 /* Allocate Audio structure */
  pdev->pClassData = USBD_malloc(sizeof (USBD_DFU_HandleTypeDef));
  
  if(pdev->pClassData == NULL)
  {
    return USBD_FAIL; 
  }
  else
  {
    hdfu = pdev->pClassData;
    
    hdfu->alt_setting = 0;
    hdfu->data_ptr = USBD_DFU_APP_DEFAULT_ADD;
    hdfu->wblock_num = 0;
    hdfu->wlength = 0;
    
    hdfu->manif_state = DFU_MANIFEST_COMPLETE;
    hdfu->dev_state = DFU_STATE_IDLE;
    
    hdfu->dev_status[0] = DFU_ERROR_NONE;
    hdfu->dev_status[1] = 0;
    hdfu->dev_status[2] = 0;   
    hdfu->dev_status[3] = 0;
    hdfu->dev_status[4] = DFU_STATE_IDLE;    
    hdfu->dev_status[5] = 0;    
    
    /* Initialize Hardware layer */
    if (((USBD_DFU_MediaTypeDef *)pdev->pUserData)->Init() != USBD_OK)
    {
      return USBD_FAIL;
    }   
  }
  return USBD_OK;
}
/**
  * @brief  USBD_HID_Init
  *         Initialize the HID interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_HID_Init (USBD_HandleTypeDef *pdev, 
                               uint8_t cfgidx)
{
  uint8_t ret = 0;
  
  /* Open EP IN */
  USBD_LL_OpenEP(pdev,
                 HID_EPIN_ADDR,
                 USBD_EP_TYPE_INTR,
                 HID_EPIN_SIZE);  
  
  pdev->pClassData = USBD_malloc(sizeof (USBD_HID_HandleTypeDef));
  
  if(pdev->pClassData == NULL)
  {
    ret = 1; 
  }
  else
  {
    ((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
  }
  return ret;
}
/**
  * @brief  USBD_CUSTOM_HID_Init
  *         Initialize the CUSTOM_HID interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_CUSTOM_HID_Init (USBD_HandleTypeDef *pdev, 
                               uint8_t cfgidx)
{
  uint8_t ret = 0;
  USBD_CUSTOM_HID_HandleTypeDef     *hhid;
  /* Open EP IN */
  USBD_LL_OpenEP(pdev,
                 CUSTOM_HID_EPIN_ADDR,
                 USBD_EP_TYPE_INTR,
                 CUSTOM_HID_EPIN_SIZE);  
  
  /* Open EP OUT */
  USBD_LL_OpenEP(pdev,
                 CUSTOM_HID_EPOUT_ADDR,
                 USBD_EP_TYPE_INTR,
                 CUSTOM_HID_EPOUT_SIZE);
  
  pdev->pClassData = USBD_malloc(sizeof (USBD_CUSTOM_HID_HandleTypeDef));
  
  if(pdev->pClassData == NULL)
  {
    ret = 1; 
  }
  else
  {
    hhid = (USBD_CUSTOM_HID_HandleTypeDef*) pdev->pClassData;
      
    hhid->state = CUSTOM_HID_IDLE;
    ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->Init();
          /* Prepare Out endpoint to receive 1st packet */ 
    USBD_LL_PrepareReceive(pdev, CUSTOM_HID_EPOUT_ADDR, hhid->Report_buf, 
                           USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
  }
    
  return ret;
}
/**
  * @brief  USBD_CDC_Init
  *         Initilaize the CDC interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_CDC_Init (USBD_HandleTypeDef *pdev,
                               uint8_t cfgidx)
{
    uint8_t ret = 0;
    USBD_CDC_HandleTypeDef   *hcdc;

    if(pdev->dev_speed == USBD_SPEED_HIGH  )
    {
        /* Open EP IN */
        USBD_LL_OpenEP(pdev,
                       CDC_IN_EP,
                       USBD_EP_TYPE_BULK,
                       CDC_DATA_HS_IN_PACKET_SIZE);

        /* Open EP OUT */
        USBD_LL_OpenEP(pdev,
                       CDC_OUT_EP,
                       USBD_EP_TYPE_BULK,
                       CDC_DATA_HS_OUT_PACKET_SIZE);

    }
    else
    {
        /* Open EP IN */
        USBD_LL_OpenEP(pdev,
                       CDC_IN_EP,
                       USBD_EP_TYPE_BULK,
                       CDC_DATA_FS_IN_PACKET_SIZE);

        /* Open EP OUT */
        USBD_LL_OpenEP(pdev,
                       CDC_OUT_EP,
                       USBD_EP_TYPE_BULK,
                       CDC_DATA_FS_OUT_PACKET_SIZE);
    }
    /* Open Command IN EP */
    USBD_LL_OpenEP(pdev,
                   CDC_CMD_EP,
                   USBD_EP_TYPE_INTR,
                   CDC_CMD_PACKET_SIZE);


    pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));

    if(pdev->pClassData == NULL)
    {
        ret = 1;
    }
    else
    {
        hcdc = pdev->pClassData;

        /* Init  physical Interface components */
        ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();

        /* Init Xfer states */
        hcdc->TxState =0;
        hcdc->RxState =0;

        if(pdev->dev_speed == USBD_SPEED_HIGH  )
        {
            /* Prepare Out endpoint to receive next packet */
            USBD_LL_PrepareReceive(pdev,
                                   CDC_OUT_EP,
                                   hcdc->RxBuffer,
                                   CDC_DATA_HS_OUT_PACKET_SIZE);
        }
        else
        {
            /* Prepare Out endpoint to receive next packet */
            USBD_LL_PrepareReceive(pdev,
                                   CDC_OUT_EP,
                                   hcdc->RxBuffer,
                                   CDC_DATA_FS_OUT_PACKET_SIZE);
        }


    }
    return ret;
}