/*!
 * @file        usbd_descriptor.c
 *
 * @brief       usb device descriptor configuration
 *
 * @version     V1.0.0
 *
 * @date        2025-02-15
 *
 * @attention
 *
 *  Copyright (C) 2025 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

/* Includes ***************************************************************/
#include "usbd_descriptor.h"

/* Private includes *******************************************************/
#include "usbd_composite.h"
#include <stdio.h>
#include <string.h>

/* Private macro **********************************************************/
#define USBD_GEEHY_VID              12619
#define USBD_HS_PID                 0x0120
#define USBD_LANGID_STR             0x0409
#define USBD_MANUFACTURER_STR       "Geehy"
#define USBD_PRODUCT_STR            "APM32 Composite"
#define USBD_CONFIGURATION_STR      "Composite Config"
#define USBD_INTERFACE_STR          "Composite Interface"

/* Private function prototypes ********************************************/
static USBD_DESC_INFO_T USBD_HS_DeviceDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_ConfigDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_ConfigStrDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_InterfaceStrDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_LangIdStrDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_ManufacturerStrDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_ProductStrDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HS_SerialStrDescHandler(uint8_t usbSpeed);
#if USBD_SUP_LPM
static USBD_DESC_INFO_T USBD_HS_BosDescHandler(uint8_t usbSpeed);
#endif
static USBD_DESC_INFO_T USBD_OtherSpeedConfigDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_DevQualifierDescHandler(uint8_t usbSpeed);

/* Private typedef ********************************************************/

/* USB device descripotr handler */
USBD_DESC_T USBD_DESC_HS =
{
    "CDC Descriptor",
    USBD_HS_DeviceDescHandler,
    USBD_HS_ConfigDescHandler,
    USBD_HS_ConfigStrDescHandler,
    USBD_HS_InterfaceStrDescHandler,
    USBD_HS_LangIdStrDescHandler,
    USBD_HS_ManufacturerStrDescHandler,
    USBD_HS_ProductStrDescHandler,
    USBD_HS_SerialStrDescHandler,
#if USBD_SUP_LPM
    USBD_HS_BosDescHandler,
#endif
    NULL,
    USBD_OtherSpeedConfigDescHandler,
    USBD_DevQualifierDescHandler,
};

/* Private variables ******************************************************/

/*!
 * @brief   Device descriptor
 */
uint8_t USBD_DeviceDesc[USBD_DEVICE_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x12,
    /* bDescriptorType */
    USBD_DESC_DEVICE,
    /* bcdUSB */
#if USBD_SUP_LPM
    0x01,            /*<! For resume test of USBCV3.0. Only support LPM USB device */
#else
    0x00,
#endif
    0x02,
    /* bDeviceClass */
    0xEF,
    /* bDeviceSubClass */
    0x02,
    /* bDeviceProtocol */
    0x01,
    /* bMaxPacketSize */
    USBD_EP0_PACKET_MAX_SIZE,
    /* idVendor */
    USBD_GEEHY_VID & 0xFF, USBD_GEEHY_VID >> 8,
    /* idProduct */
    USBD_HS_PID & 0xFF, USBD_HS_PID >> 8,
    /* bcdDevice = 2.00 */
    0x00, 0x02,
    /* Index of string descriptor describing manufacturer */
    USBD_DESC_STR_MFC,
    /* Index of string descriptor describing product */
    USBD_DESC_STR_PRODUCT,
    /* Index of string descriptor describing the device serial number */
    USBD_DESC_STR_SERIAL,
    /* bNumConfigurations */
    USBD_SUP_CONFIGURATION_MAX_NUM,
};

/*!
 * @brief   Configuration descriptor
 */
