/* 
 * The MIT License (MIT)
 *
 * Copyright (c) 2018, hathach (tinyusb.org)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * This file is part of the TinyUSB stack.
 */

#include "tusb_option.h"

#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DESC_AUTO

#include "tusb.h"

//--------------------------------------------------------------------+
// Auto Description Default Configure & Validation
//--------------------------------------------------------------------+

// If HID Generic interface is generated
#define AUTO_DESC_HID_GENERIC    (CFG_TUD_HID && ((CFG_TUD_HID_KEYBOARD && !CFG_TUD_HID_KEYBOARD_BOOT) || \
                                                (CFG_TUD_HID_MOUSE && !CFG_TUD_HID_MOUSE_BOOT)) )
/*------------- VID/PID -------------*/
#ifndef CFG_TUD_DESC_VID
#define CFG_TUD_DESC_VID       0xCAFE
#endif

#ifndef CFG_TUD_DESC_PID

/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
 * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
 *
 * Auto ProductID layout's Bitmap:
 *   [MSB]         HID Generic | Boot Mouse | Boot Keyboard | MSC | CDC          [LSB]
 */
#define _PID_MAP(itf, n)      ( (CFG_TUD_##itf) << (n) )
#define CFG_TUD_DESC_PID      (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
                               _PID_MAP(HID_KEYBOARD, 2) | _PID_MAP(HID_MOUSE, 3) | (AUTO_DESC_HID_GENERIC << 4) )
#endif

//--------------------------------------------------------------------+
// Interface & Endpoint mapping
//--------------------------------------------------------------------+

/*------------- Interface Numbering -------------*/
/* The order as follows: CDC, MSC, Boot Keyboard, Boot Mouse, HID Generic
 * If an interface is not enabled, the later will take its place */

enum
{
#if CFG_TUD_CDC
  ITF_NUM_CDC,
  ITF_NUM_CDC_DATA,
#endif

#if CFG_TUD_MSC
  ITF_NUM_MSC,
#endif

#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
  ITF_NUM_HID_BOOT_KBD,
#endif

#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
  ITF_NUM_HID_BOOT_MSE,
#endif

#if AUTO_DESC_HID_GENERIC
  ITF_NUM_HID_GEN,
#endif

  ITF_NUM_TOTAL
};

enum
{
  ITF_STR_LANGUAGE = 0 ,
  ITF_STR_MANUFACTURER ,
  ITF_STR_PRODUCT      ,
  ITF_STR_SERIAL       ,

#if CFG_TUD_CDC
  ITF_STR_CDC          ,
#endif

#if CFG_TUD_MSC
  ITF_STR_MSC          ,
#endif

#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
  ITF_STR_HID_BOOT_KBD,
#endif

#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
  ITF_STR_HID_BOOT_MSE,
#endif

#if AUTO_DESC_HID_GENERIC
  ITF_STR_HID_GEN,
#endif
};

/*------------- Endpoint Numbering & Size -------------*/
#define _EP_IN(x)               (0x80 | (x))
#define _EP_OUT(x)              (x)

// CDC
#ifdef CFG_TUD_DESC_CDC_EPNUM_NOTIF
  #define EP_CDC_NOTIF            _EP_IN (CFG_TUD_DESC_CDC_EPNUM_NOTIF)
#else
  #define EP_CDC_NOTIF            _EP_IN ( ITF_NUM_CDC+1 )
#endif
#define EP_CDC_NOTIF_SIZE       8

#ifdef CFG_TUD_DESC_CDC_EPNUM
  #define EP_CDC_OUT              _EP_OUT( CFG_TUD_DESC_CDC_EPNUM )
  #define EP_CDC_IN               _EP_IN ( CFG_TUD_DESC_CDC_EPNUM )
#else
  #define EP_CDC_OUT              _EP_OUT( ITF_NUM_CDC+2 )
  #define EP_CDC_IN               _EP_IN ( ITF_NUM_CDC+2 )
#endif

// Mass Storage
#ifdef CFG_TUD_DESC_MSC_EPNUM
  #define EP_MSC_OUT              _EP_OUT( CFG_TUD_DESC_MSC_EPNUM )
  #define EP_MSC_IN               _EP_IN ( CFG_TUD_DESC_MSC_EPNUM )
