diff options
| author | Ha Thach <[email protected]> | 2026-05-04 14:16:15 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-05-04 14:16:15 +0700 |
| commit | 3170fa0bf2667c4cc8e5a22944c15686c681654e (patch) | |
| tree | e3800f4a7bcdcd6536b52d3ab5dbec6a35feecf2 | |
| parent | 84e2e6d1186b3dd1d5f88154adce4f5ecb8b403d (diff) | |
| parent | 25ddb7ff0cfd361b733dadd3bb5307fdb94b6dc1 (diff) | |
Merge pull request #3568 from hathach/copilot/upgrade-net-lwip-webserver-descriptors
net: replace CFG_TUD_NET_ENDPOINT_SIZE with actual descriptor-based ep size
| -rw-r--r-- | .gitignore | 30 | ||||
| -rw-r--r-- | examples/device/net_lwip_webserver/src/usb_descriptors.c | 167 | ||||
| -rw-r--r-- | src/class/net/ecm_rndis_device.c | 9 | ||||
| -rw-r--r-- | src/class/net/ncm_device.c | 5 | ||||
| -rw-r--r-- | src/class/net/net_device.h | 3 | ||||
| -rw-r--r-- | src/device/usbd.h | 8 |
6 files changed, 193 insertions, 29 deletions
diff --git a/.gitignore b/.gitignore index e324916a4..c11e51bb9 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,33 @@ BrowseInfo README_processed.rst .worktrees cmake-metrics/ +# Directories fetched by tools/get_deps.py - not to be committed +lib/CMSIS_5/ +lib/CMSIS_6/ +lib/FreeRTOS-Kernel/ +lib/fatfs/ +lib/lwip/ +lib/sct_neopixel/ +lib/threadx/ +tools/linkermap/ +tools/uf2/ +hw/mcu/allwinner/ +hw/mcu/analog/ +hw/mcu/artery/ +hw/mcu/broadcom/ +hw/mcu/bridgetek/ft9xx/ft90x-sdk/ +hw/mcu/gd/ +hw/mcu/hpmicro/ +hw/mcu/infineon/ +hw/mcu/microchip/ +hw/mcu/mindmotion/ +hw/mcu/nordic/nrfx/ +hw/mcu/nuvoton/ +hw/mcu/nxp/ +hw/mcu/raspberry_pi/ +hw/mcu/renesas/ +hw/mcu/silabs/ +hw/mcu/sony/cxd56/spresense-exported-sdk/ +hw/mcu/st/ +hw/mcu/ti/ +hw/mcu/wch/ diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c index e97b103f9..a7e48c79b 100644 --- a/examples/device/net_lwip_webserver/src/usb_descriptors.c +++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c @@ -65,17 +65,19 @@ enum { CONFIG_ID_COUNT }; +#if CFG_TUD_NCM +#define USB_BCD 0x0201 +#else +#define USB_BCD 0x0200 +#endif + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ static const tusb_desc_device_t desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, -#if CFG_TUD_NCM - .bcdUSB = 0x0201, -#else - .bcdUSB = 0x0200, -#endif + .bcdUSB = USB_BCD, // Use Interface Association Descriptor (IAD) device class .bDeviceClass = TUSB_CLASS_MISC, .bDeviceSubClass = MISC_SUBCLASS_COMMON, @@ -144,57 +146,186 @@ const uint8_t *tud_descriptor_device_cb(void) { #if CFG_TUD_ECM_RNDIS -static uint8_t const rndis_configuration[] = { +// full speed configuration +static uint8_t const rndis_fs_configuration[] = { // Config number (index+1), interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS + 1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100), // Interface number, string index, EP notification address and size, EP data address (out, in) and size. TUD_RNDIS_DESCRIPTOR( - ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE), + ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, 64), }; -static const uint8_t ecm_configuration[] = { +static const uint8_t ecm_fs_configuration[] = { // Config number (index+1), interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM + 1, ITF_NUM_TOTAL, 0, ALT_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_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), + 64, CFG_TUD_NET_MTU), }; +#if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +// high speed configuration +static uint8_t const rndis_hs_configuration[] = { + // Config number (index+1), interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS + 1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100), + + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_RNDIS_DESCRIPTOR( + ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, 512), +}; + +static const uint8_t ecm_hs_configuration[] = { + // Config number (index+1), interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM + 1, ITF_NUM_TOTAL, 0, ALT_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_ECM_DESCRIPTOR( + ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, + 512, CFG_TUD_NET_MTU), +}; +#endif // highspeed + #else -static uint8_t const ncm_configuration[] = { +// full speed configuration +static uint8_t const ncm_fs_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. + // Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size, EP notification bInterval. + TUD_CDC_NCM_DESCRIPTOR( + ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, + 64, CFG_TUD_NET_MTU, 50), +}; + +#if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +// high speed configuration +// bInterval: FS=50 means 50ms; HS encodes as 2^(n-1) * 125us, so 9 = 2^8 * 125us = 32ms +static uint8_t const ncm_hs_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, EP notification bInterval. 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), + 512, CFG_TUD_NET_MTU, 9), }; +#endif // highspeed #endif -// Configuration array: RNDIS and CDC-ECM +// NCM work with all latest OS i.e macos 10.10+, windows 10+, and Linux. +// For older system Configuration array of RNDIS and CDC-ECM may be needed for better compatibility. // - Windows only works with RNDIS // - MacOS only works with CDC-ECM // - Linux will work on both -static const uint8_t *const configuration_arr[CONFIG_ID_COUNT] = { #if CFG_TUD_ECM_RNDIS - [CONFIG_ID_RNDIS] = rndis_configuration, - [CONFIG_ID_ECM] = ecm_configuration + +static const uint8_t *const configuration_fs_arr[CONFIG_ID_COUNT] = { + [CONFIG_ID_RNDIS] = rndis_fs_configuration, + [CONFIG_ID_ECM] = ecm_fs_configuration +}; + +#if TUD_OPT_HIGH_SPEED +static const uint8_t *const configuration_hs_arr[CONFIG_ID_COUNT] = { + [CONFIG_ID_RNDIS] = rndis_hs_configuration, + [CONFIG_ID_ECM] = ecm_hs_configuration +}; + +// Size array for each configuration +static const uint16_t configuration_sz_arr[CONFIG_ID_COUNT] = { + [CONFIG_ID_RNDIS] = MAIN_CONFIG_TOTAL_LEN, + [CONFIG_ID_ECM] = ALT_CONFIG_TOTAL_LEN +}; + +// Scratch buffer for other speed configuration (sized to hold the largest config) +#define MAX_CONFIG_TOTAL_LEN TU_MAX(MAIN_CONFIG_TOTAL_LEN, ALT_CONFIG_TOTAL_LEN) +#endif + #else - [CONFIG_ID_NCM] = ncm_configuration + +static const uint8_t *const configuration_fs_arr[CONFIG_ID_COUNT] = { + [CONFIG_ID_NCM] = ncm_fs_configuration +}; + +#if TUD_OPT_HIGH_SPEED +static const uint8_t *const configuration_hs_arr[CONFIG_ID_COUNT] = { + [CONFIG_ID_NCM] = ncm_hs_configuration +}; + +// Size array for each configuration +static const uint16_t configuration_sz_arr[CONFIG_ID_COUNT] = { + [CONFIG_ID_NCM] = NCM_CONFIG_TOTAL_LEN +}; + +// Scratch buffer for other speed configuration (sized to hold the largest config) +#define MAX_CONFIG_TOTAL_LEN NCM_CONFIG_TOTAL_LEN +#endif + #endif + +#if TUD_OPT_HIGH_SPEED +static uint8_t desc_other_speed_config[MAX_CONFIG_TOTAL_LEN]; + +// device qualifier: device descriptor fields that differ at other speed +static tusb_desc_device_qualifier_t const desc_device_qualifier = { + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = USB_BCD, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = CONFIG_ID_COUNT, + .bReserved = 0x00 }; +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const *tud_descriptor_device_qualifier_cb(void) { + return (uint8_t const *) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SPEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) { + if (index >= CONFIG_ID_COUNT) return NULL; + + // if link speed is high return fullspeed config, and vice versa + const uint8_t *const *arr = (tud_speed_get() == TUSB_SPEED_HIGH) ? configuration_fs_arr : configuration_hs_arr; + + // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG + memcpy(desc_other_speed_config, arr[index], configuration_sz_arr[index]); + desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; + + return desc_other_speed_config; +} + +#endif // highspeed + // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete const uint8_t *tud_descriptor_configuration_cb(uint8_t index) { - return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL; + if (index >= CONFIG_ID_COUNT) return NULL; +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + return (tud_speed_get() == TUSB_SPEED_HIGH) ? configuration_hs_arr[index] : configuration_fs_arr[index]; +#else + return configuration_fs_arr[index]; +#endif } #if CFG_TUD_NCM diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c index 9282e0605..b27cac3ea 100644 --- a/src/class/net/ecm_rndis_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -48,9 +48,10 @@ 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; + uint16_t ep_size; // bulk endpoint max packet size (IN and OUT assumed equal) + uint8_t ep_notif; bool ecm_mode; @@ -176,6 +177,9 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 // Pair of endpoints TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + // Save the actual bulk endpoint size (IN and OUT assumed equal) + _netd_itf.ep_size = tu_edpt_packet_size((tusb_desc_endpoint_t const *) p_desc); + if (_netd_itf.ecm_mode) { // ECM by default is in-active, save the endpoint attribute // to open later when received setInterface @@ -357,8 +361,7 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ /* data transmission finished */ if (ep_addr == _netd_itf.ep_in) { /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */ - - if (xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE))) { + if (xferred_bytes > 0 && 0 == (xferred_bytes & (_netd_itf.ep_size-1))) { do_in_xfer(NULL, 0); /* a ZLP is needed */ } else { /* we're finally finished */ diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 405e4467b..1327dbaf2 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -83,6 +83,7 @@ typedef struct { uint8_t itf_num; // interface number uint8_t itf_data_alt; // ==0 -> no endpoints, i.e. no network traffic, ==1 -> normal operation with two endpoints (spec, chapter 5.3) uint8_t rhport; // storage of \a rhport because some callbacks are done without it + uint16_t ep_size; // bulk endpoint max packet size (IN and OUT assumed equal) // recv handling recv_ntb_t *recv_free_ntb[RECV_NTB_N]; // free list of recv NTBs @@ -340,7 +341,8 @@ static xmit_ntb_t *xmit_get_next_ready_ntb(void) { static bool xmit_insert_required_zlp(uint8_t rhport, uint32_t xferred_bytes) { TU_LOG_DRV("xmit_insert_required_zlp(%d,%ld)\n", rhport, xferred_bytes); - if (xferred_bytes == 0 || xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE != 0) { + uint16_t const ep_size = ncm_interface.ep_size; + if (xferred_bytes == 0 || (xferred_bytes & (ep_size-1)) != 0) { return false; } @@ -905,6 +907,7 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16 // a TUSB_DESC_ENDPOINT (actually two) must follow, open these endpoints TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in)); + ncm_interface.ep_size = tu_edpt_packet_size((tusb_desc_endpoint_t const *) p_desc); drv_len += 2 * sizeof(tusb_desc_endpoint_t); return drv_len; diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 96c03fd61..849f8a2f9 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -35,9 +35,6 @@ #error "Cannot enable both ECM_RNDIS and NCM network drivers" #endif -/* 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 Transmission Unit (in bytes) of the network, including Ethernet header */ #ifndef CFG_TUD_NET_MTU #define CFG_TUD_NET_MTU 1514 diff --git a/src/device/usbd.h b/src/device/usbd.h index d3a6dccbb..93fb588df 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -1026,9 +1026,9 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ // 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) \ +// CDC-NCM Descriptor Template +// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), size, max segment size, EP notification bInterval. +#define TUD_CDC_NCM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize, _ep_notif_interval) \ /* Interface Association */\ 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, 0,\ /* CDC Control Interface */\ @@ -1042,7 +1042,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ /* 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,\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), _ep_notif_interval,\ /* 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) */\ |