uint8_t USBD_ConfigDesc[USBD_CONFIG_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_CONFIGURATION,
    /* wTotalLength */
    USBD_CONFIG_DESCRIPTOR_SIZE & 0xFF,
    USBD_CONFIG_DESCRIPTOR_SIZE >> 8,

    /* bNumInterfaces */
    0x04,
    /* bConfigurationValue */
    0x01,
    /* iConfiguration */
    USBD_DESC_STR_PRODUCT,
    /* bmAttributes */
#if USBD_SUP_SELF_PWR
    0xC0,
#else
    0x80,
#endif
    /* MaxPower */
    0x32,

    /********************  CDC1  ********************/
    /********************  Standard Interface Association Descriptor ********************/
    0x08,                                             /* bLength: Interface Descriptor size */
    USBD_DESC_IAD,                                    /* bDescriptorType: */
    USBD_CDC1_CTRL_INTERFACE_NUM,                     /* bFirstInterface */
    USBD_CDC1_INTERFACE_CNT,                          /* bInterfaceCount */
    0x02U,                                            /* bFunctionClass: Communication Interface Class */
    0x02U,                                            /* bFunctionSubClass: Abstract Control Model */
    0x01U,                                            /* bInterfaceProtocol Common AT commands */
    USBD_DESC_STR_PRODUCT,                            /* iFunction */

    /* CDC Command Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC1_CTRL_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x01,
    /* bInterfaceClass */
    USBD_CDC_CTRL_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    USBD_CDC_SUB_CLASS_ACM,
    /* bInterfaceProtocol */
    USBD_CDC_ITF_PORTOCOL_AT,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* CDC Header Function Descriptor */
    /* bLength: Endpoint Descriptor size */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Header Func Desc */
    0x00,
    /* bcdCDC: spec release number */
    0x10, 0x01,

    /* CDC Call Management Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Call Management Func Desc */
    0x01,
    /* bmCapabilities: D0+D1 */
    0x00,
    /* bDataInterface: 1 */
    USBD_CDC1_DATA_INTERFACE_NUM,

    /* CDC ACM Function Descriptor */
    /* bFunctionLength */
    0x04,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Abstract Control Management desc */
    0x02,
    /* bmCapabilities */
    0x02,

    /* CDC Union Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Union func desc */
    0x06,
    /* bMasterInterface: Communication class interface */
    USBD_CDC1_CTRL_INTERFACE_NUM,
    /* bSlaveInterface0: Data Class Interface */
    USBD_CDC1_DATA_INTERFACE_NUM,

    /* Endpoint 2 */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC1_CMD_EP_ADDR,
    /* bmAttributes */
    0x03,
    /* wMaxPacketSize: */
    USBD_CDC_CMD_MP_SIZE & 0xFF,
    USBD_CDC_CMD_MP_SIZE >> 8,
    /* bInterval: */
    USBD_CDC_HS_INTERVAL,

    /* CDC Data Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC1_DATA_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x02,
    /* bInterfaceClass */
    USBD_CDC_DATA_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    0x00,
    /* bInterfaceProtocol */
    0x00,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* Endpoint OUT */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC1_DATA_OUT_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_HS_MP_SIZE & 0xFF,
    USBD_CDC_HS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,

    /* Endpoint IN */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC1_DATA_IN_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_HS_MP_SIZE & 0xFF,
    USBD_CDC_HS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,

    /********************  CDC2  ********************/
    /********************  Standard Interface Association Descriptor ********************/
    0x08,                                             /* bLength: Interface Descriptor size */
    USBD_DESC_IAD,                                    /* bDescriptorType: */
    USBD_CDC2_CTRL_INTERFACE_NUM,                      /* bFirstInterface */
    USBD_CDC2_INTERFACE_CNT,                           /* bInterfaceCount */
    0x02U,                                            /* bFunctionClass: Communication Interface Class */
    0x02U,                                            /* bFunctionSubClass: Abstract Control Model */
    0x01U,                                            /* bInterfaceProtocol Common AT commands */
    USBD_DESC_STR_PRODUCT,                            /* iFunction */

    /* CDC Command Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC2_CTRL_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x00,
    /* bInterfaceClass */
    USBD_CDC_CTRL_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    USBD_CDC_SUB_CLASS_ACM,
    /* bInterfaceProtocol */
    USBD_CDC_ITF_PORTOCOL_AT,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* CDC Header Function Descriptor */
    /* bLength: Endpoint Descriptor size */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Header Func Desc */
    0x00,
    /* bcdCDC: spec release number */
    0x10, 0x01,

    /* CDC Call Management Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Call Management Func Desc */
    0x01,
    /* bmCapabilities: D0+D1 */
    0x00,
    /* bDataInterface: 3 */
    USBD_CDC2_DATA_INTERFACE_NUM,

    /* CDC ACM Function Descriptor */
    /* bFunctionLength */
    0x04,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Abstract Control Management desc */
    0x02,
    /* bmCapabilities */
    0x02,

    /* CDC Union Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Union func desc */
    0x06,
    /* bMasterInterface: Communication class interface */
    USBD_CDC2_CTRL_INTERFACE_NUM,
    /* bSlaveInterface0: Data Class Interface */
    USBD_CDC2_DATA_INTERFACE_NUM,

    /* CDC Data Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC2_DATA_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x02,
    /* bInterfaceClass */
    USBD_CDC_DATA_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    0x00,
    /* bInterfaceProtocol */
    0x00,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* Endpoint OUT */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC2_DATA_OUT_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_HS_MP_SIZE & 0xFF,
    USBD_CDC_HS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,

    /* Endpoint IN */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC2_DATA_IN_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_HS_MP_SIZE & 0xFF,
    USBD_CDC_HS_MP_SIZE >> 8,
    /* bInterval: */
    0x00
};

