~ruther/qmk_firmware

ac1672689599ff7180b3baaaa9a1356e0e23021e — fauxpark 6 years ago 21df614
LUFA USB descriptor cleanup (#4871)

* Fix indentation

* Fix braces

* Expand descriptor headers

* Align descriptor elements

* Nicer formatting

* Tidy up preprocessor statements

* Remove VERSION_BCD redefine - LUFA_VERSION_INTEGER is currently 0x170418

* Tidy up comments

* Tweak ordering of  HID report elements (no functional changes)

* We don't need all of these newlines

* Move default USB_MAX_POWER_CONSUMPTION closer to where it makes sense

* Ask nicely

* Add some more comments

* Change indentation back to 4 spaces

* Add changelog entry
A docs/ChangeLog/20190830/PR4871.md => docs/ChangeLog/20190830/PR4871.md +4 -0
@@ 0,0 1,4 @@
* LUFA USB descriptor cleanup
    * Some code cleanups related to the USB HID descriptors on AVR keyboards, to make them easier to read and understand
    * More information: see https://github.com/qmk/qmk_firmware/pull/4871
    * No behaviour changes anticipated and no keymaps modified

M tmk_core/protocol/usb_descriptor.c => tmk_core/protocol/usb_descriptor.c +698 -705
@@ 6,238 6,242 @@
 */

/*
             LUFA Library
     Copyright (C) Dean Camera, 2012.
                         LUFA Library
         Copyright (C) Dean Camera, 2012.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
    dean [at] fourwalledcubicle [dot] com
                     www.lufa-lib.org
*/

/*
  Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
  Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
    Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
    Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)

    Permission to use, copy, modify, distribute, and sell this
    software and its documentation for any purpose is hereby granted
    without fee, provided that the above copyright notice appear in
    all copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.
*/

#include "util.h"
#include "report.h"
#include "usb_descriptor.h"

#ifndef USB_MAX_POWER_CONSUMPTION
#define USB_MAX_POWER_CONSUMPTION 500
#endif

/*******************************************************************************
 * HID Report Descriptors
 ******************************************************************************/
/*
 * HID report descriptors
 */
#ifdef KEYBOARD_SHARED_EP
const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
#define SHARED_REPORT_STARTED
    #define SHARED_REPORT_STARTED
#else
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = {
#endif
    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
    HID_RI_USAGE(8, 0x06), /* Keyboard */
    HID_RI_COLLECTION(8, 0x01), /* Application */
#   ifdef KEYBOARD_SHARED_EP
    HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
    HID_RI_USAGE(8, 0x06), // Keyboard
    HID_RI_COLLECTION(8, 0x01), // Application
#ifdef KEYBOARD_SHARED_EP
        HID_RI_REPORT_ID(8, REPORT_ID_KEYBOARD),
#   endif
        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
        HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
        HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
#endif
        // Modifiers (8 bits)
        HID_RI_USAGE_PAGE(8, 0x07), // Keyboard/Keypad
        HID_RI_USAGE_MINIMUM(8, 0xE0), // Keyboard Left Control
        HID_RI_USAGE_MAXIMUM(8, 0xE7), // Keyboard Right GUI
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
        HID_RI_REPORT_COUNT(8, 0x08),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),

        // Reserved (1 byte)
        HID_RI_REPORT_COUNT(8, 0x01),
        HID_RI_REPORT_SIZE(8, 0x08),
        HID_RI_INPUT(8, HID_IOF_CONSTANT),  /* reserved */
        HID_RI_INPUT(8, HID_IOF_CONSTANT),
        // Keycodes (6 bytes)
        HID_RI_USAGE_PAGE(8, 0x07), // Keyboard/Keypad
        HID_RI_USAGE_MINIMUM(8, 0x00),
        HID_RI_USAGE_MAXIMUM(8, 0xFF),
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
        HID_RI_REPORT_COUNT(8, 0x06),
        HID_RI_REPORT_SIZE(8, 0x08),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),

        HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
        HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
        HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
        // Status LEDs (5 bits)
        HID_RI_USAGE_PAGE(8, 0x08), // LED
        HID_RI_USAGE_MINIMUM(8, 0x01), // Num Lock
        HID_RI_USAGE_MAXIMUM(8, 0x05), // Kana
        HID_RI_REPORT_COUNT(8, 0x05),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
        // LED padding (3 bits)
        HID_RI_REPORT_COUNT(8, 0x01),
        HID_RI_REPORT_SIZE(8, 0x03),
        HID_RI_OUTPUT(8, HID_IOF_CONSTANT),

        HID_RI_USAGE_PAGE(8, 0x07), /* Keyboard */
        HID_RI_USAGE_MINIMUM(8, 0x00), /* Reserved (no event indicated) */
        HID_RI_USAGE_MAXIMUM(8, 0xFF), /* Keyboard Application */
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
        HID_RI_REPORT_COUNT(8, 0x06),
        HID_RI_REPORT_SIZE(8, 0x08),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
    HID_RI_END_COLLECTION(0),

#ifndef KEYBOARD_SHARED_EP
};
#endif

#if defined(MOUSE_ENABLE)

#   if !defined(MOUSE_SHARED_EP)
#ifdef MOUSE_ENABLE
    #ifndef MOUSE_SHARED_EP
const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] = {
#   elif !defined(SHARED_REPORT_STARTED)
    #elif !defined(SHARED_REPORT_STARTED)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
#define SHARED_REPORT_STARTED
#   endif
    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
    HID_RI_USAGE(8, 0x02), /* Mouse */
    HID_RI_COLLECTION(8, 0x01), /* Application */
#   ifdef MOUSE_SHARED_EP
        #define SHARED_REPORT_STARTED
    #endif
    HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
    HID_RI_USAGE(8, 0x02), // Mouse
    HID_RI_COLLECTION(8, 0x01), // Application
    #ifdef MOUSE_SHARED_EP
        HID_RI_REPORT_ID(8, REPORT_ID_MOUSE),
#   endif
        HID_RI_USAGE(8, 0x01), /* Pointer */
        HID_RI_COLLECTION(8, 0x00), /* Physical */

            HID_RI_USAGE_PAGE(8, 0x09), /* Button */
            HID_RI_USAGE_MINIMUM(8, 0x01),  /* Button 1 */
            HID_RI_USAGE_MAXIMUM(8, 0x05),  /* Button 5 */
    #endif
        HID_RI_USAGE(8, 0x01), // Pointer
        HID_RI_COLLECTION(8, 0x00), // Physical
            // Buttons (5 bits)
            HID_RI_USAGE_PAGE(8, 0x09), // Button
            HID_RI_USAGE_MINIMUM(8, 0x01), // Button 1
            HID_RI_USAGE_MAXIMUM(8, 0x05), // Button 5
            HID_RI_LOGICAL_MINIMUM(8, 0x00),
            HID_RI_LOGICAL_MAXIMUM(8, 0x01),
            HID_RI_REPORT_COUNT(8, 0x05),
            HID_RI_REPORT_SIZE(8, 0x01),
            HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
            // Button padding (3 bits)
            HID_RI_REPORT_COUNT(8, 0x01),
            HID_RI_REPORT_SIZE(8, 0x03),
            HID_RI_INPUT(8, HID_IOF_CONSTANT),

            HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
            HID_RI_USAGE(8, 0x30), /* Usage X */
            HID_RI_USAGE(8, 0x31), /* Usage Y */
            // X/Y position (2 bytes)
            HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
            HID_RI_USAGE(8, 0x30), // X
            HID_RI_USAGE(8, 0x31), // Y
            HID_RI_LOGICAL_MINIMUM(8, -127),
            HID_RI_LOGICAL_MAXIMUM(8, 127),
            HID_RI_REPORT_COUNT(8, 0x02),
            HID_RI_REPORT_SIZE(8, 0x08),
            HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),

            HID_RI_USAGE(8, 0x38), /* Wheel */
            // Vertical wheel (1 byte)
            HID_RI_USAGE(8, 0x38), // Wheel
            HID_RI_LOGICAL_MINIMUM(8, -127),
            HID_RI_LOGICAL_MAXIMUM(8, 127),
            HID_RI_REPORT_COUNT(8, 0x01),
            HID_RI_REPORT_SIZE(8, 0x08),
            HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),

            HID_RI_USAGE_PAGE(8, 0x0C), /* Consumer */
            HID_RI_USAGE(16, 0x0238), /* AC Pan (Horizontal wheel) */
            // Horizontal wheel (1 byte)
            HID_RI_USAGE_PAGE(8, 0x0C), // Consumer
            HID_RI_USAGE(16, 0x0238), // AC Pan
            HID_RI_LOGICAL_MINIMUM(8, -127),
            HID_RI_LOGICAL_MAXIMUM(8, 127),
            HID_RI_REPORT_COUNT(8, 0x01),
            HID_RI_REPORT_SIZE(8, 0x08),
            HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),

        HID_RI_END_COLLECTION(0),
    HID_RI_END_COLLECTION(0),
