Просмотр исходного кода

Merge branch 'master' into fix-warnings

Ha Thach 4 лет назад
Родитель
Сommit
311c05b401

+ 1 - 2
CONTRIBUTORS.rst

@@ -177,8 +177,7 @@ Notable contributors
 -  Add new DCD port for Synopsys DesignWare for STM32 L4, F2, F4,
    F7, H7 etc ...
 -  Add new DCD port for TI MSP430
--  Board support for STM32F407 Discovery, STM32H743 Nucleo, pyboard
-   v1.1, msp\_exp430f5529lp etc ...
+-  Board support for STM32F407 Discovery, STM32H743 Nucleo, pyboard v1.1, msp\_exp430f5529lp etc ...
 
 
 `Zixun Li <https://github.com/HiFiPhile>`__

+ 32 - 1
docs/info/changelog.rst

@@ -2,6 +2,37 @@
 Changelog
 *********
 
+0.12.0
+======
+
+- add CFG_TUSB_OS_INC_PATH for os include path
+
+Device Controller Driver (DCD)
+------------------------------
+
+- Getting device stack to pass USB Compliance Verification test (chapter9, HID, MSC). Ports are tested:
+  nRF, SAMD 21/51, rp2040, stm32f4, Renesas RX, iMXRT, ESP32-S2/3, Kinetic KL25/32, DA146xx
+- Added dcd_edpt_close_all() for switching configuration
+- [Transdimension] Support dcd_edpt_xfer_fifo() with auto wrap over if fifo buffer is 4K aligned and size is multiple of 4K.
+- [DA146xx] Improve vbus, reset, suspend, resume detection, and remote wakeup.
+
+Device Stack
+------------
+
+- Add new network driver Network Control Model (CDC-NCM), update net_lwip_webserver to work with NCM (need re-configure example)
+- Add new USB Video Class UVC 1.5 driver and video_capture example ((work in progress)
+- Fix potential buffer overflow for HID, bluetooth drivers
+
+Host Controller Driver (HCD)
+----------------------------
+
+No notable changes
+
+Host Stack
+----------
+
+No notable changes
+
 0.11.0 (2021-08-29)
 ===================
 
@@ -26,7 +57,7 @@ Synopsys
 ^^^^^^^^
 
 - Fix Synopsys set address bug which could cause re-enumeration failed
-- Fix for dcd_synopsys driver integer overflow in HS mode (issue #968)
+- Fix dcd_synopsys driver integer overflow in HS mode (issue #968)
 
 nRF5x
 ^^^^^

+ 1 - 1
docs/reference/getting_started.rst

@@ -122,7 +122,7 @@ Logger
 By default log message is printed via on-board UART which is slow and take lots of CPU time comparing to USB speed. If your board support on-board/external debugger, it would be more efficient to use it for logging. There are 2 protocols: 
 
 
-* `LOGGER=rtt`: use [Segger RTT protocol](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/)   
+* `LOGGER=rtt`: use `Segger RTT protocol <https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/>`_
 
   * Cons: requires jlink as the debugger.
   * Pros: work with most if not all MCUs

+ 1 - 1
examples/device/cdc_msc/src/usb_descriptors.c

@@ -232,7 +232,7 @@ char const* string_desc_arr [] =
   (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
   "TinyUSB",                     // 1: Manufacturer
   "TinyUSB Device",              // 2: Product
-  "123456",                      // 3: Serials, should use chip ID
+  "123456789012",                // 3: Serials, should use chip ID
   "TinyUSB CDC",                 // 4: CDC Interface
   "TinyUSB MSC",                 // 5: MSC Interface
 };

+ 1 - 1
examples/device/cdc_msc_freertos/src/usb_descriptors.c

@@ -218,7 +218,7 @@ char const* string_desc_arr [] =
   (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
   "TinyUSB",                     // 1: Manufacturer
   "TinyUSB Device",              // 2: Product
-  "123456",                      // 3: Serials, should use chip ID
+  "123456789012",                // 3: Serials, should use chip ID
   "TinyUSB CDC",                 // 4: CDC Interface
   "TinyUSB MSC",                 // 5: MSC Interface
 };

+ 1 - 1
examples/device/msc_dual_lun/src/usb_descriptors.c

@@ -141,7 +141,7 @@ char const* string_desc_arr [] =
   (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
   "TinyUSB",                     // 1: Manufacturer
   "TinyUSB Device",              // 2: Product
-  "123456",                      // 3: Serials, should use chip ID
+  "123456789012",                // 3: Serials, should use chip ID
 };
 
 static uint16_t _desc_str[32];

+ 13 - 6
examples/device/net_lwip_webserver/Makefile

@@ -3,13 +3,11 @@ DEPS_SUBMODULES += lib/lwip
 include ../../../tools/top.mk
 include ../../make.mk
 
-CFLAGS += \
-  -DPBUF_POOL_SIZE=2 \
-  -DTCP_WND=2*TCP_MSS \
-  -DHTTPD_USE_CUSTOM_FSDATA=0
-  
 # suppress warning caused by lwip
-CFLAGS += -Wno-error=null-dereference
+CFLAGS += \
+  -Wno-error=null-dereference \
+  -Wno-error=unused-parameter \
+  -Wno-error=unused-variable
 
 INC += \
   src \
@@ -53,6 +51,15 @@ SRC_C += \
   lib/lwip/src/core/ipv4/ip4.c \
   lib/lwip/src/core/ipv4/ip4_addr.c \
   lib/lwip/src/core/ipv4/ip4_frag.c \
+  lib/lwip/src/core/ipv6/dhcp6.c \
+  lib/lwip/src/core/ipv6/ethip6.c \
+  lib/lwip/src/core/ipv6/icmp6.c \
+  lib/lwip/src/core/ipv6/inet6.c \
+  lib/lwip/src/core/ipv6/ip6.c \
+  lib/lwip/src/core/ipv6/ip6_addr.c \
+  lib/lwip/src/core/ipv6/ip6_frag.c \
+  lib/lwip/src/core/ipv6/mld6.c \
+  lib/lwip/src/core/ipv6/nd6.c \
   lib/lwip/src/netif/ethernet.c \
   lib/lwip/src/netif/slipif.c \
   lib/lwip/src/apps/http/httpd.c \

+ 12 - 0
examples/device/net_lwip_webserver/src/lwipopts.h

@@ -42,11 +42,14 @@
 #define LWIP_ICMP                       1
 #define LWIP_UDP                        1
 #define LWIP_TCP                        1
+#define LWIP_IPV4                       1
+#define LWIP_IPV6                       0
 #define ETH_PAD_SIZE                    0
 #define LWIP_IP_ACCEPT_UDP_PORT(p)      ((p) == PP_NTOHS(67))
 
 #define TCP_MSS                         (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
 #define TCP_SND_BUF                     (2 * TCP_MSS)
+#define TCP_WND                         (TCP_MSS)
 
 #define ETHARP_SUPPORT_STATIC_ENTRIES   1
 
@@ -56,4 +59,13 @@
 
 #define LWIP_SINGLE_NETIF               1
 
+#define PBUF_POOL_SIZE                  2
+
+#define HTTPD_USE_CUSTOM_FSDATA         0
+
+#define LWIP_MULTICAST_PING             1
+#define LWIP_BROADCAST_PING             1
+#define LWIP_IPV6_MLD                   0
+#define LWIP_IPV6_SEND_ROUTER_SOLICIT   0
+
 #endif /* __LWIPOPTS_H__ */

+ 28 - 12
examples/device/net_lwip_webserver/src/main.c

@@ -50,8 +50,11 @@ try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00
 #include "dnserver.h"
 #include "lwip/init.h"
 #include "lwip/timeouts.h"
+#include "lwip/ethip6.h"
 #include "httpd.h"
 
+#define INIT_IP4(a,b,c,d) { PP_HTONL(LWIP_MAKEU32(a,b,c,d)) }
+
 /* lwip context */
 static struct netif netif_data;
 
@@ -64,24 +67,24 @@ static struct pbuf *received_frame;
 const uint8_t tud_network_mac_address[6] = {0x02,0x02,0x84,0x6A,0x96,0x00};
 
 /* network parameters of this MCU */
-static const ip_addr_t ipaddr  = IPADDR4_INIT_BYTES(192, 168, 7, 1);
-static const ip_addr_t netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
-static const ip_addr_t gateway = IPADDR4_INIT_BYTES(0, 0, 0, 0);
+static const ip4_addr_t ipaddr  = INIT_IP4(192, 168, 7, 1);
+static const ip4_addr_t netmask = INIT_IP4(255, 255, 255, 0);
+static const ip4_addr_t gateway = INIT_IP4(0, 0, 0, 0);
 
 /* database IP addresses that can be offered to the host; this must be in RAM to store assigned MAC addresses */
 static dhcp_entry_t entries[] =
 {
     /* mac ip address                          lease time */
-    { {0}, IPADDR4_INIT_BYTES(192, 168, 7, 2), 24 * 60 * 60 },
-    { {0}, IPADDR4_INIT_BYTES(192, 168, 7, 3), 24 * 60 * 60 },
-    { {0}, IPADDR4_INIT_BYTES(192, 168, 7, 4), 24 * 60 * 60 },
+    { {0}, INIT_IP4(192, 168, 7, 2), 24 * 60 * 60 },
+    { {0}, INIT_IP4(192, 168, 7, 3), 24 * 60 * 60 },
+    { {0}, INIT_IP4(192, 168, 7, 4), 24 * 60 * 60 },
 };
 
 static const dhcp_config_t dhcp_config =
 {
-    .router = IPADDR4_INIT_BYTES(0, 0, 0, 0),  /* router address (if any) */
+    .router = INIT_IP4(0, 0, 0, 0),            /* router address (if any) */
     .port = 67,                                /* listen port */
-    .dns = IPADDR4_INIT_BYTES(192, 168, 7, 1), /* dns server (if any) */
+    .dns = INIT_IP4(192, 168, 7, 1),           /* dns server (if any) */
     "usb",                                     /* dns suffix */
     TU_ARRAY_SIZE(entries),                    /* num entry */
     entries                                    /* entries */
@@ -108,11 +111,18 @@ static err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
   }
 }
 
-static err_t output_fn(struct netif *netif, struct pbuf *p, const ip_addr_t *addr)
+static err_t ip4_output_fn(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr)
 {
   return etharp_output(netif, p, addr);
 }
 
+#if LWIP_IPV6
+static err_t ip6_output_fn(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr)
+{
+  return ethip6_output(netif, p, addr);
+}
+#endif
+
 static err_t netif_init_cb(struct netif *netif)
 {
   LWIP_ASSERT("netif != NULL", (netif != NULL));
@@ -122,7 +132,10 @@ static err_t netif_init_cb(struct netif *netif)
   netif->name[0] = 'E';
   netif->name[1] = 'X';
   netif->linkoutput = linkoutput_fn;
-  netif->output = output_fn;
+  netif->output = ip4_output_fn;
+#if LWIP_IPV6
+  netif->output_ip6 = ip6_output_fn;
+#endif
   return ERR_OK;
 }
 
@@ -138,11 +151,14 @@ static void init_lwip(void)
   netif->hwaddr[5] ^= 0x01;
 
   netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ip_input);
+#if LWIP_IPV6
+  netif_create_ip6_linklocal_address(netif, 1);
+#endif
   netif_set_default(netif);
 }
 
 /* handle any DNS requests from dns-server */