#else
  #define EP_MSC_OUT              _EP_OUT( ITF_NUM_MSC+1 )
  #define EP_MSC_IN               _EP_IN ( ITF_NUM_MSC+1 )
#endif

#if TUD_OPT_HIGH_SPEED
#define EP_MSC_SIZE 512
#else
#define EP_MSC_SIZE 64
#endif


// HID Keyboard with boot protocol
#ifdef CFG_TUD_DESC_HID_KEYBOARD_EPNUM
  #define EP_HID_KBD_BOOT         _EP_IN ( CFG_TUD_DESC_HID_KEYBOARD_EPNUM )
#else
  #define EP_HID_KBD_BOOT         _EP_IN ( ITF_NUM_HID_BOOT_KBD+1 )
#endif
#define EP_HID_KBD_BOOT_SZ      8

// HID Mouse with boot protocol
#ifdef CFG_TUD_DESC_HID_MOUSE_EPNUM
  #define EP_HID_MSE_BOOT         _EP_IN ( CFG_TUD_DESC_HID_MOUSE_EPNUM )
#else
  #define EP_HID_MSE_BOOT         _EP_IN ( ITF_NUM_HID_BOOT_MSE+1 )
#endif
#define EP_HID_MSE_BOOT_SZ      8

// HID composite = keyboard + mouse + gamepad + etc ...
#define EP_HID_GEN              _EP_IN ( ITF_NUM_HID_GEN+1 )
#define EP_HID_GEN_SIZE         16


//--------------------------------------------------------------------+
// Auto generated HID Report Descriptors
//--------------------------------------------------------------------+


/*------------- Boot Protocol Report Descriptor -------------*/
#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
uint8_t const _desc_auto_hid_boot_kbd_report[] = { HID_REPORT_DESC_KEYBOARD() };
#endif

#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
uint8_t const _desc_auto_hid_boot_mse_report[] = { HID_REPORT_DESC_MOUSE() };
#endif


/*------------- Generic (composite) Descriptor -------------*/
#if AUTO_DESC_HID_GENERIC

// Report ID: 0 if there is only 1 report
// starting from 1 if there is multiple reports
#define _REPORT_ID_KBD

// TODO report ID
uint8_t const _desc_auto_hid_generic_report[] =
{
#if CFG_TUD_HID_KEYBOARD && !CFG_TUD_HID_KEYBOARD_BOOT
    HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ),
#endif

#if CFG_TUD_HID_MOUSE && !CFG_TUD_HID_MOUSE_BOOT
    HID_REPORT_DESC_MOUSE( HID_REPORT_ID(2), )
#endif

};

#endif // hid generic


/*------------------------------------------------------------------*/
/* Auto generated Device & Configuration descriptor
 *------------------------------------------------------------------*/

// For highspeed device but currently in full speed mode
//tusb_desc_device_qualifier_t _device_qual =
//{
//    .bLength = sizeof(tusb_desc_device_qualifier_t),
//    .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
//    .bcdUSB = 0x0200,
//    .bDeviceClass =
//};

/*------------- Device Descriptor -------------*/
tusb_desc_device_t const _desc_auto_device =
{
    .bLength            = sizeof(tusb_desc_device_t),
    .bDescriptorType    = TUSB_DESC_DEVICE,
    .bcdUSB             = 0x0200,

  #if CFG_TUD_CDC
    // Use Interface Association Descriptor (IAD) for CDC
    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
    .bDeviceClass       = TUSB_CLASS_MISC,
    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
  #else
    .bDeviceClass       = 0x00,
    .bDeviceSubClass    = 0x00,
    .bDeviceProtocol    = 0x00,
  #endif

    .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,

    .idVendor           = CFG_TUD_DESC_VID,
    .idProduct          = CFG_TUD_DESC_PID,
    .bcdDevice          = 0x0100,

    .iManufacturer      = 0x01,
    .iProduct           = 0x02,
    .iSerialNumber      = 0x03,

    .bNumConfigurations = 0x01
};