#   ifndef MOUSE_SHARED_EP
    #ifndef MOUSE_SHARED_EP
};
#   endif
    #endif
#endif

#if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
#endif
#   ifdef EXTRAKEY_ENABLE
    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
    HID_RI_USAGE(8, 0x80), /* System Control */
    HID_RI_COLLECTION(8, 0x01), /* Application */

#ifdef EXTRAKEY_ENABLE
    HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
    HID_RI_USAGE(8, 0x80), // System Control
    HID_RI_COLLECTION(8, 0x01), // Application
        HID_RI_REPORT_ID(8, REPORT_ID_SYSTEM),
        HID_RI_USAGE_MINIMUM(16, 0x0081), // System Power Down
        HID_RI_USAGE_MAXIMUM(16, 0x0083), // System Wake Up
        HID_RI_LOGICAL_MINIMUM(16, 0x0001),
        HID_RI_LOGICAL_MAXIMUM(16, 0x0003),
        HID_RI_USAGE_MINIMUM(16, 0x0081), /* System Power Down */
        HID_RI_USAGE_MAXIMUM(16, 0x0083), /* System Wake Up */
        HID_RI_REPORT_SIZE(8, 16),
        HID_RI_REPORT_COUNT(8, 1),
        HID_RI_REPORT_SIZE(8, 16),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
    HID_RI_END_COLLECTION(0),

    HID_RI_USAGE_PAGE(8, 0x0C), /* Consumer */
    HID_RI_USAGE(8, 0x01), /* Consumer Control */
    HID_RI_COLLECTION(8, 0x01), /* Application */
    HID_RI_USAGE_PAGE(8, 0x0C), // Consumer
    HID_RI_USAGE(8, 0x01), // Consumer Control
    HID_RI_COLLECTION(8, 0x01), // Application
        HID_RI_REPORT_ID(8, REPORT_ID_CONSUMER),
        HID_RI_USAGE_MINIMUM(16, 0x0001), // Consumer Control
        HID_RI_USAGE_MAXIMUM(16, 0x029C), // AC Distribute Vertically
        HID_RI_LOGICAL_MINIMUM(16, 0x0001),
        HID_RI_LOGICAL_MAXIMUM(16, 0x029C),
        HID_RI_USAGE_MINIMUM(16, 0x0001), /* +10 */
        HID_RI_USAGE_MAXIMUM(16, 0x029C), /* AC Distribute Vertically */
        HID_RI_REPORT_SIZE(8, 16),
        HID_RI_REPORT_COUNT(8, 1),
        HID_RI_REPORT_SIZE(8, 16),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
    HID_RI_END_COLLECTION(0),
#   endif
#endif

#   ifdef NKRO_ENABLE
    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
    HID_RI_USAGE(8, 0x06), /* Keyboard */
    HID_RI_COLLECTION(8, 0x01), /* Application */
#ifdef NKRO_ENABLE
    HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
    HID_RI_USAGE(8, 0x06), // Keyboard
    HID_RI_COLLECTION(8, 0x01), // Application
        HID_RI_REPORT_ID(8, REPORT_ID_NKRO),
        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
        HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
        HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
        // Modifiers (8 bits)
        HID_RI_USAGE_PAGE(8, 0x07), // Keyboard/Keypad
        HID_RI_USAGE_MINIMUM(8, 0xE0), // Keyboard Left Control
        HID_RI_USAGE_MAXIMUM(8, 0xE7), // Keyboard Right GUI
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
        HID_RI_REPORT_COUNT(8, 0x08),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
        // Keycodes
        HID_RI_USAGE_PAGE(8, 0x07), // Keyboard/Keypad
        HID_RI_USAGE_MINIMUM(8, 0x00),
        HID_RI_USAGE_MAXIMUM(8, KEYBOARD_REPORT_BITS * 8 - 1),
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
        HID_RI_REPORT_COUNT(8, KEYBOARD_REPORT_BITS * 8),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),

        HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
        HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
        HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
        // Status LEDs (5 bits)
        HID_RI_USAGE_PAGE(8, 0x08), // LED
        HID_RI_USAGE_MINIMUM(8, 0x01), // Num Lock
        HID_RI_USAGE_MAXIMUM(8, 0x05), // Kana
        HID_RI_REPORT_COUNT(8, 0x05),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
        // LED padding (3 bits)
        HID_RI_REPORT_COUNT(8, 0x01),
        HID_RI_REPORT_SIZE(8, 0x03),
        HID_RI_OUTPUT(8, HID_IOF_CONSTANT),

        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
        HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
        HID_RI_USAGE_MAXIMUM(8, KEYBOARD_REPORT_BITS*8-1),
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
        HID_RI_REPORT_COUNT(8, KEYBOARD_REPORT_BITS*8),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
    HID_RI_END_COLLECTION(0),
#   endif
#endif
#ifdef SHARED_EP_ENABLE
};
#endif

#ifdef RAW_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM RawReport[] =
{
    HID_RI_USAGE_PAGE(16, 0xFF60), /* Vendor Page 0xFF60 */
    HID_RI_USAGE(8, 0x61), /* Vendor Usage 0x61 */
    HID_RI_COLLECTION(8, 0x01), /* Application */
        HID_RI_USAGE(8, 0x62), /* Vendor Usage 0x62 */
const USB_Descriptor_HIDReport_Datatype_t PROGMEM RawReport[] = {
    HID_RI_USAGE_PAGE(16, 0xFF60), // Vendor Defined
    HID_RI_USAGE(8, 0x61), // Vendor Defined
    HID_RI_COLLECTION(8, 0x01), // Application
        // Data to host
        HID_RI_USAGE(8, 0x62), // Vendor Defined
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
        HID_RI_REPORT_COUNT(8, RAW_EPSIZE),
        HID_RI_REPORT_SIZE(8, 0x08),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
        HID_RI_USAGE(8, 0x63), /* Vendor Usage 0x63 */
        // Data from host
        HID_RI_USAGE(8, 0x63), // Vendor Defined
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
        HID_RI_REPORT_COUNT(8, RAW_EPSIZE),


@@ 248,18 252,19 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM RawReport[] =
#endif

#ifdef CONSOLE_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] =
{
    HID_RI_USAGE_PAGE(16, 0xFF31), /* Vendor Page(PJRC Teensy compatible) */
    HID_RI_USAGE(8, 0x74), /* Vendor Usage(PJRC Teensy compatible) */
    HID_RI_COLLECTION(8, 0x01), /* Application */
        HID_RI_USAGE(8, 0x75), /* Vendor Usage 0x75 */
const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = {
    HID_RI_USAGE_PAGE(16, 0xFF31), // Vendor Defined (PJRC Teensy compatible)
    HID_RI_USAGE(8, 0x74), // Vendor Defined (PJRC Teensy compatible)
    HID_RI_COLLECTION(8, 0x01), // Application
        // Data to host
        HID_RI_USAGE(8, 0x75), // Vendor Defined
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
        HID_RI_REPORT_COUNT(8, CONSOLE_EPSIZE),
        HID_RI_REPORT_SIZE(8, 0x08),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
        HID_RI_USAGE(8, 0x76), /* Vendor Usage 0x76 */
        // Data from host
        HID_RI_USAGE(8, 0x76), // Vendor Defined
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
        HID_RI_REPORT_COUNT(8, CONSOLE_EPSIZE),


@@ 269,15 274,15 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] =
};
#endif


/*******************************************************************************
 * Device Descriptors
 ******************************************************************************/
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
{
    .Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},

    .USBSpecification       = VERSION_BCD(1,1,0),
/*
 * Device descriptor
 */
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = {
    .Header = {
        .Size               = sizeof(USB_Descriptor_Device_t),
        .Type               = DTYPE_Device
    },
    .USBSpecification       = VERSION_BCD(1, 1, 0),
#if VIRTSER_ENABLE
    .Class                  = USB_CSCP_IADDeviceClass,
    .SubClass               = USB_CSCP_IADDeviceSubclass,


@@ 287,710 292,698 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
    .SubClass               = USB_CSCP_NoDeviceSubclass,
    .Protocol               = USB_CSCP_NoDeviceProtocol,
#endif

    .Endpoint0Size          = FIXED_CONTROL_ENDPOINT_SIZE,

    /* specified in config.h */
    // Specified in config.h
    .VendorID               = VENDOR_ID,
    .ProductID              = PRODUCT_ID,
    .ReleaseNumber          = DEVICE_VER,

    .ManufacturerStrIndex   = 0x01,
    .ProductStrIndex        = 0x02,
    .SerialNumStrIndex      = 0x03,

    .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
};

/*******************************************************************************
 * Configuration Descriptors
 ******************************************************************************/
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
    .Config =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},

            .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
            .TotalInterfaces        = TOTAL_INTERFACES,

            .ConfigurationNumber    = 1,
            .ConfigurationStrIndex  = NO_DESCRIPTOR,

            .ConfigAttributes       = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_REMOTEWAKEUP),