/*!
 * @brief   Other speed configuration descriptor
 */
uint8_t USBD_OtherSpeedCfgDesc[USBD_CONFIG_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_OTHER_SPEED,
    /* wTotalLength */
    USBD_CONFIG_DESCRIPTOR_SIZE & 0xFF,
    USBD_CONFIG_DESCRIPTOR_SIZE >> 8,

    /* bNumInterfaces */
    0x04,
    /* bConfigurationValue */
    0x01,
    /* iConfiguration */
    USBD_DESC_STR_PRODUCT,
    /* bmAttributes */
#if USBD_SUP_SELF_PWR
    0xC0,
#else
    0x80,
#endif
    /* MaxPower */
    0x32,

    /********************  CDC1  ********************/
    /********************  Standard Interface Association Descriptor ********************/
    0x08,                                             /* bLength: Interface Descriptor size */
    USBD_DESC_IAD,                                    /* bDescriptorType: */
    USBD_CDC1_CTRL_INTERFACE_NUM,                      /* bFirstInterface */
    USBD_CDC1_INTERFACE_CNT,                           /* bInterfaceCount */
    0x02U,                                            /* bFunctionClass: Communication Interface Class */
    0x02U,                                            /* bFunctionSubClass: Abstract Control Model */
    0x01U,                                            /* bInterfaceProtocol Common AT commands */
    USBD_DESC_STR_PRODUCT,                            /* iFunction */

    /* CDC Command Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC1_CTRL_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x01,
    /* bInterfaceClass */
    USBD_CDC_CTRL_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    USBD_CDC_SUB_CLASS_ACM,
    /* bInterfaceProtocol */
    USBD_CDC_ITF_PORTOCOL_AT,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* CDC Header Function Descriptor */
    /* bLength: Endpoint Descriptor size */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Header Func Desc */
    0x00,
    /* bcdCDC: spec release number */
    0x10, 0x01,

    /* CDC Call Management Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Call Management Func Desc */
    0x01,
    /* bmCapabilities: D0+D1 */
    0x00,
    /* bDataInterface: 1 */
    USBD_CDC1_DATA_INTERFACE_NUM,

    /* CDC ACM Function Descriptor */
    /* bFunctionLength */
    0x04,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Abstract Control Management desc */
    0x02,
    /* bmCapabilities */
    0x02,

    /* CDC Union Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Union func desc */
    0x06,
    /* bMasterInterface: Communication class interface */
    USBD_CDC1_CTRL_INTERFACE_NUM,
    /* bSlaveInterface0: Data Class Interface */
    USBD_CDC1_DATA_INTERFACE_NUM,

    /* Endpoint 2 */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC1_CMD_EP_ADDR,
    /* bmAttributes */
    0x03,
    /* wMaxPacketSize: */
    USBD_CDC_CMD_MP_SIZE & 0xFF,
    USBD_CDC_CMD_MP_SIZE >> 8,
    /* bInterval: */
    USBD_CDC_FS_INTERVAL,

    /* CDC Data Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC1_DATA_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x02,
    /* bInterfaceClass */
    USBD_CDC_DATA_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    0x00,
    /* bInterfaceProtocol */
    0x00,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* Endpoint OUT */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC1_DATA_OUT_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_FS_MP_SIZE & 0xFF,
    USBD_CDC_FS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,

    /* Endpoint IN */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC1_DATA_IN_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_FS_MP_SIZE & 0xFF,
    USBD_CDC_FS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,

    /********************  CDC2  ********************/
    /********************  Standard Interface Association Descriptor ********************/
    0x08,                                             /* bLength: Interface Descriptor size */
    USBD_DESC_IAD,                                    /* bDescriptorType: */
    USBD_CDC2_CTRL_INTERFACE_NUM,                      /* bFirstInterface */
    USBD_CDC2_INTERFACE_CNT,                           /* bInterfaceCount */
    0x02U,                                            /* bFunctionClass: Communication Interface Class */
    0x02U,                                            /* bFunctionSubClass: Abstract Control Model */
    0x01U,                                            /* bInterfaceProtocol Common AT commands */
    USBD_DESC_STR_PRODUCT,                            /* iFunction */

    /* CDC Command Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC2_CTRL_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x00,
    /* bInterfaceClass */
    USBD_CDC_CTRL_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    USBD_CDC_SUB_CLASS_ACM,
    /* bInterfaceProtocol */
    USBD_CDC_ITF_PORTOCOL_AT,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* CDC Header Function Descriptor */
    /* bLength: Endpoint Descriptor size */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Header Func Desc */
    0x00,
    /* bcdCDC: spec release number */
    0x10, 0x01,

    /* CDC Call Management Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Call Management Func Desc */
    0x01,
    /* bmCapabilities: D0+D1 */
    0x00,
    /* bDataInterface: 3 */
    USBD_CDC2_DATA_INTERFACE_NUM,

    /* CDC ACM Function Descriptor */
    /* bFunctionLength */
    0x04,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Abstract Control Management desc */
    0x02,
    /* bmCapabilities */
    0x02,

    /* CDC Union Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Union func desc */
    0x06,
    /* bMasterInterface: Communication class interface */
    USBD_CDC2_CTRL_INTERFACE_NUM,
    /* bSlaveInterface0: Data Class Interface */
    USBD_CDC2_DATA_INTERFACE_NUM,

    /* CDC Data Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    USBD_CDC2_DATA_INTERFACE_NUM,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x02,
    /* bInterfaceClass */
    USBD_CDC_DATA_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    0x00,
    /* bInterfaceProtocol */
    0x00,
    /* iInterface */
    USBD_DESC_STR_PRODUCT,

    /* Endpoint OUT */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC2_DATA_OUT_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_FS_MP_SIZE & 0xFF,
    USBD_CDC_FS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,

    /* Endpoint IN */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_CDC2_DATA_IN_EP_ADDR,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    USBD_CDC_FS_MP_SIZE & 0xFF,
    USBD_CDC_FS_MP_SIZE >> 8,
    /* bInterval: */
    0x00,
};