-bool dns_query_proc(const char *name, ip_addr_t *addr)
+bool dns_query_proc(const char *name, ip4_addr_t *addr)
 {
   if (0 == strcmp(name, "tiny.usb"))
   {
@@ -218,7 +234,7 @@ int main(void)
   init_lwip();
   while (!netif_is_up(&netif_data));
   while (dhserv_init(&dhcp_config) != ERR_OK);
-  while (dnserv_init(&ipaddr, 53, dns_query_proc) != ERR_OK);
+  while (dnserv_init(IP_ADDR_ANY, 53, dns_query_proc) != ERR_OK);
   httpd_init();
 
   while (1)

+ 5 - 4
examples/device/video_capture/src/usb_descriptors.h

@@ -48,7 +48,7 @@ enum {
     /* control */\
     + TUD_VIDEO_DESC_STD_VC_LEN\
     + (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
-    + TUD_VIDEO_DESC_INPUT_TERM_LEN\
+    + TUD_VIDEO_DESC_CAMERA_TERM_LEN\
     + TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
     /* Interface 1, Alternate 0 */\
     + TUD_VIDEO_DESC_STD_VS_LEN\
@@ -79,9 +79,11 @@ enum {
   TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
     TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \
          /* wTotalLength - bLength */ \
-         TUD_VIDEO_DESC_INPUT_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \
+         TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \
          UVC_CLOCK_FREQUENCY, 1), \
-      TUD_VIDEO_DESC_INPUT_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, VIDEO_ETT_COMPOSITE_CONNECTOR, 0, 0), \
+      TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\
+                                 /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\
+                                 /*wObjectiveFocalLength*/0, /*bmControls*/0), \
       TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
   /* Video stream alt. 0 */ \
   TUD_VIDEO_DESC_STD_VS( 1, 0, 0, 0), \
@@ -108,5 +110,4 @@ enum {
     /* EP */ \
     TUD_VIDEO_DESC_EP_ISO(_epin, _epsize, 1)
 
-
 #endif

+ 24 - 1
hw/bsp/rp2040/family.cmake

@@ -77,7 +77,6 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
 			${TOP}/src/class/video/video_device.c
 			)
 
-
 	# Base config for host mode; wrapped by SDK's tinyusb_host
 	add_library(tinyusb_host_base INTERFACE)
 	target_sources(tinyusb_host_base INTERFACE
@@ -153,4 +152,28 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
 		enable_language(C CXX ASM)
 		pico_sdk_init()
 	endfunction()
+
+	# This method must be called from the project scope to suppress known warnings in TinyUSB source files
+	function(suppress_tinyusb_warnings)
+		set_source_files_properties(
+				${PICO_TINYUSB_PATH}/src/tusb.c
+				PROPERTIES
+				COMPILE_FLAGS "-Wno-conversion")
+		set_source_files_properties(
+				${PICO_TINYUSB_PATH}/src/common/tusb_fifo.c
+				PROPERTIES
+				COMPILE_FLAGS "-Wno-conversion -Wno-cast-qual")
+		set_source_files_properties(
+				${PICO_TINYUSB_PATH}/src/device/usbd.c
+				PROPERTIES
+				COMPILE_FLAGS "-Wno-conversion -Wno-cast-qual -Wno-null-dereference")
+		set_source_files_properties(
+				${PICO_TINYUSB_PATH}/src/device/usbd_control.c
+				PROPERTIES
+				COMPILE_FLAGS "-Wno-conversion")
+		set_source_files_properties(
+				${PICO_TINYUSB_PATH}/src/class/cdc/cdc_device.c
+				PROPERTIES
+				COMPILE_FLAGS "-Wno-conversion")
+	endfunction()
 endif()

+ 8 - 8
lib/networking/dhserver.c

@@ -96,19 +96,19 @@ static const dhcp_config_t *config = NULL;
 
 char magic_cookie[] = {0x63,0x82,0x53,0x63};
 
-static ip_addr_t get_ip(const uint8_t *pnt)
+static ip4_addr_t get_ip(const uint8_t *pnt)
 {
-  ip_addr_t result;
+  ip4_addr_t result;
   memcpy(&result, pnt, sizeof(result));
   return result;
 }
 
-static void set_ip(uint8_t *pnt, ip_addr_t value)
+static void set_ip(uint8_t *pnt, ip4_addr_t value)
 {
   memcpy(pnt, &value.addr, sizeof(value.addr));
 }
 
-static dhcp_entry_t *entry_by_ip(ip_addr_t ip)
+static dhcp_entry_t *entry_by_ip(ip4_addr_t ip)
 {
 	int i;
 	for (i = 0; i < config->num_entry; i++)
@@ -162,11 +162,11 @@ uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr)
 int fill_options(void *dest,
 	uint8_t msg_type,
 	const char *domain,
-	ip_addr_t dns,
+	ip4_addr_t dns,
 	int lease_time,
-	ip_addr_t serverid,
-	ip_addr_t router,
-	ip_addr_t subnet)
+	ip4_addr_t serverid,
+	ip4_addr_t router,
+	ip4_addr_t subnet)
 {
 	uint8_t *ptr = (uint8_t *)dest;
 	/* ACK message type */

+ 5 - 5
lib/networking/dhserver.h

@@ -41,16 +41,16 @@
 
 typedef struct dhcp_entry
 {
-	uint8_t  mac[6];
-	ip_addr_t addr;
-	uint32_t lease;
+	uint8_t    mac[6];
+	ip4_addr_t addr;
+	uint32_t   lease;
 } dhcp_entry_t;
 
 typedef struct dhcp_config
 {
-	ip_addr_t     router;
+	ip4_addr_t    router;
 	uint16_t      port;
-	ip_addr_t     dns;
+	ip4_addr_t    dns;
 	const char   *domain;
 	int           num_entry;
 	dhcp_entry_t *entries;

+ 1 - 1
lib/networking/dnserver.c

@@ -136,7 +136,7 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
 	dns_header_t *header;
 	static dns_query_t query;
 	struct pbuf *out;
-	ip_addr_t host_addr;
+	ip4_addr_t host_addr;
 	dns_answer_t *answer;
 
 	(void)arg;

+ 1 - 1
lib/networking/dnserver.h

@@ -39,7 +39,7 @@
 #include "lwip/udp.h"
 #include "netif/etharp.h"
 
-typedef bool (*dns_query_proc_t)(const char *name, ip_addr_t *addr);
+typedef bool (*dns_query_proc_t)(const char *name, ip4_addr_t *addr);
 
 err_t dnserv_init(const ip_addr_t *bind, uint16_t port, dns_query_proc_t query_proc);
 void  dnserv_free(void);

+ 12 - 4
src/class/video/video.h

@@ -373,6 +373,7 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
 #define TUD_VIDEO_DESC_CS_VC_LEN                  12
 #define TUD_VIDEO_DESC_INPUT_TERM_LEN             8
 #define TUD_VIDEO_DESC_OUTPUT_TERM_LEN            9
+#define TUD_VIDEO_DESC_CAMERA_TERM_LEN            18
 #define TUD_VIDEO_DESC_STD_VS_LEN                 9
 #define TUD_VIDEO_DESC_CS_VS_IN_LEN               13
 #define TUD_VIDEO_DESC_CS_VS_OUT_LEN              9
@@ -382,10 +383,10 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
 #define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN   6
 
 /* 2.2 compression formats */
-#define TUD_VIDEO_GUID_YUY2   0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x00,0x80,0x71,0x9B,0x38,0x00,0xAA,0x00
-#define TUD_VIDEO_GUID_NV12   0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x00,0x80,0x71,0x9B,0x38,0x00,0xAA,0x00
-#define TUD_VIDEO_GUID_M420   0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x00,0x80,0x71,0x9B,0x38,0x00,0xAA,0x00
-#define TUD_VIDEO_GUID_I420   0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x00,0x80,0x71,0x9B,0x38,0x00,0xAA,0x00
+#define TUD_VIDEO_GUID_YUY2   0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+#define TUD_VIDEO_GUID_NV12   0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+#define TUD_VIDEO_GUID_M420   0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+#define TUD_VIDEO_GUID_I420   0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
 
 #define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
   TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \
@@ -412,6 +413,13 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
   TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \
     _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx
 
+/* 3.7.2.3 */
+#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \
+  TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \
+    _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \
+    U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \
+    TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls)
+
 /* 3.9.1 */
 #define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \
   TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \

+ 90 - 32
src/class/video/video_device.c

@@ -354,21 +354,25 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
   return true;
 }
 
-/** Set the minimum or the maximum values to variables which need to negotiate with the host
+/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host
  *
- * @param[in]     set_max     If true, the maximum values is set, otherwise the minimum value is set.
+ * @param[in]     request     GET_MAX, GET_MIN, GET_RES or GET_DEF
  * @param[in,out] param       Target
  */
-static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, bool set_max,
+static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request,
                                             video_probe_and_commit_control_t *param)
 {
   uint_fast8_t const fmtnum = param->bFormatIndex;
   if (!fmtnum) {
-    if (set_max) {
-      tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
-      param->bFormatIndex   = vs->stm.bNumFormats;
-    } else {
-      param->bFormatIndex   = 1;
+    switch (request) {
+      case VIDEO_REQUEST_GET_MAX:
+        param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
+        break;
+      case VIDEO_REQUEST_GET_MIN:
+      case VIDEO_REQUEST_GET_DEF:
+        param->bFormatIndex = 1;
+        break;
+      default: return false;
     }
     /* Set the parameters determined by the format  */
     param->wKeyFrameRate    = 1;
@@ -391,7 +395,18 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
     tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
     void const *end = _end_of_streaming_descriptor(vs);
     tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
-    frmnum = set_max ? fmt->bNumFrameDescriptors: 1;
+    switch (request) {
+      case VIDEO_REQUEST_GET_MAX:
+        frmnum = fmt->bNumFrameDescriptors;
+        break;
+      case VIDEO_REQUEST_GET_MIN:
+        frmnum = 1;
+        break;
+      case VIDEO_REQUEST_GET_DEF:
+        frmnum = fmt->bDefaultFrameIndex;
+        break;
+      default: return false;
+    }
     param->bFrameIndex = frmnum;
     /* Set the parameters determined by the frame */
     tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
@@ -405,18 +420,56 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
     tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
     tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
 
-    uint_fast32_t interval;
-    uint_fast8_t num_intervals = frm->bFrameIntervalType;
-    if (!num_intervals) {
-      interval = set_max ? frm->dwFrameInterval[1]: frm->dwFrameInterval[0];
-    } else {
-      interval = set_max ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[0];
+    uint_fast32_t interval, interval_ms;
+    switch (request) {
+      case VIDEO_REQUEST_GET_MAX:
+        {
+          uint_fast32_t min_interval, max_interval;
+          uint_fast8_t num_intervals = frm->bFrameIntervalType;
+          max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1];
+          min_interval = frm->dwFrameInterval[0];
+          interval = max_interval;
+          interval_ms = min_interval / 10000;
+        }
+        break;
+      case VIDEO_REQUEST_GET_MIN:
+        {
+          uint_fast32_t min_interval, max_interval;
+          uint_fast8_t num_intervals = frm->bFrameIntervalType;
+          max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1];
+          min_interval = frm->dwFrameInterval[0];
+          interval = min_interval;
+          interval_ms = max_interval / 10000;
+        }
+        break;
+      case VIDEO_REQUEST_GET_DEF:
+        interval = frm->dwDefaultFrameInterval;
+        interval_ms = interval / 10000;
+        break;
+      case VIDEO_REQUEST_GET_RES:
+        {
+          uint_fast8_t num_intervals = frm->bFrameIntervalType;
+          if (num_intervals) {
+            interval = 0;
+          } else {
+            interval = frm->dwFrameInterval[2];
+            interval_ms = interval / 10000;
+          }
+        }
+        break;
+      default: return false;
     }
     param->dwFrameInterval = interval;
-    uint_fast32_t interval_ms = interval / 10000;
-    TU_ASSERT(interval_ms);
-    uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
-    param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2;
+    if (!interval) {
+      param->dwMaxPayloadTransferSize = 0;
+    } else {
+      uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
+      if (!interval_ms) {
+        param->dwMaxPayloadTransferSize = frame_size + 2;
+      } else {
+        param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2;
+      }
+    }
     return true;
   }
   return true;
@@ -781,32 +834,28 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
           return VIDEO_ERROR_NONE;
 
         case VIDEO_REQUEST_GET_MIN:
+        case VIDEO_REQUEST_GET_MAX:
+        case VIDEO_REQUEST_GET_RES:
+        case VIDEO_REQUEST_GET_DEF:
           if (stage == CONTROL_STAGE_SETUP)
           {
             TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
-
             video_probe_and_commit_control_t tmp;
             tmp = *(video_probe_and_commit_control_t*)&self->ep_buf;
-            TU_VERIFY(_negotiate_streaming_parameters(self, false, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
-            TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+            TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
+            TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
           }
           return VIDEO_ERROR_NONE;
 
-        case VIDEO_REQUEST_GET_MAX:
+        case VIDEO_REQUEST_GET_LEN:
           if (stage == CONTROL_STAGE_SETUP)
           {
-            TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
-            video_probe_and_commit_control_t tmp;
-            tmp = *(video_probe_and_commit_control_t*)&self->ep_buf;
-            TU_VERIFY(_negotiate_streaming_parameters(self, true, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
-            TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+            TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
+            uint16_t len = sizeof(video_probe_and_commit_control_t);
+            TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
           }
           return VIDEO_ERROR_NONE;
 
-        case VIDEO_REQUEST_GET_RES: return VIDEO_ERROR_UNKNOWN;
-        case VIDEO_REQUEST_GET_DEF: return VIDEO_ERROR_UNKNOWN;
-        case VIDEO_REQUEST_GET_LEN: return VIDEO_ERROR_UNKNOWN;
-
         case VIDEO_REQUEST_GET_INFO:
           if (stage == CONTROL_STAGE_SETUP)
           {
@@ -841,6 +890,15 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
           }
           return VIDEO_ERROR_NONE;
 
+        case VIDEO_REQUEST_GET_LEN:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
+            uint16_t len = sizeof(video_probe_and_commit_control_t);
+            TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
         case VIDEO_REQUEST_GET_INFO:
           if (stage == CONTROL_STAGE_SETUP)
           {

+ 7 - 0
src/device/dcd.h

@@ -106,7 +106,14 @@ typedef struct TU_ATTR_ALIGNED(4)
 void dcd_init       (uint8_t rhport);
 
 // Interrupt Handler
+#if __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
 void dcd_int_handler(uint8_t rhport);
+#if __GNUC__
+#pragma GCC diagnostic pop
+#endif
 
 // Enable device interrupt
 void dcd_int_enable (uint8_t rhport);

+ 7 - 0
src/osal/osal.h

@@ -67,6 +67,10 @@ typedef void (*osal_task_func_t)( void * );
 // OSAL Porting API
 //--------------------------------------------------------------------+
 
+#if __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
 //------------- Semaphore -------------//
 static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
 static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
@@ -84,6 +88,9 @@ static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
 static inline bool osal_queue_receive(osal_queue_t qhdl, void* data);
 static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
 static inline bool osal_queue_empty(osal_queue_t qhdl);
+#if __GNUC__
+#pragma GCC diagnostic pop
+#endif
 
 #if 0  // TODO remove subtask related macros later
 // Sub Task

+ 20 - 4
src/portable/dialog/da146xx/dcd_da146xx.c

@@ -368,8 +368,8 @@ static void start_rx_packet(xfer_ctl_t *xfer)
     else
     {
       // Other endpoint is using DMA in that direction, fall back to interrupts.
-      // For endpoint size greater then FIFO size enable FIFO level warning interrupt
-      // when FIFO has less then 17 bytes free.
+      // For endpoint size greater than FIFO size enable FIFO level warning interrupt
+      // when FIFO has less than 17 bytes free.
       regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk;
       USB->USB_FWMSK_REG |= 1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos);
     }
@@ -420,7 +420,7 @@ static void start_tx_packet(xfer_ctl_t *xfer)
   regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk;
 }
 
-static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
+static uint16_t read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
 {
   EPx_REGS *regs = XFER_REGS(xfer);
   uint16_t remaining = xfer->total_len - xfer->transferred - xfer->last_packet_size;
@@ -433,6 +433,8 @@ static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
   for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd;
 
   xfer->last_packet_size += receive_this_time;
+
+  return bytes_in_fifo - receive_this_time;
 }
 
 static void handle_ep0_rx(void)
@@ -562,7 +564,7 @@ static void handle_epx_rx_ev(uint8_t ep)
       // FIFO maybe empty if DMA read it before or it's final iteration and function already read all that was to read.
       if (fifo_bytes > 0)
       {
-        read_rx_fifo(xfer, fifo_bytes);
+        fifo_bytes = read_rx_fifo(xfer, fifo_bytes);
       }
       if (GET_BIT(rxs, USB_USB_RXS1_REG_USB_RX_LAST))
       {
@@ -577,6 +579,13 @@ static void handle_epx_rx_ev(uint8_t ep)
           xfer->transferred += xfer->last_packet_size;
           if (xfer->total_len == xfer->transferred || xfer->last_packet_size < xfer->max_packet_size || xfer->iso)
           {
+            if (fifo_bytes)
+            {
+              // There are extra bytes in the FIFO just flush them
+              regs->rxc |= USB_USB_RXC1_REG_USB_FLUSH_Msk;
+              fifo_bytes = 0;
+            }
+
             dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, XFER_RESULT_SUCCESS, true);
           }
           else
@@ -632,6 +641,13 @@ static void handle_epx_tx_ev(xfer_ctl_t *xfer)
         return;
       }
     }
+    else if (regs->epc_in & USB_USB_EPC1_REG_USB_STALL_Msk)
+    {
+      // TX_DONE also indicates that STALL packet was just sent, there is
+      // no point to put anything into transmit FIFO. It could result in
+      // empty packet being scheduled.
+      return;
+    }
   }
   if (txs & USB_USB_TXS1_REG_USB_TX_URUN_Msk)
   {

+ 11 - 11
src/portable/raspberrypi/rp2040/dcd_rp2040.c

@@ -70,7 +70,7 @@ static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
 static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
 {
   // size must be multiple of 64
-  uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
+  uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
 
   // double buffered Bulk endpoint
   if ( transfer_type == TUSB_XFER_BULK )
@@ -88,7 +88,7 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
   pico_info("  Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
 
   // Fill in endpoint control register with buffer offset
-  uint32_t const reg = EP_CTRL_ENABLE_BITS | (transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
+  uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
 
   *ep->endpoint_control = reg;
 }
@@ -177,7 +177,7 @@ static void hw_handle_buff_status(void)
     uint32_t remaining_buffers = usb_hw->buf_status;
     pico_trace("buf_status = 0x%08x\n", remaining_buffers);
     uint bit = 1u;
-    for (uint i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++)
+    for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++)
     {
         if (remaining_buffers & bit)
         {
@@ -365,19 +365,19 @@ void dcd_init (uint8_t rhport)
   dcd_connect(rhport);
 }
 
-void dcd_int_enable(uint8_t rhport)
+void dcd_int_enable(__unused uint8_t rhport)
 {
     assert(rhport == 0);
     irq_set_enabled(USBCTRL_IRQ, true);
 }
 
-void dcd_int_disable(uint8_t rhport)
+void dcd_int_disable(__unused uint8_t rhport)
 {
     assert(rhport == 0);
     irq_set_enabled(USBCTRL_IRQ, false);
 }
 
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
 {
   assert(rhport == 0);
 
@@ -386,7 +386,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
   hw_endpoint_xfer(0x80, NULL, 0);
 }
 
-void dcd_remote_wakeup(uint8_t rhport)
+void dcd_remote_wakeup(__unused uint8_t rhport)
 {
     pico_info("dcd_remote_wakeup %d\n", rhport);
     assert(rhport == 0);
@@ -394,14 +394,14 @@ void dcd_remote_wakeup(uint8_t rhport)
 }
 
 // disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
+void dcd_disconnect(__unused uint8_t rhport)
 {
   (void) rhport;
   usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
 }
 
 // connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport)
+void dcd_connect(__unused uint8_t rhport)
 {
   (void) rhport;
   usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
@@ -423,7 +423,7 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
   }
 }
 
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+bool dcd_edpt_open (__unused uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 {
     assert(rhport == 0);
     hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
@@ -438,7 +438,7 @@ void dcd_edpt_close_all (uint8_t rhport)
   reset_non_control_endpoints();
 }
 
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 {
     assert(rhport == 0);
     hw_endpoint_xfer(ep_addr, buffer, total_bytes);

+ 5 - 5
src/portable/raspberrypi/rp2040/rp2040_usb.c

@@ -38,7 +38,7 @@ const char *ep_dir_string[] = {
         "in",
 };
 
-static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) {
+static inline void _hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
     // todo add critsec as necessary to prevent issues between worker and IRQ...
     //  note that this is perhaps as simple as disabling IRQs because it would make
     //  sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
@@ -107,7 +107,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
 static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
 {
   uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
-  ep->remaining_len -= buflen;
+  ep->remaining_len = (uint16_t)(ep->remaining_len - buflen);
 
   uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
 
@@ -214,7 +214,7 @@ static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
     // sent some data can increase the length we have sent
     assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
 
-    ep->xferred_len += xferred_bytes;
+    ep->xferred_len = (uint16_t)(ep->xferred_len + xferred_bytes);
   }else
   {
     // If we have received some data, so can increase the length
@@ -222,7 +222,7 @@ static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
     assert(buf_ctrl & USB_BUF_CTRL_FULL);
 
     memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes);
-    ep->xferred_len += xferred_bytes;
+    ep->xferred_len = (uint16_t)(ep->xferred_len + xferred_bytes);
     ep->user_buf += xferred_bytes;
   }
 
@@ -242,7 +242,7 @@ static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
   // Update hw endpoint struct with info from hardware
   // after a buff status interrupt
 
-  uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+  uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
   TU_LOG(3, "  Sync BufCtrl: [0] = 0x%04u  [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
 
   // always sync buffer 0

+ 1 - 1
src/tusb_option.h

@@ -28,7 +28,7 @@
 #define _TUSB_OPTION_H_
 
 #define TUSB_VERSION_MAJOR     0
-#define TUSB_VERSION_MINOR     11
+#define TUSB_VERSION_MINOR     12
 #define TUSB_VERSION_REVISION  0
 #define TUSB_VERSION_STRING    TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)