#ifndef USB_MAX_POWER_CONSUMPTION
    #define USB_MAX_POWER_CONSUMPTION 500
#endif

            .MaxPowerConsumption    = USB_CONFIG_POWER_MA(USB_MAX_POWER_CONSUMPTION)
/*
 * Configuration descriptors
 */
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
    .Config = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Configuration_Header_t),
            .Type               = DTYPE_Configuration
        },
        .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
        .TotalInterfaces        = TOTAL_INTERFACES,
        .ConfigurationNumber    = 1,
        .ConfigurationStrIndex  = NO_DESCRIPTOR,
        .ConfigAttributes       = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_REMOTEWAKEUP),
        .MaxPowerConsumption    = USB_CONFIG_POWER_MA(USB_MAX_POWER_CONSUMPTION)
    },

#ifndef KEYBOARD_SHARED_EP
    /*
     * Keyboard
     */
#ifndef KEYBOARD_SHARED_EP
    .Keyboard_Interface =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

            .InterfaceNumber        = KEYBOARD_INTERFACE,
            .AlternateSetting       = 0x00,

            .TotalEndpoints         = 1,

            .Class                  = HID_CSCP_HIDClass,
            .SubClass               = HID_CSCP_BootSubclass,
            .Protocol               = HID_CSCP_KeyboardBootProtocol,

            .InterfaceStrIndex      = NO_DESCRIPTOR
    .Keyboard_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },

    .Keyboard_HID =
        {
            .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},

            .HIDSpec                = VERSION_BCD(1,1,1),
            .CountryCode            = 0x00,
            .TotalReportDescriptors = 1,
            .HIDReportType          = HID_DTYPE_Report,
            .HIDReportLength        = sizeof(KeyboardReport)
        .InterfaceNumber        = KEYBOARD_INTERFACE,
        .AlternateSetting       = 0x00,
        .TotalEndpoints         = 1,
        .Class                  = HID_CSCP_HIDClass,
        .SubClass               = HID_CSCP_BootSubclass,
        .Protocol               = HID_CSCP_KeyboardBootProtocol,

        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Keyboard_HID = {
        .Header = {
            .Size               = sizeof(USB_HID_Descriptor_HID_t),
            .Type               = HID_DTYPE_HID
        },

    .Keyboard_INEndpoint =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

            .EndpointAddress        = (ENDPOINT_DIR_IN | KEYBOARD_IN_EPNUM),
            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize           = KEYBOARD_EPSIZE,
            .PollingIntervalMS      = 0x0A
        .HIDSpec                = VERSION_BCD(1, 1, 1),
        .CountryCode            = 0x00,
        .TotalReportDescriptors = 1,
        .HIDReportType          = HID_DTYPE_Report,
        .HIDReportLength        = sizeof(KeyboardReport)
    },
    .Keyboard_INEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = (ENDPOINT_DIR_IN | KEYBOARD_IN_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = KEYBOARD_EPSIZE,
        .PollingIntervalMS      = 0x0A
    },
#endif

#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    /*
     * Mouse
     */
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    .Mouse_Interface =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

            .InterfaceNumber        = MOUSE_INTERFACE,
            .AlternateSetting       = 0x00,

            .TotalEndpoints         = 1,

            .Class                  = HID_CSCP_HIDClass,
            .SubClass               = HID_CSCP_BootSubclass,
            .Protocol               = HID_CSCP_MouseBootProtocol,

            .InterfaceStrIndex      = NO_DESCRIPTOR
    .Mouse_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },

    .Mouse_HID =
        {
            .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},

            .HIDSpec                = VERSION_BCD(1,1,1),
            .CountryCode            = 0x00,
            .TotalReportDescriptors = 1,
            .HIDReportType          = HID_DTYPE_Report,
            .HIDReportLength        = sizeof(MouseReport)
        .InterfaceNumber        = MOUSE_INTERFACE,
        .AlternateSetting       = 0x00,
        .TotalEndpoints         = 1,
        .Class                  = HID_CSCP_HIDClass,
        .SubClass               = HID_CSCP_BootSubclass,
        .Protocol               = HID_CSCP_MouseBootProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Mouse_HID = {
        .Header = {
            .Size               = sizeof(USB_HID_Descriptor_HID_t),
            .Type               = HID_DTYPE_HID
        },

    .Mouse_INEndpoint =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

            .EndpointAddress        = (ENDPOINT_DIR_IN | MOUSE_IN_EPNUM),
            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize           = MOUSE_EPSIZE,
            .PollingIntervalMS      = 0x0A
        .HIDSpec                = VERSION_BCD(1, 1, 1),
        .CountryCode            = 0x00,
        .TotalReportDescriptors = 1,
        .HIDReportType          = HID_DTYPE_Report,
        .HIDReportLength        = sizeof(MouseReport)
    },
    .Mouse_INEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = (ENDPOINT_DIR_IN | MOUSE_IN_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = MOUSE_EPSIZE,
        .PollingIntervalMS      = 0x0A
    },
#endif

#ifdef SHARED_EP_ENABLE
    /*
     * Shared
     */
#ifdef SHARED_EP_ENABLE
    .Shared_Interface =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

            .InterfaceNumber        = SHARED_INTERFACE,
            .AlternateSetting       = 0x00,

            .TotalEndpoints         = 1,

            .Class                  = HID_CSCP_HIDClass,
#   ifdef KEYBOARD_SHARED_EP
            .SubClass               = HID_CSCP_BootSubclass,
            .Protocol               = HID_CSCP_KeyboardBootProtocol,
#   else
            .SubClass               = HID_CSCP_NonBootSubclass,
            .Protocol               = HID_CSCP_NonBootProtocol,
    .Shared_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },
        .InterfaceNumber        = SHARED_INTERFACE,
        .AlternateSetting       = 0x00,
        .TotalEndpoints         = 1,
        .Class                  = HID_CSCP_HIDClass,
#ifdef KEYBOARD_SHARED_EP
        .SubClass               = HID_CSCP_BootSubclass,
        .Protocol               = HID_CSCP_KeyboardBootProtocol,
#else
        .SubClass               = HID_CSCP_NonBootSubclass,
        .Protocol               = HID_CSCP_NonBootProtocol,
#endif

            .InterfaceStrIndex      = NO_DESCRIPTOR
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Shared_HID = {
        .Header = {
            .Size               = sizeof(USB_HID_Descriptor_HID_t),
            .Type               = HID_DTYPE_HID
        },

    .Shared_HID =
        {
            .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},

            .HIDSpec                = VERSION_BCD(1,1,1),
            .CountryCode            = 0x00,
            .TotalReportDescriptors = 1,
            .HIDReportType          = HID_DTYPE_Report,
            .HIDReportLength        = sizeof(SharedReport)
        .HIDSpec                = VERSION_BCD(1, 1, 1),
        .CountryCode            = 0x00,
        .TotalReportDescriptors = 1,
        .HIDReportType          = HID_DTYPE_Report,
        .HIDReportLength        = sizeof(SharedReport)
    },
    .Shared_INEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = (ENDPOINT_DIR_IN | SHARED_IN_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = SHARED_EPSIZE,
        .PollingIntervalMS      = 0x0A
    },
#endif

    .Shared_INEndpoint =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

            .EndpointAddress        = (ENDPOINT_DIR_IN | SHARED_IN_EPNUM),
            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize           = SHARED_EPSIZE,
            .PollingIntervalMS      = 0x0A
#ifdef RAW_ENABLE
    /*
     * Raw HID
     */
    .Raw_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },
        .InterfaceNumber        = RAW_INTERFACE,
        .AlternateSetting       = 0x00,
        .TotalEndpoints         = 2,
        .Class                  = HID_CSCP_HIDClass,
        .SubClass               = HID_CSCP_NonBootSubclass,
        .Protocol               = HID_CSCP_NonBootProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Raw_HID = {
        .Header = {
            .Size               = sizeof(USB_HID_Descriptor_HID_t),
            .Type               = HID_DTYPE_HID
        },
        .HIDSpec                = VERSION_BCD(1, 1, 1),
        .CountryCode            = 0x00,
        .TotalReportDescriptors = 1,
        .HIDReportType          = HID_DTYPE_Report,
        .HIDReportLength        = sizeof(RawReport)
    },
    .Raw_INEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = (ENDPOINT_DIR_IN | RAW_IN_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = RAW_EPSIZE,
        .PollingIntervalMS      = 0x01
    },
    .Raw_OUTEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = (ENDPOINT_DIR_OUT | RAW_OUT_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = RAW_EPSIZE,
        .PollingIntervalMS      = 0x01
    },