#if USBD_SUP_LPM
/*!
 * @brief   BOS descriptor
 */
uint8_t USBD_BosDesc[USBD_BOS_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x05,
    /* bDescriptorType */
    USBD_DESC_BOS,
    /* wtotalLength */
    0x0C, 0x00,
    /* bNumDeviceCaps */
    0x01,

    /* Device Capability */
    /* bLength */
    0x07,
    /* bDescriptorType */
    USBD_DEVICE_CAPABILITY_TYPE,
    /* bDevCapabilityType */
    USBD_20_EXTENSION_TYPE,
    /* bmAttributes */
    0x02, 0x00, 0x00, 0x00,
};
#endif

/*!
 * @brief   Serial string descriptor
 */
uint8_t USBD_SerialStrDesc[USBD_SERIAL_STRING_SIZE] =
{
    USBD_SERIAL_STRING_SIZE,
    USBD_DESC_STRING,

    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '1', 0
};

/*!
 * @brief   Language ID string descriptor
 */
uint8_t USBD_LandIDStrDesc[USBD_LANGID_STRING_SIZE] =
{
    /* Size */
    USBD_LANGID_STRING_SIZE,
    /* bDescriptorType */
    USBD_DESC_STRING,
    USBD_LANGID_STR & 0xFF, USBD_LANGID_STR >> 8
};