/*------------- Configuration Descriptor -------------*/
typedef struct ATTR_PACKED
{
  tusb_desc_configuration_t           config;

  //------------- CDC -------------//
#if CFG_TUD_CDC
  struct ATTR_PACKED
  {
    tusb_desc_interface_assoc_t       iad;

    //CDC Control Interface
    tusb_desc_interface_t             comm_itf;
    cdc_desc_func_header_t            header;
    cdc_desc_func_call_management_t   call;
    cdc_desc_func_acm_t               acm;
    cdc_desc_func_union_t             union_func;
    tusb_desc_endpoint_t              ep_notif;

    //CDC Data Interface
    tusb_desc_interface_t             data_itf;
    tusb_desc_endpoint_t              ep_out;
    tusb_desc_endpoint_t              ep_in;
  }cdc;
#endif

  //------------- Mass Storage -------------//
#if CFG_TUD_MSC
  struct ATTR_PACKED
  {
    tusb_desc_interface_t             itf;
    tusb_desc_endpoint_t              ep_out;
    tusb_desc_endpoint_t              ep_in;
  } msc;
#endif

  //------------- HID -------------//
#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
  struct ATTR_PACKED
  {
    tusb_desc_interface_t             itf;
    tusb_hid_descriptor_hid_t         hid_desc;
    tusb_desc_endpoint_t              ep_in;
  } hid_kbd_boot;
#endif

#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
  struct ATTR_PACKED
  {
    tusb_desc_interface_t             itf;
    tusb_hid_descriptor_hid_t         hid_desc;
    tusb_desc_endpoint_t              ep_in;
  } hid_mse_boot;
#endif

#if AUTO_DESC_HID_GENERIC

  struct ATTR_PACKED
  {
    tusb_desc_interface_t             itf;
    tusb_hid_descriptor_hid_t         hid_desc;
    tusb_desc_endpoint_t              ep_in;

    #if 0 //  CFG_TUD_HID_KEYBOARD
    tusb_desc_endpoint_t              ep_out;
    #endif
  } hid_generic;

#endif

} desc_auto_cfg_t;