#endif

		/*
	     * Raw
	     */
	#ifdef RAW_ENABLE
	    .Raw_Interface =
	        {
	            .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

	            .InterfaceNumber        = RAW_INTERFACE,
	            .AlternateSetting       = 0x00,

	            .TotalEndpoints         = 2,

	            .Class                  = HID_CSCP_HIDClass,
	            .SubClass               = HID_CSCP_NonBootSubclass,
	            .Protocol               = HID_CSCP_NonBootProtocol,

	            .InterfaceStrIndex      = NO_DESCRIPTOR
	        },

	    .Raw_HID =
	        {
	            .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},

	            .HIDSpec                = VERSION_BCD(1,1,1),
	            .CountryCode            = 0x00,
	            .TotalReportDescriptors = 1,
	            .HIDReportType          = HID_DTYPE_Report,
	            .HIDReportLength        = sizeof(RawReport)
	        },

	    .Raw_INEndpoint =
	        {
	            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

	            .EndpointAddress        = (ENDPOINT_DIR_IN | RAW_IN_EPNUM),
	            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
	            .EndpointSize           = RAW_EPSIZE,
	            .PollingIntervalMS      = 0x01
	        },

	    .Raw_OUTEndpoint =
	        {
	            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

	            .EndpointAddress        = (ENDPOINT_DIR_OUT | RAW_OUT_EPNUM),
	            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
	            .EndpointSize           = RAW_EPSIZE,
	            .PollingIntervalMS      = 0x01
	        },
	#endif

#ifdef CONSOLE_ENABLE
    /*
     * Console
     */
#ifdef CONSOLE_ENABLE
    .Console_Interface =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

            .InterfaceNumber        = CONSOLE_INTERFACE,
            .AlternateSetting       = 0x00,

            .TotalEndpoints         = 2,

            .Class                  = HID_CSCP_HIDClass,
            .SubClass               = HID_CSCP_NonBootSubclass,
            .Protocol               = HID_CSCP_NonBootProtocol,

            .InterfaceStrIndex      = NO_DESCRIPTOR
    .Console_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },

    .Console_HID =
        {
            .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},

            .HIDSpec                = VERSION_BCD(1,1,1),
            .CountryCode            = 0x00,
            .TotalReportDescriptors = 1,
            .HIDReportType          = HID_DTYPE_Report,
            .HIDReportLength        = sizeof(ConsoleReport)
        .InterfaceNumber        = CONSOLE_INTERFACE,
        .AlternateSetting       = 0x00,
        .TotalEndpoints         = 2,
        .Class                  = HID_CSCP_HIDClass,
        .SubClass               = HID_CSCP_NonBootSubclass,
        .Protocol               = HID_CSCP_NonBootProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Console_HID = {
        .Header = {
            .Size               = sizeof(USB_HID_Descriptor_HID_t),
            .Type               = HID_DTYPE_HID
        },

    .Console_INEndpoint =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

            .EndpointAddress        = (ENDPOINT_DIR_IN | CONSOLE_IN_EPNUM),
            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize           = CONSOLE_EPSIZE,
            .PollingIntervalMS      = 0x01
        .HIDSpec                = VERSION_BCD(1, 1, 1),
        .CountryCode            = 0x00,
        .TotalReportDescriptors = 1,
        .HIDReportType          = HID_DTYPE_Report,
        .HIDReportLength        = sizeof(ConsoleReport)
    },
    .Console_INEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },

    .Console_OUTEndpoint =
        {
            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

            .EndpointAddress        = (ENDPOINT_DIR_OUT | CONSOLE_OUT_EPNUM),
            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize           = CONSOLE_EPSIZE,
            .PollingIntervalMS      = 0x01
        .EndpointAddress        = (ENDPOINT_DIR_IN | CONSOLE_IN_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = CONSOLE_EPSIZE,
        .PollingIntervalMS      = 0x01
    },
    .Console_OUTEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = (ENDPOINT_DIR_OUT | CONSOLE_OUT_EPNUM),
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = CONSOLE_EPSIZE,
        .PollingIntervalMS      = 0x01
    },
#endif