/*!
 * @brief   Device qualifier descriptor
 */
uint8_t USBD_DevQualifierDesc[USBD_DEVICE_QUALIFIER_DESCRIPTOR_SIZE] =
{
    /* Size */
    USBD_DEVICE_QUALIFIER_DESCRIPTOR_SIZE,
    /* bDescriptorType */
    USBD_DESC_DEVICE_QUALIFIER,
    0x00,
    0x02,
    0xEF,
    0x02,
    0x01,
    0x40,
    0x01,
    0x00,
};

/* Private functions ******************************************************/

/*!
 * @brief     USB device convert ascii string descriptor to unicode format
 *
 * @param     desc : descriptor string
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_DESC_Ascii2Unicode(uint8_t* desc)
{
    USBD_DESC_INFO_T descInfo;
    uint8_t* buffer;
    uint8_t str[USBD_SUP_STR_DESC_MAX_NUM];

    uint8_t* unicode = str;
    uint16_t length;
    __IO uint8_t index = 0;

    if (desc == NULL)
    {
        descInfo.desc = NULL;
        descInfo.size = 0;
    }
    else
    {
        buffer = desc;
        length = (strlen((char*)buffer) * 2) + 2;
        /* Get unicode descriptor */
        unicode[index] = length;

        index++;
        unicode[index] = USBD_DESC_STRING;
        index++;

        while (*buffer != '\0')
        {
            unicode[index] = *buffer;
            buffer++;
            index++;

            unicode[index] = 0x00;
            index++;
        }
    }

    descInfo.desc = unicode;
    descInfo.size = length;

    return descInfo;
}