desc_auto_cfg_t const _desc_auto_config_struct =
{
    .config =
    {
        .bLength             = sizeof(tusb_desc_configuration_t),
        .bDescriptorType     = TUSB_DESC_CONFIGURATION,

        .wTotalLength        = sizeof(desc_auto_cfg_t),
        .bNumInterfaces      = ITF_NUM_TOTAL,

        .bConfigurationValue = 1,
        .iConfiguration      = 0x00,
        .bmAttributes        = TU_BIT(7) | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
        .bMaxPower           = TUSB_DESC_CONFIG_POWER_MA(100)
    },

#if CFG_TUD_CDC
    // IAD points to CDC Interfaces
    .cdc =
    {
      .iad =
      {
          .bLength           = sizeof(tusb_desc_interface_assoc_t),
          .bDescriptorType   = TUSB_DESC_INTERFACE_ASSOCIATION,

          .bFirstInterface   = ITF_NUM_CDC,
          .bInterfaceCount   = 2,

          .bFunctionClass    = TUSB_CLASS_CDC,
          .bFunctionSubClass = CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
          .bFunctionProtocol = CDC_COMM_PROTOCOL_ATCOMMAND,
          .iFunction         = 0
      },

      //------------- CDC Communication Interface -------------//
      .comm_itf =
      {
          .bLength            = sizeof(tusb_desc_interface_t),
          .bDescriptorType    = TUSB_DESC_INTERFACE,
          .bInterfaceNumber   = ITF_NUM_CDC,
          .bAlternateSetting  = 0,
          .bNumEndpoints      = 1,
          .bInterfaceClass    = TUSB_CLASS_CDC,
          .bInterfaceSubClass = CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
          .bInterfaceProtocol = CDC_COMM_PROTOCOL_ATCOMMAND,
          .iInterface         = 4
      },

      .header =
      {
          .bLength            = sizeof(cdc_desc_func_header_t),
          .bDescriptorType    = TUSB_DESC_CLASS_SPECIFIC,
          .bDescriptorSubType = CDC_FUNC_DESC_HEADER,
          .bcdCDC             = 0x0120
      },

      .call =
      {
          .bLength            = sizeof(cdc_desc_func_call_management_t),
          .bDescriptorType    = TUSB_DESC_CLASS_SPECIFIC,
          .bDescriptorSubType = CDC_FUNC_DESC_CALL_MANAGEMENT,
          .bmCapabilities     = { 0 },
          .bDataInterface     = ITF_NUM_CDC+1,
      },

      .acm =
      {
          .bLength            = sizeof(cdc_desc_func_acm_t),
          .bDescriptorType    = TUSB_DESC_CLASS_SPECIFIC,
          .bDescriptorSubType = CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT,
          .bmCapabilities     = { // 0x02
              .support_line_request = 1,
          }
      },

      .union_func =
      {
          .bLength                  = sizeof(cdc_desc_func_union_t), // plus number of
          .bDescriptorType          = TUSB_DESC_CLASS_SPECIFIC,
          .bDescriptorSubType       = CDC_FUNC_DESC_UNION,
          .bControlInterface        = ITF_NUM_CDC,
          .bSubordinateInterface    = ITF_NUM_CDC+1,
      },

      .ep_notif =
      {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_CDC_NOTIF,
          .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
          .wMaxPacketSize   = { .size = EP_CDC_NOTIF_SIZE },
          .bInterval        = 0x10
      },

      //------------- CDC Data Interface -------------//
      .data_itf =
      {
          .bLength            = sizeof(tusb_desc_interface_t),
          .bDescriptorType    = TUSB_DESC_INTERFACE,
          .bInterfaceNumber   = ITF_NUM_CDC+1,
          .bAlternateSetting  = 0x00,
          .bNumEndpoints      = 2,
          .bInterfaceClass    = TUSB_CLASS_CDC_DATA,
          .bInterfaceSubClass = 0,
          .bInterfaceProtocol = 0,
          .iInterface         = 0x00
      },

      .ep_out =
      {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_CDC_OUT,
          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
          .wMaxPacketSize   = { .size = CFG_TUD_CDC_EPSIZE },
          .bInterval        = 0
      },

      .ep_in =
      {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_CDC_IN,
          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
          .wMaxPacketSize   = { .size = CFG_TUD_CDC_EPSIZE },
          .bInterval        = 0
      },
    },
#endif // cdc

#if CFG_TUD_MSC
    //------------- Mass Storage-------------//
    .msc =
    {
      .itf =
      {
          .bLength            = sizeof(tusb_desc_interface_t),
          .bDescriptorType    = TUSB_DESC_INTERFACE,
          .bInterfaceNumber   = ITF_NUM_MSC,
          .bAlternateSetting  = 0x00,
          .bNumEndpoints      = 2,
          .bInterfaceClass    = TUSB_CLASS_MSC,
          .bInterfaceSubClass = MSC_SUBCLASS_SCSI,
          .bInterfaceProtocol = MSC_PROTOCOL_BOT,
          .iInterface         = 4 + CFG_TUD_CDC
      },

      .ep_out =
      {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_MSC_OUT,
          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
          .wMaxPacketSize   = { .size = EP_MSC_SIZE},
          .bInterval        = 1
      },

      .ep_in =
      {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_MSC_IN,
          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
          .wMaxPacketSize   = { .size = EP_MSC_SIZE},
          .bInterval        = 1
      }
    },
#endif // msc

#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
    .hid_kbd_boot =
    {
        .itf =
        {
          .bLength            = sizeof(tusb_desc_interface_t),
          .bDescriptorType    = TUSB_DESC_INTERFACE,
          .bInterfaceNumber   = ITF_NUM_HID_BOOT_KBD,
          .bAlternateSetting  = 0x00,
          .bNumEndpoints      = 1,
          .bInterfaceClass    = TUSB_CLASS_HID,
          .bInterfaceSubClass = HID_SUBCLASS_BOOT,
          .bInterfaceProtocol = HID_PROTOCOL_KEYBOARD,
          .iInterface         = 0 //4 + CFG_TUD_CDC + CFG_TUD_MSC
        },

        .hid_desc =
        {
          .bLength         = sizeof(tusb_hid_descriptor_hid_t),
          .bDescriptorType = HID_DESC_TYPE_HID,
          .bcdHID          = 0x0111,
          .bCountryCode    = HID_Local_NotSupported,
          .bNumDescriptors = 1,
          .bReportType     = HID_DESC_TYPE_REPORT,
          .wReportLength   = sizeof(_desc_auto_hid_boot_kbd_report)
        },

        .ep_in =
        {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_HID_KBD_BOOT,
          .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
          .wMaxPacketSize   = { .size = EP_HID_KBD_BOOT_SZ },
          .bInterval        = 0x0A
        }
    },
#endif // boot keyboard

  //------------- HID Mouse -------------//
#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
    .hid_mse_boot =
    {
        .itf =
        {
          .bLength            = sizeof(tusb_desc_interface_t),
          .bDescriptorType    = TUSB_DESC_INTERFACE,
          .bInterfaceNumber   = ITF_NUM_HID_BOOT_MSE,
          .bAlternateSetting  = 0x00,
          .bNumEndpoints      = 1,
          .bInterfaceClass    = TUSB_CLASS_HID,
          .bInterfaceSubClass = HID_SUBCLASS_BOOT,
          .bInterfaceProtocol = HID_PROTOCOL_MOUSE,
          .iInterface         = 0 // 4 + CFG_TUD_CDC + CFG_TUD_MSC + CFG_TUD_HID_KEYBOARD
        },

        .hid_desc =
        {
          .bLength         = sizeof(tusb_hid_descriptor_hid_t),
          .bDescriptorType = HID_DESC_TYPE_HID,
          .bcdHID          = 0x0111,
          .bCountryCode    = HID_Local_NotSupported,
          .bNumDescriptors = 1,
          .bReportType     = HID_DESC_TYPE_REPORT,
          .wReportLength   = sizeof(_desc_auto_hid_boot_mse_report)
        },

        .ep_in =
        {
          .bLength          = sizeof(tusb_desc_endpoint_t),
          .bDescriptorType  = TUSB_DESC_ENDPOINT,
          .bEndpointAddress = EP_HID_MSE_BOOT,
          .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
          .wMaxPacketSize   = { .size = EP_HID_MSE_BOOT_SZ },
          .bInterval        = 0x0A
        },
    },

#endif // boot mouse

#if AUTO_DESC_HID_GENERIC
    //------------- HID Generic Multiple report -------------//
    .hid_generic =
    {
        .itf =
        {
            .bLength            = sizeof(tusb_desc_interface_t),
            .bDescriptorType    = TUSB_DESC_INTERFACE,
            .bInterfaceNumber   = ITF_NUM_HID_GEN,
            .bAlternateSetting  = 0x00,
            .bNumEndpoints      = 1,
            .bInterfaceClass    = TUSB_CLASS_HID,
            .bInterfaceSubClass = 0,
            .bInterfaceProtocol = 0,
            .iInterface         = 0, // 4 + CFG_TUD_CDC + CFG_TUD_MSC,
        },

        .hid_desc =
        {
            .bLength           = sizeof(tusb_hid_descriptor_hid_t),
            .bDescriptorType   = HID_DESC_TYPE_HID,
            .bcdHID            = 0x0111,
            .bCountryCode      = HID_Local_NotSupported,
            .bNumDescriptors   = 1,
            .bReportType       = HID_DESC_TYPE_REPORT,
            .wReportLength     = sizeof(_desc_auto_hid_generic_report)
        },

        .ep_in =
        {
            .bLength          = sizeof(tusb_desc_endpoint_t),
            .bDescriptorType  = TUSB_DESC_ENDPOINT,
            .bEndpointAddress = EP_HID_GEN,
            .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
            .wMaxPacketSize   = { .size = EP_HID_GEN_SIZE },
            .bInterval        = 0x0A
        }
    }
#endif // hid generic
};

uint8_t const * const _desc_auto_config = (uint8_t const*) &_desc_auto_config_struct;

tud_desc_set_t const _usbd_auto_desc_set =
{
    .device = &_desc_auto_device,
    .config = &_desc_auto_config_struct,

    .hid_report =
    {
#if AUTO_DESC_HID_GENERIC
        .generic = _desc_auto_hid_generic_report,
#else
        .generic = NULL,
#endif

#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
        .boot_keyboard = _desc_auto_hid_boot_kbd_report,
#endif

#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
        .boot_mouse = _desc_auto_hid_boot_mse_report
#endif
    }
};

#endif