#ifdef MIDI_ENABLE
    .Audio_Interface_Association =
        {
            .Header                   = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},

            .FirstInterfaceIndex      = AC_INTERFACE,
            .TotalInterfaces          = 2,

            .Class                    = AUDIO_CSCP_AudioClass,
            .SubClass                 = AUDIO_CSCP_ControlSubclass,
            .Protocol                 = AUDIO_CSCP_ControlProtocol,

            .IADStrIndex              = NO_DESCRIPTOR,
    /*
     * MIDI
     */
    .Audio_Interface_Association = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_Association_t),
            .Type               = DTYPE_InterfaceAssociation
        },
    .Audio_ControlInterface =
        {
            .Header                   = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

            .InterfaceNumber          = AC_INTERFACE,
            .AlternateSetting         = 0,

            .TotalEndpoints           = 0,

            .Class                    = AUDIO_CSCP_AudioClass,
            .SubClass                 = AUDIO_CSCP_ControlSubclass,
            .Protocol                 = AUDIO_CSCP_ControlProtocol,

            .InterfaceStrIndex        = NO_DESCRIPTOR
        .FirstInterfaceIndex    = AC_INTERFACE,
        .TotalInterfaces        = 2,
        .Class                  = AUDIO_CSCP_AudioClass,
        .SubClass               = AUDIO_CSCP_ControlSubclass,
        .Protocol               = AUDIO_CSCP_ControlProtocol,
        .IADStrIndex            = NO_DESCRIPTOR,
    },
    .Audio_ControlInterface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },

    .Audio_ControlInterface_SPC =
        {
            .Header                   = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface},
            .Subtype                  = AUDIO_DSUBTYPE_CSInterface_Header,

            .ACSpecification          = VERSION_BCD(1,0,0),
            .TotalLength              = sizeof(USB_Audio_Descriptor_Interface_AC_t),

            .InCollection             = 1,
            .InterfaceNumber          = AS_INTERFACE,
        .InterfaceNumber        = AC_INTERFACE,
        .AlternateSetting       = 0,
        .TotalEndpoints         = 0,
        .Class                  = AUDIO_CSCP_AudioClass,
        .SubClass               = AUDIO_CSCP_ControlSubclass,
        .Protocol               = AUDIO_CSCP_ControlProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Audio_ControlInterface_SPC = {
        .Header = {
            .Size               = sizeof(USB_Audio_Descriptor_Interface_AC_t),
            .Type               = DTYPE_CSInterface
        },

    .Audio_StreamInterface =
        {
            .Header                   = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

            .InterfaceNumber          = AS_INTERFACE,
            .AlternateSetting         = 0,

            .TotalEndpoints           = 2,

            .Class                    = AUDIO_CSCP_AudioClass,
            .SubClass                 = AUDIO_CSCP_MIDIStreamingSubclass,
            .Protocol                 = AUDIO_CSCP_StreamingProtocol,

            .InterfaceStrIndex        = NO_DESCRIPTOR
        .Subtype                = AUDIO_DSUBTYPE_CSInterface_Header,
        .ACSpecification        = VERSION_BCD(1, 0, 0),
        .TotalLength            = sizeof(USB_Audio_Descriptor_Interface_AC_t),
        .InCollection           = 1,
        .InterfaceNumber        = AS_INTERFACE,
    },
    .Audio_StreamInterface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },

    .Audio_StreamInterface_SPC =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface},
            .Subtype                  = AUDIO_DSUBTYPE_CSInterface_General,

            .AudioSpecification       = VERSION_BCD(1,0,0),

            .TotalLength              = offsetof(USB_Descriptor_Configuration_t, MIDI_Out_Jack_Endpoint_SPC)
                                        + sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t)
                                        - offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC)
        .InterfaceNumber        = AS_INTERFACE,
        .AlternateSetting       = 0,
        .TotalEndpoints         = 2,
        .Class                  = AUDIO_CSCP_AudioClass,
        .SubClass               = AUDIO_CSCP_MIDIStreamingSubclass,
        .Protocol               = AUDIO_CSCP_StreamingProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .Audio_StreamInterface_SPC = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t),
            .Type               = DTYPE_CSInterface
        },

    .MIDI_In_Jack_Emb =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
            .Subtype                  = AUDIO_DSUBTYPE_CSInterface_InputTerminal,

            .JackType                 = MIDI_JACKTYPE_Embedded,
            .JackID                   = 0x01,

            .JackStrIndex             = NO_DESCRIPTOR
        .Subtype                = AUDIO_DSUBTYPE_CSInterface_General,
        .AudioSpecification     = VERSION_BCD(1, 0, 0),
        .TotalLength            = offsetof(USB_Descriptor_Configuration_t, MIDI_Out_Jack_Endpoint_SPC) + sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t) - offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC)
    },
    .MIDI_In_Jack_Emb = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_InputJack_t),
            .Type               = DTYPE_CSInterface
        },

    .MIDI_In_Jack_Ext =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
            .Subtype                  = AUDIO_DSUBTYPE_CSInterface_InputTerminal,

            .JackType                 = MIDI_JACKTYPE_External,
            .JackID                   = 0x02,

            .JackStrIndex             = NO_DESCRIPTOR
        .Subtype                = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
        .JackType               = MIDI_JACKTYPE_Embedded,
        .JackID                 = 0x01,
        .JackStrIndex           = NO_DESCRIPTOR
    },
    .MIDI_In_Jack_Ext = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_InputJack_t),
            .Type               = DTYPE_CSInterface
        },

    .MIDI_Out_Jack_Emb =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
            .Subtype                  = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,

            .JackType                 = MIDI_JACKTYPE_Embedded,
            .JackID                   = 0x03,

            .NumberOfPins             = 1,
            .SourceJackID             = {0x02},
            .SourcePinID              = {0x01},

            .JackStrIndex             = NO_DESCRIPTOR
        .Subtype                = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
        .JackType               = MIDI_JACKTYPE_External,
        .JackID                 = 0x02,
        .JackStrIndex           = NO_DESCRIPTOR
    },
    .MIDI_Out_Jack_Emb = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_OutputJack_t),
            .Type               = DTYPE_CSInterface
        },

    .MIDI_Out_Jack_Ext =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
            .Subtype                  = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,

            .JackType                 = MIDI_JACKTYPE_External,
            .JackID                   = 0x04,

            .NumberOfPins             = 1,
            .SourceJackID             = {0x01},
            .SourcePinID              = {0x01},

            .JackStrIndex             = NO_DESCRIPTOR
        .Subtype                = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
        .JackType               = MIDI_JACKTYPE_Embedded,
        .JackID                 = 0x03,
        .NumberOfPins           = 1,
        .SourceJackID           = {0x02},
        .SourcePinID            = {0x01},
        .JackStrIndex           = NO_DESCRIPTOR
    },
    .MIDI_Out_Jack_Ext = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_OutputJack_t),
            .Type               = DTYPE_CSInterface
        },

    .MIDI_In_Jack_Endpoint =
        {
            .Endpoint =
                {
                    .Header              = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},

                    .EndpointAddress     = MIDI_STREAM_OUT_EPADDR,
                    .Attributes          = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
                    .EndpointSize        = MIDI_STREAM_EPSIZE,
                    .PollingIntervalMS   = 0x05
                },

            .Refresh                  = 0,
            .SyncEndpointNumber       = 0
        .Subtype                = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
        .JackType               = MIDI_JACKTYPE_External,
        .JackID                 = 0x04,
        .NumberOfPins           = 1,
        .SourceJackID           = {0x01},
        .SourcePinID            = {0x01},
        .JackStrIndex           = NO_DESCRIPTOR
    },
    .MIDI_In_Jack_Endpoint = {
        .Endpoint = {
            .Header = {
                .Size           = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t),
                .Type           = DTYPE_Endpoint
            },
            .EndpointAddress    = MIDI_STREAM_OUT_EPADDR,
            .Attributes         = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize       = MIDI_STREAM_EPSIZE,
            .PollingIntervalMS  = 0x05
        },

    .MIDI_In_Jack_Endpoint_SPC =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
            .Subtype                  = AUDIO_DSUBTYPE_CSEndpoint_General,

            .TotalEmbeddedJacks       = 0x01,
            .AssociatedJackID         = {0x01}
        .Refresh                = 0,
        .SyncEndpointNumber     = 0
    },
    .MIDI_In_Jack_Endpoint_SPC = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t),
            .Type               = DTYPE_CSEndpoint
        },

    .MIDI_Out_Jack_Endpoint =
        {
            .Endpoint =
                {
                    .Header              = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},

                    .EndpointAddress     = MIDI_STREAM_IN_EPADDR,
                    .Attributes          = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
                    .EndpointSize        = MIDI_STREAM_EPSIZE,
                    .PollingIntervalMS   = 0x05
                },

            .Refresh                  = 0,
            .SyncEndpointNumber       = 0
        .Subtype                = AUDIO_DSUBTYPE_CSEndpoint_General,
        .TotalEmbeddedJacks     = 0x01,
        .AssociatedJackID       = {0x01}
    },
    .MIDI_Out_Jack_Endpoint = {
        .Endpoint = {
            .Header = {
                .Size           = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t),
                .Type           = DTYPE_Endpoint
            },
            .EndpointAddress    = MIDI_STREAM_IN_EPADDR,
            .Attributes         = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
            .EndpointSize       = MIDI_STREAM_EPSIZE,
            .PollingIntervalMS  = 0x05
        },

    .MIDI_Out_Jack_Endpoint_SPC =
        {
            .Header                   = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
            .Subtype                  = AUDIO_DSUBTYPE_CSEndpoint_General,

            .TotalEmbeddedJacks       = 0x01,
            .AssociatedJackID         = {0x03}
        .Refresh                = 0,
        .SyncEndpointNumber     = 0
    },
    .MIDI_Out_Jack_Endpoint_SPC = {
        .Header = {
            .Size               = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t),
            .Type               = DTYPE_CSEndpoint
        },
        .Subtype                = AUDIO_DSUBTYPE_CSEndpoint_General,
        .TotalEmbeddedJacks     = 0x01,
        .AssociatedJackID       = {0x03}
    },
#endif