/*!
 * @brief     USB device HS device descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_DeviceDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo.desc = USBD_DeviceDesc;
    descInfo.size = sizeof(USBD_DeviceDesc);

    return descInfo;
}

/*!
 * @brief     USB device HS configuration descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_ConfigDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    USBD_EP_DESC_T *cdc1CmdDesc = USBD_GetEpDesc(USBD_ConfigDesc, USBD_CDC1_CMD_EP_ADDR);
    USBD_EP_DESC_T *cdc1OutDesc = USBD_GetEpDesc(USBD_ConfigDesc, USBD_CDC1_DATA_OUT_EP_ADDR);
    USBD_EP_DESC_T *cdc1InDesc = USBD_GetEpDesc(USBD_ConfigDesc, USBD_CDC1_DATA_IN_EP_ADDR);

    USBD_EP_DESC_T *cdc2OutDesc = USBD_GetEpDesc(USBD_ConfigDesc, USBD_CDC2_DATA_OUT_EP_ADDR); 
    USBD_EP_DESC_T *cdc2InDesc = USBD_GetEpDesc(USBD_ConfigDesc, USBD_CDC2_DATA_IN_EP_ADDR);

    if (usbSpeed == USBD_SPEED_FS)
    {
        if (cdc1CmdDesc != NULL)
        {
            cdc1CmdDesc->bInterval = USBD_CDC_FS_INTERVAL;
        }

        if (cdc1OutDesc != NULL)
        {
            cdc1OutDesc->wMaxPacketSize = USBD_CDC_FS_MP_SIZE;
        }
        
        if (cdc1InDesc != NULL)
        {
            cdc1InDesc->wMaxPacketSize = USBD_CDC_FS_MP_SIZE;
        }

        if (cdc2OutDesc != NULL)
        {
            cdc2OutDesc->wMaxPacketSize = USBD_CDC_FS_MP_SIZE;
        }

        if (cdc2InDesc != NULL)
        {
            cdc2InDesc->wMaxPacketSize = USBD_CDC_FS_MP_SIZE;
        }
    }
    else
    {
        if (cdc1CmdDesc != NULL)
        {
            cdc1CmdDesc->bInterval = USBD_CDC_HS_INTERVAL;
        }

        if (cdc1OutDesc != NULL)
        {
            cdc1OutDesc->wMaxPacketSize = USBD_CDC_HS_MP_SIZE;
        }
        
        if (cdc1InDesc != NULL)
        {
            cdc1InDesc->wMaxPacketSize = USBD_CDC_HS_MP_SIZE;
        }

        if (cdc2OutDesc != NULL)
        {
            cdc2OutDesc->wMaxPacketSize = USBD_CDC_HS_MP_SIZE;
        }

        if (cdc2InDesc != NULL)
        {
            cdc2InDesc->wMaxPacketSize = USBD_CDC_HS_MP_SIZE;
        }
    }

    descInfo.desc = USBD_ConfigDesc;
    descInfo.size = sizeof(USBD_ConfigDesc);

    return descInfo;
}

#if USBD_SUP_LPM
/*!
 * @brief     USB device HS BOS descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_BosDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo.desc = USBD_BosDesc;
    descInfo.size = sizeof(USBD_BosDesc);

    return descInfo;
}
#endif

/*!
 * @brief     USB device HS configuration string descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_ConfigStrDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_CONFIGURATION_STR);

    return descInfo;
}

/*!
 * @brief     USB device HS interface string descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_InterfaceStrDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_INTERFACE_STR);

    return descInfo;
}

/*!
 * @brief     USB device HS LANG ID string descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_LangIdStrDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo.desc = USBD_LandIDStrDesc;
    descInfo.size = sizeof(USBD_LandIDStrDesc);

    return descInfo;
}

/*!
 * @brief     USB device HS manufacturer string descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_ManufacturerStrDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_MANUFACTURER_STR);

    return descInfo;
}

/*!
 * @brief     USB device HS product string descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_ProductStrDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_PRODUCT_STR);

    return descInfo;
}

/*!
 * @brief     USB device HS serial string descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_HS_SerialStrDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    descInfo.desc = USBD_SerialStrDesc;
    descInfo.size = sizeof(USBD_SerialStrDesc);

    return descInfo;
}

/*!
 * @brief     USB device other speed configuration descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_OtherSpeedConfigDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    /* Use FS configuration */
    descInfo.desc = USBD_OtherSpeedCfgDesc;
    descInfo.size = sizeof(USBD_OtherSpeedCfgDesc);

    return descInfo;
}

/*!
 * @brief     USB device device qualifier descriptor
 *
 * @param     usbSpeed : usb speed
 *
 * @retval    usb descriptor information
 */
static USBD_DESC_INFO_T USBD_DevQualifierDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    UNUSED(usbSpeed);

    /* Use FS configuration */
    descInfo.desc = USBD_DevQualifierDesc;
    descInfo.size = sizeof(USBD_DevQualifierDesc);

    return descInfo;
}
