diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 040f40166..cd1c19373 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -31,6 +31,12 @@ Notable contributors - Improve ESP32s2 DCD +`Jacob Berg Potter `__ +------------------------------------------------ + +- Add new class driver for network CDC-NCM + + `Jan Dümpelmann `__ ----------------------------------------------- @@ -93,9 +99,9 @@ Notable contributors ------------------------------------------------ - Add new DCD port for Nuvoton NUC 120, 121, 125, 126, 505 -- Add new class driver for USBNET RNDIS, CDC-ECM -- Add *net\_lwip\_webserver* example for demonstration of usbnet with - lwip +- Add new class driver for network RNDIS, CDC-ECM +- Enhance NCM network driver to compatible with RNDIS/ECM +- Add *net\_lwip\_webserver* example for demonstration of usbnet with lwip - Board support for NuTiny NUC120, NUC121s, NUC125s, NUC126V, NUC505 - Improve multiple cdc interfaces API & add cdc\_dual\_ports example @@ -118,10 +124,8 @@ Notable contributors ------------------------------------------------ - Add new class driver for USB Audio Class 2.0 (UAC2) -- Rework tu\_fifo with unmasked pointer, add DMA support, and constant - address support -- Add new DCD/USBD edpt\_xfer\_fifo() API for optimizing endpoint - transfer +- Rework tu\_fifo with unmasked pointer, add DMA support, and constant address support +- Add new DCD/USBD edpt\_xfer\_fifo() API for optimizing endpoint transfer - Add and greatly improve Isochronous transfer - Add new audio examples: audio\_test and audio\_4\_channel\_mic @@ -130,8 +134,7 @@ Notable contributors ------------------------------------------------ - Add new DCD port for SAMD21 and SAMD51 -- Add new class driver for Musical Instrument Digital Interface - (MIDI) +- Add new class driver for Musical Instrument Digital Interface (MIDI) - Improve USBD control transfer, MSC, CDC class driver - Board support for Metro M0 & M4 express - Write the excellent porting.md documentation @@ -178,7 +181,7 @@ Notable contributors `Zixun Li `__ ------------------------------------------------ +------------------------------------------- - Add new DCD port for Microchip SAMx7x - Add IAR compiler support diff --git a/README.rst b/README.rst index 52738da32..5eecd63ac 100644 --- a/README.rst +++ b/README.rst @@ -65,7 +65,7 @@ Supports multiple device configurations by dynamically changing USB descriptors, - Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ... - Mass Storage Class (MSC): with multiple LUNs - Musical Instrument Digital Interface (MIDI) -- Network with RNDIS, CDC-ECM (work in progress) +- Network with RNDIS, Ethernet Control Model (ECM), Network Control Model (NCM) - USB Test and Measurement Class (USBTMC) - Vendor-specific class support with generic In & Out endpoints. Can be used with MS OS 2.0 compatible descriptor to load winUSB driver without INF file. - `WebUSB `__ with vendor-specific class diff --git a/examples/device/cdc_msc_freertos/src/CMakeLists.txt b/examples/device/cdc_msc_freertos/src/CMakeLists.txt index c0a665fa0..07fc4df89 100644 --- a/examples/device/cdc_msc_freertos/src/CMakeLists.txt +++ b/examples/device/cdc_msc_freertos/src/CMakeLists.txt @@ -23,7 +23,8 @@ target_sources(${COMPONENT_TARGET} PUBLIC "${TOP}/src/class/hid/hid_device.c" "${TOP}/src/class/midi/midi_device.c" "${TOP}/src/class/msc/msc_device.c" - "${TOP}/src/class/net/net_device.c" + "${TOP}/src/class/net/ecm_rndis_device.c" + "${TOP}/src/class/net/ncm_device.c" "${TOP}/src/class/usbtmc/usbtmc_device.c" "${TOP}/src/class/vendor/vendor_device.c" "${TOP}/src/portable/espressif/esp32sx/dcd_esp32sx.c" diff --git a/examples/device/hid_composite_freertos/src/CMakeLists.txt b/examples/device/hid_composite_freertos/src/CMakeLists.txt index a2a4fc9b1..6f156379f 100644 --- a/examples/device/hid_composite_freertos/src/CMakeLists.txt +++ b/examples/device/hid_composite_freertos/src/CMakeLists.txt @@ -23,7 +23,8 @@ target_sources(${COMPONENT_TARGET} PUBLIC "${TOP}/src/class/hid/hid_device.c" "${TOP}/src/class/midi/midi_device.c" "${TOP}/src/class/msc/msc_device.c" - "${TOP}/src/class/net/net_device.c" + "${TOP}/src/class/net/ecm_rndis_device.c" + "${TOP}/src/class/net/ncm_device.c" "${TOP}/src/class/usbtmc/usbtmc_device.c" "${TOP}/src/class/vendor/vendor_device.c" "${TOP}/src/portable/espressif/esp32sx/dcd_esp32sx.c" diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c index 80831921a..a5bd2153a 100644 --- a/examples/device/net_lwip_webserver/src/main.c +++ b/examples/device/net_lwip_webserver/src/main.c @@ -97,7 +97,7 @@ static err_t linkoutput_fn(struct netif *netif, struct pbuf *p) return ERR_USE; /* if the network driver can accept another packet, we make it happen */ - if (tud_network_can_xmit()) + if (tud_network_can_xmit(p->tot_len)) { tud_network_xmit(p, 0 /* unused for this example */); return ERR_OK; diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index 262d4ebce..114961cb7 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -95,12 +95,11 @@ #endif //------------- CLASS -------------// -#define CFG_TUD_CDC 0 -#define CFG_TUD_MSC 0 -#define CFG_TUD_HID 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 0 -#define CFG_TUD_NET 1 + +// Network class has 2 drivers: ECM/RNDIS and NCM. +// Only one of the drivers can be enabled +#define CFG_TUD_ECM_RNDIS 1 +#define CFG_TUD_NCM (1-CFG_TUD_ECM_RNDIS) #ifdef __cplusplus } diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c index 71e6c4582..2b4b2a0c3 100644 --- a/examples/device/net_lwip_webserver/src/usb_descriptors.c +++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c @@ -33,7 +33,7 @@ */ #define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ - _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(NET, 5) ) + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) ) // String Descriptor Index enum @@ -55,8 +55,12 @@ enum enum { +#if CFG_TUD_ECM_RNDIS CONFIG_ID_RNDIS = 0, CONFIG_ID_ECM = 1, +#else + CONFIG_ID_NCM = 0, +#endif CONFIG_ID_COUNT }; @@ -99,6 +103,7 @@ uint8_t const * tud_descriptor_device_cb(void) //--------------------------------------------------------------------+ #define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN) #define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN) +#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_NCM_DESC_LEN) #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number @@ -120,6 +125,8 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_NET_IN 0x82 #endif +#if CFG_TUD_ECM_RNDIS + static uint8_t const rndis_configuration[] = { // Config number (index+1), interface count, string index, total length, attribute, power in mA @@ -138,14 +145,31 @@ static uint8_t const ecm_configuration[] = TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU), }; +#else + +static uint8_t const ncm_configuration[] = +{ + // Config number (index+1), interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100), + + // Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. + TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU), +}; + +#endif + // Configuration array: RNDIS and CDC-ECM // - Windows only works with RNDIS // - MacOS only works with CDC-ECM // - Linux will work on both static uint8_t const * const configuration_arr[2] = { +#if CFG_TUD_ECM_RNDIS [CONFIG_ID_RNDIS] = rndis_configuration, [CONFIG_ID_ECM ] = ecm_configuration +#else + [CONFIG_ID_NCM ] = ncm_configuration +#endif }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/rules.mk b/examples/rules.mk index 861973284..5f9dd9d19 100644 --- a/examples/rules.mk +++ b/examples/rules.mk @@ -33,7 +33,8 @@ SRC_C += \ src/class/hid/hid_device.c \ src/class/midi/midi_device.c \ src/class/msc/msc_device.c \ - src/class/net/net_device.c \ + src/class/net/ecm_rndis_device.c \ + src/class/net/ncm_device.c \ src/class/usbtmc/usbtmc_device.c \ src/class/vendor/vendor_device.c diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index 41960b6cd..4ba24b3aa 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -70,7 +70,8 @@ if (NOT TARGET _rp2040_family_inclusion_marker) ${TOP}/src/class/hid/hid_device.c ${TOP}/src/class/midi/midi_device.c ${TOP}/src/class/msc/msc_device.c - ${TOP}/src/class/net/net_device.c + ${TOP}/src/class/net/ecm_rndis_device.c + ${TOP}/src/class/net/ncm_device.c ${TOP}/src/class/usbtmc/usbtmc_device.c ${TOP}/src/class/vendor/vendor_device.c ) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 5df47f70b..e345139ea 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -58,31 +58,32 @@ typedef enum /// Communication Interface Subclass Codes typedef enum { - CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , ///< Direct Line Control Model [USBPSTN1.2] - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL , ///< Abstract Control Model [USBPSTN1.2] - CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL , ///< Telephone Control Model [USBPSTN1.2] - CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL , ///< Multi-Channel Control Model [USBISDN1.2] - CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL , ///< CAPI Control Model [USBISDN1.2] - CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL , ///< Ethernet Networking Control Model [USBECM1.2] - CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL , ///< ATM Networking Control Model [USBATM1.2] - CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL , ///< Wireless Handset Control Model [USBWMC1.1] - CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT , ///< Device Management [USBWMC1.1] - CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL , ///< Mobile Direct Line Model [USBWMC1.1] - CDC_COMM_SUBCLASS_OBEX , ///< OBEX [USBWMC1.1] - CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL ///< Ethernet Emulation Model [USBEEM1.0] + CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , ///< Direct Line Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL = 0x02 , ///< Abstract Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL = 0x03 , ///< Telephone Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL = 0x04 , ///< Multi-Channel Control Model [USBISDN1.2] + CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL = 0x05 , ///< CAPI Control Model [USBISDN1.2] + CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL = 0x06 , ///< Ethernet Networking Control Model [USBECM1.2] + CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL = 0x07 , ///< ATM Networking Control Model [USBATM1.2] + CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL = 0x08 , ///< Wireless Handset Control Model [USBWMC1.1] + CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT = 0x09 , ///< Device Management [USBWMC1.1] + CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL = 0x0A , ///< Mobile Direct Line Model [USBWMC1.1] + CDC_COMM_SUBCLASS_OBEX = 0x0B , ///< OBEX [USBWMC1.1] + CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL = 0x0C , ///< Ethernet Emulation Model [USBEEM1.0] + CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL = 0x0D ///< Network Control Model [USBNCM1.0] } cdc_comm_sublcass_type_t; /// Communication Interface Protocol Codes typedef enum { - CDC_COMM_PROTOCOL_NONE = 0x00 , ///< No specific protocol - CDC_COMM_PROTOCOL_ATCOMMAND , ///< AT Commands: V.250 etc - CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 , ///< AT Commands defined by PCCA-101 - CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO , ///< AT Commands defined by PCCA-101 & Annex O - CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 , ///< AT Commands defined by GSM 07.07 - CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 , ///< AT Commands defined by 3GPP 27.007 - CDC_COMM_PROTOCOL_ATCOMMAND_CDMA , ///< AT Commands defined by TIA for CDMA - CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL ///< Ethernet Emulation Model + CDC_COMM_PROTOCOL_NONE = 0x00 , ///< No specific protocol + CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , ///< AT Commands: V.250 etc + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 = 0x02 , ///< AT Commands defined by PCCA-101 + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO = 0x03 , ///< AT Commands defined by PCCA-101 & Annex O + CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 = 0x04 , ///< AT Commands defined by GSM 07.07 + CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 = 0x05 , ///< AT Commands defined by 3GPP 27.007 + CDC_COMM_PROTOCOL_ATCOMMAND_CDMA = 0x06 , ///< AT Commands defined by TIA for CDMA + CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL = 0x07 ///< Ethernet Emulation Model } cdc_comm_protocol_type_t; //------------- SubType Descriptor in COMM Functional Descriptor -------------// @@ -114,7 +115,8 @@ typedef enum CDC_FUNC_DESC_COMMAND_SET = 0x16 , ///< Command Set Functional Descriptor CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , ///< Command Set Detail Functional Descriptor CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , ///< Telephone Control Model Functional Descriptor - CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 ///< OBEX Service Identifier Functional Descriptor + CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 , ///< OBEX Service Identifier Functional Descriptor + CDC_FUNC_DESC_NCM = 0x1A , ///< NCM Functional Descriptor }cdc_func_desc_type_t; //--------------------------------------------------------------------+ @@ -122,7 +124,8 @@ typedef enum //--------------------------------------------------------------------+ // SUBCLASS code of Data Interface is not used and should/must be zero -/// Data Interface Protocol Codes + +// Data Interface Protocol Codes typedef enum{ CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, ///< Physical interface protocol for ISDN BRI CDC_DATA_PROTOCOL_HDLC = 0x31, ///< HDLC @@ -147,7 +150,6 @@ typedef enum { CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. - CDC_REQUEST_SET_COMM_FEATURE = 0x02, CDC_REQUEST_GET_COMM_FEATURE = 0x03, CDC_REQUEST_CLEAR_COMM_FEATURE = 0x04, @@ -194,21 +196,18 @@ typedef enum // Management Elemenent Notification (Notification Endpoint) //--------------------------------------------------------------------+ -/// Communication Interface Management Element Notification Codes +/// 6.3 Notification Codes typedef enum { - NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. - RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. - - AUX_JACK_HOOK_STATE = 0x08, - RING_DETECT = 0x09, - - SERIAL_STATE = 0x20, - - CALL_STATE_CHANGE = 0x28, - LINE_STATE_CHANGE = 0x29, - CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred - MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, + CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. + CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, + CDC_NOTIF_RING_DETECT = 0x09, + CDC_NOTIF_SERIAL_STATE = 0x20, + CDC_NOTIF_CALL_STATE_CHANGE = 0x28, + CDC_NOTIF_LINE_STATE_CHANGE = 0x29, + CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, }cdc_notification_request_t; //--------------------------------------------------------------------+ diff --git a/src/class/net/net_device.c b/src/class/net/ecm_rndis_device.c similarity index 98% rename from src/class/net/net_device.c rename to src/class/net/ecm_rndis_device.c index 9d9719ce4..c6cd388e3 100644 --- a/src/class/net/net_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -27,7 +27,7 @@ #include "tusb_option.h" -#if ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_NET ) +#if ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_ECM_RNDIS ) #include "device/usbd.h" #include "device/usbd_pvt.h" @@ -119,6 +119,8 @@ static void do_in_xfer(uint8_t *buf, uint16_t len) void netd_report(uint8_t *buf, uint16_t len) { + // skip if previous report not yet acknowledged by host + if ( usbd_edpt_busy(TUD_OPT_RHPORT, _netd_itf.ep_notif) ) return; usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_notif, buf, len); } @@ -407,8 +409,10 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ return true; } -bool tud_network_can_xmit(void) +bool tud_network_can_xmit(uint16_t size) { + (void)size; + return can_xmit; } diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h new file mode 100644 index 000000000..96ba11fbc --- /dev/null +++ b/src/class/net/ncm.h @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (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. + */ + + +#ifndef _TUSB_NCM_H_ +#define _TUSB_NCM_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Table 4.3 Data Class Interface Protocol Codes +typedef enum +{ + NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 +} ncm_data_interface_protocol_code_t; + + +// Table 6.2 Class-Specific Request Codes for Network Control Model subclass +typedef enum +{ + NCM_SET_ETHERNET_MULTICAST_FILTERS = 0x40, + NCM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, + NCM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, + NCM_SET_ETHERNET_PACKET_FILTER = 0x43, + NCM_GET_ETHERNET_STATISTIC = 0x44, + NCM_GET_NTB_PARAMETERS = 0x80, + NCM_GET_NET_ADDRESS = 0x81, + NCM_SET_NET_ADDRESS = 0x82, + NCM_GET_NTB_FORMAT = 0x83, + NCM_SET_NTB_FORMAT = 0x84, + NCM_GET_NTB_INPUT_SIZE = 0x85, + NCM_SET_NTB_INPUT_SIZE = 0x86, + NCM_GET_MAX_DATAGRAM_SIZE = 0x87, + NCM_SET_MAX_DATAGRAM_SIZE = 0x88, + NCM_GET_CRC_MODE = 0x89, + NCM_SET_CRC_MODE = 0x8A, +} ncm_request_code_t; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c new file mode 100644 index 000000000..3e131a85c --- /dev/null +++ b/src/class/net/ncm_device.c @@ -0,0 +1,510 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jacob Berg Potter + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (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_NCM ) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" +#include "net_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +#define NTH16_SIGNATURE 0x484D434E +#define NDP16_SIGNATURE_NCM0 0x304D434E +#define NDP16_SIGNATURE_NCM1 0x314D434E + +typedef struct TU_ATTR_PACKED +{ + uint16_t wLength; + uint16_t bmNtbFormatsSupported; + uint32_t dwNtbInMaxSize; + uint16_t wNdbInDivisor; + uint16_t wNdbInPayloadRemainder; + uint16_t wNdbInAlignment; + uint16_t wReserved; + uint32_t dwNtbOutMaxSize; + uint16_t wNdbOutDivisor; + uint16_t wNdbOutPayloadRemainder; + uint16_t wNdbOutAlignment; + uint16_t wNtbOutMaxDatagrams; +} ntb_parameters_t; + +typedef struct TU_ATTR_PACKED +{ + uint32_t dwSignature; + uint16_t wHeaderLength; + uint16_t wSequence; + uint16_t wBlockLength; + uint16_t wNdpIndex; +} nth16_t; + +typedef struct TU_ATTR_PACKED +{ + uint16_t wDatagramIndex; + uint16_t wDatagramLength; +} ndp16_datagram_t; + +typedef struct TU_ATTR_PACKED +{ + uint32_t dwSignature; + uint16_t wLength; + uint16_t wNextNdpIndex; + ndp16_datagram_t datagram[]; +} ndp16_t; + +typedef union TU_ATTR_PACKED { + struct { + nth16_t nth; + ndp16_t ndp; + }; + uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; +} transmit_ntb_t; + +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +typedef struct +{ + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + const ndp16_t *ndp; + uint8_t num_datagrams, current_datagram_index; + + enum { + REPORT_SPEED, + REPORT_CONNECTED, + REPORT_DONE + } report_state; + bool report_pending; + + uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams + uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb] + uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram + uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE + uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + + uint16_t nth_sequence; // Sequence number counter for transmitted NTBs + + bool transferring; + +} ncm_interface_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parameters = { + .wLength = sizeof(ntb_parameters_t), + .bmNtbFormatsSupported = 0x01, + .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, + .wNdbInDivisor = 4, + .wNdbInPayloadRemainder = 0, + .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, + .wReserved = 0, + .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, + .wNdbOutDivisor = 4, + .wNdbOutPayloadRemainder = 0, + .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, + .wNtbOutMaxDatagrams = 0 +}; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static transmit_ntb_t transmit_ntb[2]; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; + +static ncm_interface_t ncm_interface; + +/* + * Set up the NTB state in ncm_interface to be ready to add datagrams. + */ +static void ncm_prepare_for_tx(void) { + ncm_interface.datagram_count = 0; + // datagrams start after all the headers + ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t) + + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t)); +} + +/* + * If not already transmitting, start sending the current NTB to the host and swap buffers + * to start filling the other one with datagrams. + */ +static void ncm_start_tx(void) { + if (ncm_interface.transferring) { + return; + } + + transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; + size_t ntb_length = ncm_interface.next_datagram_offset; + + // Fill in NTB header + ntb->nth.dwSignature = NTH16_SIGNATURE; + ntb->nth.wHeaderLength = sizeof(nth16_t); + ntb->nth.wSequence = ncm_interface.nth_sequence++; + ntb->nth.wBlockLength = ntb_length; + ntb->nth.wNdpIndex = sizeof(nth16_t); + + // Fill in NDP16 header and terminator + ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; + ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t); + ntb->ndp.wNextNdpIndex = 0; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0; + + // Kick off an endpoint transfer + usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_in, ntb->data, ntb_length); + ncm_interface.transferring = true; + + // Swap to the other NTB and clear it out + ncm_interface.current_ntb = 1 - ncm_interface.current_ntb; + ncm_prepare_for_tx(); +} + +static struct ecm_notify_struct ncm_notify_connected = +{ + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_NETWORK_CONNECTION, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +static struct ecm_notify_struct ncm_notify_speed_change = +{ + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, + .wLength = 8, + }, + .downlink = 10000000, + .uplink = 10000000, +}; + +void tud_network_recv_renew(void) +{ + if (!ncm_interface.num_datagrams) + { + usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb)); + return; + } + + const ndp16_t *ndp = ncm_interface.ndp; + const int i = ncm_interface.current_datagram_index; + ncm_interface.current_datagram_index++; + ncm_interface.num_datagrams--; + + tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ + +void netd_init(void) +{ + tu_memclr(&ncm_interface, sizeof(ncm_interface)); + ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE; + ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB; + ncm_prepare_for_tx(); +} + +void netd_reset(uint8_t rhport) +{ + (void) rhport; + + netd_init(); +} + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // confirm interface hasn't already been allocated + TU_ASSERT(0 == ncm_interface.ep_notif, 0); + + //------------- Management Interface -------------// + ncm_interface.itf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // notification endpoint (if any) + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); + + ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface -------------// + // - CDC-NCM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for transfer of NTBs + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + + do + { + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len)); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) ); + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + + return drv_len; +} + +static void ncm_report(void) +{ + if (ncm_interface.report_state == REPORT_SPEED) { + ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); + ncm_interface.report_state = REPORT_CONNECTED; + ncm_interface.report_pending = true; + } else if (ncm_interface.report_state == REPORT_CONNECTED) { + ncm_notify_connected.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); + ncm_interface.report_state = REPORT_DONE; + ncm_interface.report_pending = true; + } +} + +TU_ATTR_WEAK void tud_network_link_state_cb(bool state) +{ + (void)state; +} + +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage != CONTROL_STAGE_SETUP ) return true; + + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum); + + tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2); + + if (req_alt != ncm_interface.itf_data_alt) { + ncm_interface.itf_data_alt = req_alt; + + if (ncm_interface.itf_data_alt) { + if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) { + tud_network_recv_renew(); // prepare for incoming datagrams + } + if (!ncm_interface.report_pending) { + ncm_report(); + } + } + + tud_network_link_state_cb(ncm_interface.itf_data_alt); + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (ncm_interface.itf_num == request->wIndex); + + if (NCM_GET_NTB_PARAMETERS == request->bRequest) + { + tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters)); + } + + break; + + // unsupported request + default: return false; + } + + return true; +} + +static void handle_incoming_datagram(uint32_t len) +{ + uint32_t size = len; + + if (len == 0) { + return; + } + + TU_ASSERT(size >= sizeof(nth16_t), ); + + const nth16_t *hdr = (const nth16_t *)receive_ntb; + TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, ); + TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, ); + + const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex); + TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, ); + TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, ); + + int num_datagrams = (ndp->wLength - 12) / 4; + ncm_interface.current_datagram_index = 0; + ncm_interface.num_datagrams = 0; + ncm_interface.ndp = ndp; + for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++) + { + ncm_interface.num_datagrams++; + } + + tud_network_recv_renew(); +} + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + /* new datagram receive_ntb */ + if (ep_addr == ncm_interface.ep_out ) + { + handle_incoming_datagram(xferred_bytes); + } + + /* data transmission finished */ + if (ep_addr == ncm_interface.ep_in ) + { + if (ncm_interface.transferring) { + ncm_interface.transferring = false; + } + + // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now + if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) { + ncm_start_tx(); + } + } + + if (ep_addr == ncm_interface.ep_notif ) + { + ncm_interface.report_pending = false; + ncm_report(); + } + + return true; +} + +// poll network driver for its ability to accept another packet to transmit +bool tud_network_can_xmit(uint16_t size) +{ + TU_VERIFY(ncm_interface.itf_data_alt == 1); + + if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { + TU_LOG2("NTB full [by count]\r\n"); + return false; + } + + size_t next_datagram_offset = ncm_interface.next_datagram_offset; + if (next_datagram_offset + size > ncm_interface.ntb_in_size) { + TU_LOG2("ntb full [by size]\r\n"); + return false; + } + + return true; +} + +void tud_network_xmit(void *ref, uint16_t arg) +{ + transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; + size_t next_datagram_offset = ncm_interface.next_datagram_offset; + + uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg); + + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size; + + ncm_interface.datagram_count++; + next_datagram_offset += size; + + // round up so the next datagram is aligned correctly + next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1); + next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT); + + ncm_interface.next_datagram_offset = next_datagram_offset; + + ncm_start_tx(); +} + +#endif diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index f030f3077..6e294465b 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -30,14 +30,36 @@ #include "class/cdc/cdc.h" +#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM +#error "Cannot enable both ECM_RNDIS and NCM network drivers" +#endif + +#include "ncm.h" + /* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */ #define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -/* Maximum Tranmission Unit (in bytes) of the network, including Ethernet header */ +/* Maximum Transmission Unit (in bytes) of the network, including Ethernet header */ #ifndef CFG_TUD_NET_MTU #define CFG_TUD_NET_MTU 1514 #endif +#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE +#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE +#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB +#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 +#endif + +#ifndef CFG_TUD_NCM_ALIGNMENT +#define CFG_TUD_NCM_ALIGNMENT 4 +#endif + #ifdef __cplusplus extern "C" { #endif @@ -46,8 +68,18 @@ // Application API //--------------------------------------------------------------------+ -// client must provide this: initialize any network state back to the beginning -void tud_network_init_cb(void); +// indicate to network driver that client has finished with the packet provided to network_recv_cb() +void tud_network_recv_renew(void); + +// poll network driver for its ability to accept another packet to transmit +bool tud_network_can_xmit(uint16_t size); + +// if network_can_xmit() returns true, network_xmit() can be called once +void tud_network_xmit(void *ref, uint16_t arg); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ // client must provide this: return false if the packet buffer was not accepted bool tud_network_recv_cb(const uint8_t *src, uint16_t size); @@ -55,18 +87,19 @@ bool tud_network_recv_cb(const uint8_t *src, uint16_t size); // client must provide this: copy from network stack packet pointer to dst uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); +//------------- ECM/RNDIS -------------// + +// client must provide this: initialize any network state back to the beginning +void tud_network_init_cb(void); + // client must provide this: 48-bit MAC address // TODO removed later since it is not part of tinyusb stack extern const uint8_t tud_network_mac_address[6]; -// indicate to network driver that client has finished with the packet provided to network_recv_cb() -void tud_network_recv_renew(void); +//------------- NCM -------------// -// poll network driver for its ability to accept another packet to transmit -bool tud_network_can_xmit(void); - -// if network_can_xmit() returns true, network_xmit() can be called once -void tud_network_xmit(void *ref, uint16_t arg); +// callback to client providing optional indication of internal state of network driver +void tud_network_link_state_cb(bool state); //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API diff --git a/src/device/usbd.c b/src/device/usbd.c index a33d778db..ab1837895 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -203,7 +203,7 @@ static usbd_class_driver_t const _usbd_driver[] = }, #endif - #if CFG_TUD_NET + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM { DRIVER_NAME("NET") .init = netd_init, diff --git a/src/device/usbd.h b/src/device/usbd.h index 6b19e7217..8d02de1ff 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -809,6 +809,39 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \ TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__) +//--------------------------------------------------------------------+ +// CDC-NCM Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor +#define TUD_CDC_NCM_DESC_LEN (8+9+5+5+13+6+7+9+9+7+7) + +// CDC-ECM Descriptor Template +// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. +#define TUD_CDC_NCM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, _desc_stridx,\ + /* CDC-NCM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\ + /* CDC-NCM Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* CDC-NCM Functional Descriptor */\ + 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0, \ + /* CDC-NCM Functional Descriptor */\ + 6, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_NCM, U16_TO_U8S_LE(0x0100), 0, \ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 50,\ + /* CDC Data Interface (default inactive) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\ + /* CDC Data Interface (alternative active) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + #ifdef __cplusplus } #endif diff --git a/src/tusb.h b/src/tusb.h index b52f8839a..bdfcb5be6 100644 --- a/src/tusb.h +++ b/src/tusb.h @@ -76,9 +76,9 @@ #include "class/msc/msc_device.h" #endif -#if CFG_TUD_AUDIO - #include "class/audio/audio_device.h" -#endif + #if CFG_TUD_AUDIO + #include "class/audio/audio_device.h" + #endif #if CFG_TUD_MIDI #include "class/midi/midi_device.h" @@ -100,7 +100,7 @@ #include "class/dfu/dfu_device.h" #endif - #if CFG_TUD_NET + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM #include "class/net/net_device.h" #endif diff --git a/src/tusb_option.h b/src/tusb_option.h index dceb2ac2c..cda8c45ce 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -261,14 +261,23 @@ #define CFG_TUD_DFU 0 #endif -#ifndef CFG_TUD_NET - #define CFG_TUD_NET 0 -#endif - #ifndef CFG_TUD_BTH #define CFG_TUD_BTH 0 #endif +#ifndef CFG_TUD_ECM_RNDIS + #ifdef CFG_TUD_NET + #warning "CFG_TUD_NET is renamed to CFG_TUD_ECM_RNDIS" + #define CFG_TUD_ECM_RNDIS CFG_TUD_NET + #else + #define CFG_TUD_ECM_RNDIS 0 + #endif +#endif + +#ifndef CFG_TUD_NCM + #define CFG_TUD_NCM 0 +#endif + //-------------------------------------------------------------------- // HOST OPTIONS //-------------------------------------------------------------------- @@ -280,10 +289,10 @@ #ifndef CFG_TUH_ENUMERATION_BUFSIZE #define CFG_TUH_ENUMERATION_BUFSIZE 256 #endif - - //------------- CLASS -------------// #endif // TUSB_OPT_HOST_ENABLED +//------------- CLASS -------------// + #ifndef CFG_TUH_HUB #define CFG_TUH_HUB 0 #endif