#ifdef VIRTSER_ENABLE
    .CDC_Interface_Association =
            {
                    .Header                 = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},

                    .FirstInterfaceIndex    = CCI_INTERFACE,
                    .TotalInterfaces        = 2,

                    .Class                  = CDC_CSCP_CDCClass,
                    .SubClass               = CDC_CSCP_ACMSubclass,
                    .Protocol               = CDC_CSCP_ATCommandProtocol,

                    .IADStrIndex            = NO_DESCRIPTOR,
            },

    .CDC_CCI_Interface =
            {
                    .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

                    .InterfaceNumber        = CCI_INTERFACE,
                    .AlternateSetting       = 0,

                    .TotalEndpoints         = 1,

                    .Class                  = CDC_CSCP_CDCClass,
                    .SubClass               = CDC_CSCP_ACMSubclass,
                    .Protocol               = CDC_CSCP_ATCommandProtocol,

                    .InterfaceStrIndex      = NO_DESCRIPTOR
            },

    .CDC_Functional_Header =
            {
                    .Header                 = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = DTYPE_CSInterface},
                    .Subtype                = 0x00,

                    .CDCSpecification       = VERSION_BCD(1,1,0),
            },

    .CDC_Functional_ACM =
            {
                    .Header                 = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = DTYPE_CSInterface},
                    .Subtype                = 0x02,

                    .Capabilities           = 0x02,
            },

    .CDC_Functional_Union =
            {
                    .Header                 = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = DTYPE_CSInterface},
                    .Subtype                = 0x06,

                    .MasterInterfaceNumber  = CCI_INTERFACE,
                    .SlaveInterfaceNumber   = CDI_INTERFACE,
            },

    .CDC_NotificationEndpoint =
            {
                    .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

                    .EndpointAddress        = CDC_NOTIFICATION_EPADDR,
                    .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
                    .EndpointSize           = CDC_NOTIFICATION_EPSIZE,
                    .PollingIntervalMS      = 0xFF
            },

    .CDC_DCI_Interface =
            {
                    .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

                    .InterfaceNumber        = CDI_INTERFACE,
                    .AlternateSetting       = 0,

                    .TotalEndpoints         = 2,

                    .Class                  = CDC_CSCP_CDCDataClass,
                    .SubClass               = CDC_CSCP_NoDataSubclass,
                    .Protocol               = CDC_CSCP_NoDataProtocol,

                    .InterfaceStrIndex      = NO_DESCRIPTOR
            },

    .CDC_DataOutEndpoint =
            {
                    .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

                    .EndpointAddress        = CDC_OUT_EPADDR,
                    .Attributes             = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
                    .EndpointSize           = CDC_EPSIZE,
                    .PollingIntervalMS      = 0x05
            },

    .CDC_DataInEndpoint =
            {
                    .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},

                    .EndpointAddress        = CDC_IN_EPADDR,
                    .Attributes             = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
                    .EndpointSize           = CDC_EPSIZE,
                    .PollingIntervalMS      = 0x05
            },
    /*
     * Virtual Serial
     */
    .CDC_Interface_Association = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_Association_t),
            .Type               = DTYPE_InterfaceAssociation
        },
        .FirstInterfaceIndex    = CCI_INTERFACE,
        .TotalInterfaces        = 2,
        .Class                  = CDC_CSCP_CDCClass,
        .SubClass               = CDC_CSCP_ACMSubclass,
        .Protocol               = CDC_CSCP_ATCommandProtocol,
        .IADStrIndex            = NO_DESCRIPTOR,
    },
    .CDC_CCI_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },
        .InterfaceNumber        = CCI_INTERFACE,
        .AlternateSetting       = 0,
        .TotalEndpoints         = 1,
        .Class                  = CDC_CSCP_CDCClass,
        .SubClass               = CDC_CSCP_ACMSubclass,
        .Protocol               = CDC_CSCP_ATCommandProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .CDC_Functional_Header = {
        .Header = {
            .Size               = sizeof(USB_CDC_Descriptor_FunctionalHeader_t),
            .Type               = DTYPE_CSInterface
        },
        .Subtype                = 0x00,
        .CDCSpecification       = VERSION_BCD(1, 1, 0),
    },
    .CDC_Functional_ACM = {
        .Header = {
            .Size               = sizeof(USB_CDC_Descriptor_FunctionalACM_t),
            .Type               = DTYPE_CSInterface
        },
        .Subtype                = 0x02,
        .Capabilities           = 0x02,
    },
    .CDC_Functional_Union = {
        .Header = {
            .Size               = sizeof(USB_CDC_Descriptor_FunctionalUnion_t),
            .Type               = DTYPE_CSInterface
        },
        .Subtype                = 0x06,
        .MasterInterfaceNumber  = CCI_INTERFACE,
        .SlaveInterfaceNumber   = CDI_INTERFACE,
    },
    .CDC_NotificationEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = CDC_NOTIFICATION_EPADDR,
        .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = CDC_NOTIFICATION_EPSIZE,
        .PollingIntervalMS      = 0xFF
    },
    .CDC_DCI_Interface = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Interface_t),
            .Type               = DTYPE_Interface
        },
        .InterfaceNumber        = CDI_INTERFACE,
        .AlternateSetting       = 0,
        .TotalEndpoints         = 2,
        .Class                  = CDC_CSCP_CDCDataClass,
        .SubClass               = CDC_CSCP_NoDataSubclass,
        .Protocol               = CDC_CSCP_NoDataProtocol,
        .InterfaceStrIndex      = NO_DESCRIPTOR
    },
    .CDC_DataOutEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = CDC_OUT_EPADDR,
        .Attributes             = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = CDC_EPSIZE,
        .PollingIntervalMS      = 0x05
    },
    .CDC_DataInEndpoint = {
        .Header = {
            .Size               = sizeof(USB_Descriptor_Endpoint_t),
            .Type               = DTYPE_Endpoint
        },
        .EndpointAddress        = CDC_IN_EPADDR,
        .Attributes             = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
        .EndpointSize           = CDC_EPSIZE,
        .PollingIntervalMS      = 0x05
    },
#endif
};


/*******************************************************************************
 * String Descriptors
 ******************************************************************************/
const USB_Descriptor_String_t PROGMEM LanguageString =
{
    .Header                 = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},

    .UnicodeString          = {LANGUAGE_ID_ENG}
/*
 * String descriptors
 */
const USB_Descriptor_String_t PROGMEM LanguageString = {
    .Header = {
        .Size      = USB_STRING_LEN(1),
        .Type      = DTYPE_String
    },
    .UnicodeString = {LANGUAGE_ID_ENG}
};

