/* * 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" // 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)) ) //--------------------------------------------------------------------+ // 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 Configuration descriptor *------------------------------------------------------------------*/ /*------------- 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 = 0 }, .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 = 0 } }, #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 = NULL, // no auto device .config = &_desc_auto_config_struct, .hid_report = _desc_auto_hid_boot_kbd_report }; #endif