const USB_Descriptor_String_t PROGMEM ManufacturerString =
{
    /* subtract 1 for null terminator */
    .Header                 = {.Size = USB_STRING_LEN(sizeof(STR(MANUFACTURER))-1), .Type = DTYPE_String},

    .UnicodeString          = LSTR(MANUFACTURER)
const USB_Descriptor_String_t PROGMEM ManufacturerString = {
    .Header = {
        .Size      = USB_STRING_LEN(sizeof(STR(MANUFACTURER)) - 1), // Subtract 1 for null terminator
        .Type      = DTYPE_String
    },
    .UnicodeString = LSTR(MANUFACTURER)
};

const USB_Descriptor_String_t PROGMEM ProductString =
{
    /* subtract 1 for null terminator */
    .Header                 = {.Size = USB_STRING_LEN(sizeof(STR(PRODUCT))-1), .Type = DTYPE_String},

    .UnicodeString          = LSTR(PRODUCT)
const USB_Descriptor_String_t PROGMEM ProductString = {
    .Header = {
        .Size      = USB_STRING_LEN(sizeof(STR(PRODUCT)) - 1), // Subtract 1 for null terminator
        .Type      = DTYPE_String
    },
    .UnicodeString = LSTR(PRODUCT)
};

#ifndef SERIAL_NUMBER
    #define SERIAL_NUMBER 0
#endif

const USB_Descriptor_String_t PROGMEM SerialNumberString =
{
    /* subtract 1 for null terminator */
    .Header                 = {.Size = USB_STRING_LEN(sizeof(STR(SERIAL_NUMBER))-1), .Type = DTYPE_String},

    .UnicodeString          = LSTR(SERIAL_NUMBER)
const USB_Descriptor_String_t PROGMEM SerialNumberString = {
    .Header = {
        .Size      = USB_STRING_LEN(sizeof(STR(SERIAL_NUMBER)) - 1), // Subtract 1 for null terminator
        .Type      = DTYPE_String
    },
    .UnicodeString = LSTR(SERIAL_NUMBER)
};


/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
 *  documentation) by the application code so that the address and size of a requested descriptor can be given
 *  to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
 *  is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
 *  USB host.
/**
 * This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
 * documentation) by the application code so that the address and size of a requested descriptor can be given
 * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
 * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
 * USB host.
 */
uint16_t get_usb_descriptor(const uint16_t wValue,
                            const uint16_t wIndex,
                            const void** const DescriptorAddress)
{
    const uint8_t  DescriptorType   = (wValue >> 8);
    const uint8_t  DescriptorIndex  = (wValue & 0xFF);

    const void* Address = NULL;
    uint16_t    Size    = NO_DESCRIPTOR;

    switch (DescriptorType)
    {
uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress) {
    const uint8_t DescriptorType  = (wValue >> 8);
    const uint8_t DescriptorIndex = (wValue & 0xFF);
    const void*   Address         = NULL;
    uint16_t      Size            = NO_DESCRIPTOR;

    switch (DescriptorType) {
        case DTYPE_Device:
            Address = &DeviceDescriptor;
            Size    = sizeof(USB_Descriptor_Device_t);

            break;
        case DTYPE_Configuration:
            Address = &ConfigurationDescriptor;
            Size    = sizeof(USB_Descriptor_Configuration_t);

            break;
        case DTYPE_String:
            switch (DescriptorIndex )
            {
            switch (DescriptorIndex) {
                case 0x00:
                    Address = &LanguageString;
                    Size    = pgm_read_byte(&LanguageString.Header.Size);

                    break;
                case 0x01:
                    Address = &ManufacturerString;
                    Size    = pgm_read_byte(&ManufacturerString.Header.Size);

                    break;
                case 0x02:
                    Address = &ProductString;
                    Size    = pgm_read_byte(&ProductString.Header.Size);

                    break;
                case 0x03:
                    Address = &SerialNumberString;
                    Size    = pgm_read_byte(&SerialNumberString.Header.Size);

                    break;
            }

            break;
        case HID_DTYPE_HID:
            switch (wIndex) {
#ifndef KEYBOARD_SHARED_EP
            case KEYBOARD_INTERFACE:
                Address = &ConfigurationDescriptor.Keyboard_HID;
                Size    = sizeof(USB_HID_Descriptor_HID_t);
                break;
                case KEYBOARD_INTERFACE:
                    Address = &ConfigurationDescriptor.Keyboard_HID;
                    Size    = sizeof(USB_HID_Descriptor_HID_t);
                    break;
#endif

#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
            case MOUSE_INTERFACE:
                Address = &ConfigurationDescriptor.Mouse_HID;
                Size    = sizeof(USB_HID_Descriptor_HID_t);
                break;
                case MOUSE_INTERFACE:
                    Address = &ConfigurationDescriptor.Mouse_HID;
                    Size    = sizeof(USB_HID_Descriptor_HID_t);

                    break;
#endif

#ifdef SHARED_EP_ENABLE
            case SHARED_INTERFACE:
                Address = &ConfigurationDescriptor.Shared_HID;
                Size    = sizeof(USB_HID_Descriptor_HID_t);
                break;
                case SHARED_INTERFACE:
                    Address = &ConfigurationDescriptor.Shared_HID;
                    Size    = sizeof(USB_HID_Descriptor_HID_t);

                    break;
#endif

#ifdef RAW_ENABLE
            case RAW_INTERFACE:
                Address = &ConfigurationDescriptor.Raw_HID;
                Size    = sizeof(USB_HID_Descriptor_HID_t);
                break;
                case RAW_INTERFACE:
                    Address = &ConfigurationDescriptor.Raw_HID;
                    Size    = sizeof(USB_HID_Descriptor_HID_t);

                    break;
#endif

#ifdef CONSOLE_ENABLE
            case CONSOLE_INTERFACE:
                Address = &ConfigurationDescriptor.Console_HID;
                Size    = sizeof(USB_HID_Descriptor_HID_t);
                break;
                case CONSOLE_INTERFACE:
                    Address = &ConfigurationDescriptor.Console_HID;
                    Size    = sizeof(USB_HID_Descriptor_HID_t);

                    break;
#endif
            }

            break;
        case HID_DTYPE_Report:
            switch (wIndex) {
#ifndef KEYBOARD_SHARED_EP
            case KEYBOARD_INTERFACE:
                Address = &KeyboardReport;
                Size    = sizeof(KeyboardReport);
                break;
                case KEYBOARD_INTERFACE:
                    Address = &KeyboardReport;
                    Size    = sizeof(KeyboardReport);

                    break;
#endif

#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
            case MOUSE_INTERFACE:
                Address = &MouseReport;
                Size    = sizeof(MouseReport);
                break;
                case MOUSE_INTERFACE:
                    Address = &MouseReport;
                    Size    = sizeof(MouseReport);

                    break;
#endif

#ifdef SHARED_EP_ENABLE
            case SHARED_INTERFACE:
                Address = &SharedReport;
                Size    = sizeof(SharedReport);
                break;
                case SHARED_INTERFACE:
                    Address = &SharedReport;
                    Size    = sizeof(SharedReport);

                    break;
#endif

#ifdef RAW_ENABLE
            case RAW_INTERFACE:
                Address = &RawReport;
                Size    = sizeof(RawReport);
                break;
                case RAW_INTERFACE:
                    Address = &RawReport;
                    Size    = sizeof(RawReport);

                    break;
#endif

#ifdef CONSOLE_ENABLE
            case CONSOLE_INTERFACE:
                Address = &ConsoleReport;
                Size    = sizeof(ConsoleReport);
                break;
                case CONSOLE_INTERFACE:
                    Address = &ConsoleReport;
                    Size    = sizeof(ConsoleReport);

                    break;
#endif
            }

            break;
    }

    *DescriptorAddress = Address;

    return Size;
}

M tmk_core/protocol/usb_descriptor.h => tmk_core/protocol/usb_descriptor.h +177 -170
@@ 6,95 6,97 @@
 */

/*
             LUFA Library
     Copyright (C) Dean Camera, 2012.
                         LUFA Library
         Copyright (C) Dean Camera, 2012.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
    dean [at] fourwalledcubicle [dot] com
                     www.lufa-lib.org
*/

/*
  Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
  Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
    Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
    Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)

    Permission to use, copy, modify, distribute, and sell this
    software and its documentation for any purpose is hereby granted
    without fee, provided that the above copyright notice appear in
    all copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.
*/

/** \file
 *
 *  Header file for Descriptors.c.
 */

#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_
    #define _DESCRIPTORS_H_

#include <LUFA/Drivers/USB/USB.h>
#ifdef PROTOCOL_CHIBIOS
#include "hal.h"
#endif
    #include <LUFA/Drivers/USB/USB.h>

typedef struct
{
    USB_Descriptor_Configuration_Header_t Config;
    #ifdef PROTOCOL_CHIBIOS
        #include "hal.h"
    #endif

/*
 * USB descriptor structure
 */
typedef struct {
    USB_Descriptor_Configuration_Header_t    Config;

#ifndef KEYBOARD_SHARED_EP
    #ifndef KEYBOARD_SHARED_EP
    // Keyboard HID Interface
    USB_Descriptor_Interface_t            Keyboard_Interface;
    USB_HID_Descriptor_HID_t              Keyboard_HID;
    USB_Descriptor_Endpoint_t             Keyboard_INEndpoint;
#endif
    USB_Descriptor_Interface_t                Keyboard_Interface;
    USB_HID_Descriptor_HID_t                  Keyboard_HID;
    USB_Descriptor_Endpoint_t                 Keyboard_INEndpoint;
    #endif

#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    // Mouse HID Interface
    USB_Descriptor_Interface_t            Mouse_Interface;
    USB_HID_Descriptor_HID_t              Mouse_HID;
    USB_Descriptor_Endpoint_t             Mouse_INEndpoint;
#endif

#if defined(SHARED_EP_ENABLE)
    USB_Descriptor_Interface_t            Shared_Interface;
    USB_HID_Descriptor_HID_t              Shared_HID;
    USB_Descriptor_Endpoint_t             Shared_INEndpoint;
#endif

#if defined(RAW_ENABLE)
     USB_Descriptor_Interface_t               Mouse_Interface;
    USB_HID_Descriptor_HID_t                  Mouse_HID;
    USB_Descriptor_Endpoint_t                 Mouse_INEndpoint;
    #endif

    #ifdef SHARED_EP_ENABLE
    // Shared Interface
    USB_Descriptor_Interface_t                Shared_Interface;
    USB_HID_Descriptor_HID_t                  Shared_HID;
    USB_Descriptor_Endpoint_t                 Shared_INEndpoint;
    #endif

    #ifdef RAW_ENABLE
    // Raw HID Interface
    USB_Descriptor_Interface_t            Raw_Interface;
    USB_HID_Descriptor_HID_t              Raw_HID;
    USB_Descriptor_Endpoint_t             Raw_INEndpoint;
    USB_Descriptor_Endpoint_t             Raw_OUTEndpoint;
#endif
    USB_Descriptor_Interface_t                Raw_Interface;
    USB_HID_Descriptor_HID_t                  Raw_HID;
    USB_Descriptor_Endpoint_t                 Raw_INEndpoint;
    USB_Descriptor_Endpoint_t                 Raw_OUTEndpoint;
    #endif

#ifdef CONSOLE_ENABLE
    #ifdef CONSOLE_ENABLE
    // Console HID Interface
    USB_Descriptor_Interface_t            Console_Interface;
    USB_HID_Descriptor_HID_t              Console_HID;
    USB_Descriptor_Endpoint_t             Console_INEndpoint;
    USB_Descriptor_Endpoint_t             Console_OUTEndpoint;
#endif
    USB_Descriptor_Interface_t                Console_Interface;
    USB_HID_Descriptor_HID_t                  Console_HID;
    USB_Descriptor_Endpoint_t                 Console_INEndpoint;
    USB_Descriptor_Endpoint_t                 Console_OUTEndpoint;
    #endif

#ifdef MIDI_ENABLE
    #ifdef MIDI_ENABLE
    USB_Descriptor_Interface_Association_t    Audio_Interface_Association;
    // MIDI Audio Control Interface
    USB_Descriptor_Interface_t                Audio_ControlInterface;
    USB_Audio_Descriptor_Interface_AC_t       Audio_ControlInterface_SPC;

    // MIDI Audio Streaming Interface
    USB_Descriptor_Interface_t                Audio_StreamInterface;
    USB_MIDI_Descriptor_AudioInterface_AS_t   Audio_StreamInterface_SPC;


@@ 106,141 108,146 @@ typedef struct
    USB_MIDI_Descriptor_Jack_Endpoint_t       MIDI_In_Jack_Endpoint_SPC;
    USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint;
    USB_MIDI_Descriptor_Jack_Endpoint_t       MIDI_Out_Jack_Endpoint_SPC;
#endif

#ifdef VIRTSER_ENABLE
  USB_Descriptor_Interface_Association_t   CDC_Interface_Association;

  // CDC Control Interface
  USB_Descriptor_Interface_t               CDC_CCI_Interface;
  USB_CDC_Descriptor_FunctionalHeader_t    CDC_Functional_Header;
  USB_CDC_Descriptor_FunctionalACM_t       CDC_Functional_ACM;
  USB_CDC_Descriptor_FunctionalUnion_t     CDC_Functional_Union;
  USB_Descriptor_Endpoint_t                CDC_NotificationEndpoint;

  // CDC Data Interface
  USB_Descriptor_Interface_t               CDC_DCI_Interface;
  USB_Descriptor_Endpoint_t                CDC_DataOutEndpoint;
  USB_Descriptor_Endpoint_t                CDC_DataInEndpoint;
#endif
    #endif

    #ifdef VIRTSER_ENABLE
    USB_Descriptor_Interface_Association_t    CDC_Interface_Association;
    // CDC Control Interface
    USB_Descriptor_Interface_t                CDC_CCI_Interface;
    USB_CDC_Descriptor_FunctionalHeader_t     CDC_Functional_Header;
    USB_CDC_Descriptor_FunctionalACM_t        CDC_Functional_ACM;
    USB_CDC_Descriptor_FunctionalUnion_t      CDC_Functional_Union;
    USB_Descriptor_Endpoint_t                 CDC_NotificationEndpoint;
    // CDC Data Interface
    USB_Descriptor_Interface_t                CDC_DCI_Interface;
    USB_Descriptor_Endpoint_t                 CDC_DataOutEndpoint;
    USB_Descriptor_Endpoint_t                 CDC_DataInEndpoint;
    #endif
} USB_Descriptor_Configuration_t;


/* index of interface */
/*
 * Interface indexes
 */
enum usb_interfaces {
#if !defined(KEYBOARD_SHARED_EP)
    #ifndef KEYBOARD_SHARED_EP
    KEYBOARD_INTERFACE,
#else
#   define KEYBOARD_INTERFACE SHARED_INTERFACE
#endif
// It is important that the Raw HID interface is at a constant
// interface number, to support Linux/OSX platforms and chrome.hid
// If Raw HID is enabled, let it be always 1.
#if defined(RAW_ENABLE)
    #else
        #define KEYBOARD_INTERFACE SHARED_INTERFACE
    #endif

    // It is important that the Raw HID interface is at a constant
    // interface number, to support Linux/OSX platforms and chrome.hid
    // If Raw HID is enabled, let it be always 1.
    #ifdef RAW_ENABLE
    RAW_INTERFACE,
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    #endif

    #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    MOUSE_INTERFACE,
#endif
#if defined(SHARED_EP_ENABLE)
    #endif

    #ifdef SHARED_EP_ENABLE
    SHARED_INTERFACE,
#endif
#if defined(CONSOLE_ENABLE)
    #endif

    #ifdef CONSOLE_ENABLE
    CONSOLE_INTERFACE,
#endif
#if defined(MIDI_ENABLE)
    #endif

    #ifdef MIDI_ENABLE
    AC_INTERFACE,
    AS_INTERFACE,
#endif
#if defined(VIRTSER_ENABLE)
    #endif

    #ifdef VIRTSER_ENABLE
    CCI_INTERFACE,
    CDI_INTERFACE,
#endif
    #endif

    TOTAL_INTERFACES
};

#define NEXT_EPNUM __COUNTER__
    #define NEXT_EPNUM __COUNTER__

/*
 * Endpoint numbers
 */
enum usb_endpoints {
    __unused_epnum__ = NEXT_EPNUM,   /* EP numbering starts at 1 */
#if !defined(KEYBOARD_SHARED_EP)
    __unused_epnum__ = NEXT_EPNUM, // Endpoint numbering starts at 1

    #ifndef KEYBOARD_SHARED_EP
    KEYBOARD_IN_EPNUM = NEXT_EPNUM,
#else
#   define KEYBOARD_IN_EPNUM    SHARED_IN_EPNUM
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    #else
        #define KEYBOARD_IN_EPNUM SHARED_IN_EPNUM
    #endif

    #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
    MOUSE_IN_EPNUM = NEXT_EPNUM,
#else
#   define MOUSE_IN_EPNUM   SHARED_IN_EPNUM
#endif
#if defined(RAW_ENABLE)
    #else
        #define MOUSE_IN_EPNUM SHARED_IN_EPNUM
    #endif

    #ifdef RAW_ENABLE
    RAW_IN_EPNUM = NEXT_EPNUM,
    RAW_OUT_EPNUM = NEXT_EPNUM,
#endif
#if defined(SHARED_EP_ENABLE)
    #endif

    #ifdef SHARED_EP_ENABLE
    SHARED_IN_EPNUM = NEXT_EPNUM,
#endif
#if defined(CONSOLE_ENABLE)
    #endif

    #ifdef CONSOLE_ENABLE
    CONSOLE_IN_EPNUM = NEXT_EPNUM,
#ifdef PROTOCOL_CHIBIOS
// ChibiOS has enough memory and descriptor to actually enable the endpoint
// It could use the same endpoint numbers, as that's supported by ChibiOS
// But the QMK code currently assumes that the endpoint numbers are different

        #ifdef PROTOCOL_CHIBIOS
    // ChibiOS has enough memory and descriptor to actually enable the endpoint
    // It could use the same endpoint numbers, as that's supported by ChibiOS
    // But the QMK code currently assumes that the endpoint numbers are different
    CONSOLE_OUT_EPNUM = NEXT_EPNUM,
#else
#define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
#endif
#endif
#ifdef MIDI_ENABLE
        #else
            #define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
        #endif
    #endif

    #ifdef MIDI_ENABLE
    MIDI_STREAM_IN_EPNUM = NEXT_EPNUM,
    MIDI_STREAM_OUT_EPNUM = NEXT_EPNUM,
#   define MIDI_STREAM_IN_EPADDR    (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM)
#   define MIDI_STREAM_OUT_EPADDR   (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM)
#endif
#ifdef VIRTSER_ENABLE
        #define MIDI_STREAM_IN_EPADDR  (ENDPOINT_DIR_IN  | MIDI_STREAM_IN_EPNUM)
        #define MIDI_STREAM_OUT_EPADDR (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM)
    #endif

    #ifdef VIRTSER_ENABLE
    CDC_NOTIFICATION_EPNUM = NEXT_EPNUM,
    CDC_IN_EPNUM = NEXT_EPNUM,
    CDC_OUT_EPNUM = NEXT_EPNUM,
#   define CDC_NOTIFICATION_EPADDR        (ENDPOINT_DIR_IN | CDC_NOTIFICATION_EPNUM)
#   define CDC_IN_EPADDR                  (ENDPOINT_DIR_IN | CDC_IN_EPNUM)
#   define CDC_OUT_EPADDR                  (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM)
#endif
        #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN  | CDC_NOTIFICATION_EPNUM)
        #define CDC_IN_EPADDR           (ENDPOINT_DIR_IN  | CDC_IN_EPNUM)
        #define CDC_OUT_EPADDR          (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM)
    #endif
};

#if defined(PROTOCOL_LUFA)
/* LUFA tells us total endpoints including control */
#define MAX_ENDPOINTS (ENDPOINT_TOTAL_ENDPOINTS - 1)
#elif defined(PROTOCOL_CHIBIOS)
/* ChibiOS gives us number of available user endpoints, not control */
#define MAX_ENDPOINTS USB_MAX_ENDPOINTS
#endif
/* TODO - ARM_ATSAM */


#if (NEXT_EPNUM - 1) > MAX_ENDPOINTS
# error There are not enough available endpoints to support all functions. Remove some in the rules.mk file. (MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, SERIAL, STENO)
#endif

#define KEYBOARD_EPSIZE             8
#define SHARED_EPSIZE               32
#define MOUSE_EPSIZE                8
#define RAW_EPSIZE                  32
#define CONSOLE_EPSIZE              32
#define MIDI_STREAM_EPSIZE          64
#define CDC_NOTIFICATION_EPSIZE     8
#define CDC_EPSIZE                  16

uint16_t get_usb_descriptor(const uint16_t wValue,
                            const uint16_t wIndex,
                            const void** const DescriptorAddress);

/* new API */
#if LUFA_VERSION_INTEGER < 0x140302
    #undef VERSION_BCD
    #define VERSION_BCD(Major, Minor, Revision) \
                                              CPU_TO_LE16( ((Major & 0xFF) << 8) | \
                                                           ((Minor & 0x0F) << 4) | \
                                                           (Revision & 0x0F) )
#endif

    #ifdef PROTOCOL_LUFA
        // LUFA tells us total endpoints including control
        #define MAX_ENDPOINTS (ENDPOINT_TOTAL_ENDPOINTS - 1)
    #elif defined(PROTOCOL_CHIBIOS)
        // ChibiOS gives us number of available user endpoints, not control
        #define MAX_ENDPOINTS USB_MAX_ENDPOINTS
    #endif

    // TODO - ARM_ATSAM

    #if (NEXT_EPNUM - 1) > MAX_ENDPOINTS
        #error There are not enough available endpoints to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Console, NKRO, MIDI, Serial, Steno
    #endif

    #define KEYBOARD_EPSIZE          8
    #define SHARED_EPSIZE           32
    #define MOUSE_EPSIZE             8
    #define RAW_EPSIZE              32
    #define CONSOLE_EPSIZE          32
    #define MIDI_STREAM_EPSIZE      64
    #define CDC_NOTIFICATION_EPSIZE  8
    #define CDC_EPSIZE              16

uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress);
#endif