Ver Fonte

vfs_usb_serial: set secondary selection for making usb port can output under default menu

Cao Sen Miao há 4 anos atrás
pai
commit
adfb7bed96

+ 1 - 1
components/cxx/test/test_cxx.cpp

@@ -62,7 +62,7 @@ TEST_CASE("can use std::vector", "[cxx]")
 #elif CONFIG_IDF_TARGET_ESP32S2
 #define LEAKS "800"
 #elif CONFIG_IDF_TARGET_ESP32C3
-#define LEAKS "600"
+#define LEAKS "700"
 #else
 #error "unknown target in CXX tests, can't set leaks threshold"
 #endif

+ 24 - 1
components/esp_system/Kconfig

@@ -236,8 +236,31 @@ menu "ESP System Settings"
             bool "None"
     endchoice
 
-    # Internal option, indicates that console UART is used (and not USB, for example)
+    choice ESP_CONSOLE_SECONDARY
+        depends on IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
+        prompt "Channel for console secondary output"
+        default ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+        help
+            This secondary option supports output through other specific port like USB_SERIAL_JTAG
+            when UART0 port as a primary is selected but not connected. This secondary output currently only supports
+            non-blocking mode without using REPL. If you want to output in blocking mode with REPL or
+            input through this secondary port, please change the primary config to this port
+            in `Channel for console output` menu.
+        config ESP_CONSOLE_SECONDARY_NONE
+            bool "No secondary console"
+        config ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+            bool "USB_SERIAL_JTAG PORT"
+            depends on !ESP_CONSOLE_USB_SERIAL_JTAG
+            help
+                This option supports output through USB_SERIAL_JTAG port when the UART0 port is not connected.
+                The output currently only supports non-blocking mode without using the console.
+                If you want to output in blocking mode with REPL or input through USB_SERIAL_JTAG port,
+                please change the primary config to ESP_CONSOLE_USB_SERIAL_JTAG above.
+    endchoice
+
+
     config ESP_CONSOLE_UART
+        # Internal option, indicates that console UART is used (and not USB, for example)
         bool
         default y if ESP_CONSOLE_UART_DEFAULT || ESP_CONSOLE_UART_CUSTOM
 

+ 7 - 21
components/esp_system/startup.c

@@ -50,9 +50,7 @@
 #include "esp_pm.h"
 #include "esp_private/pm_impl.h"
 #include "esp_pthread.h"
-#include "esp_private/usb_console.h"
-#include "esp_vfs_cdcacm.h"
-#include "esp_vfs_usb_serial_jtag.h"
+#include "esp_vfs_console.h"
 
 #include "brownout.h"
 
@@ -83,9 +81,6 @@
     #error "System has been configured to run on multiple cores, but target SoC only has a single core."
 #endif
 
-#define STRINGIFY(s) STRINGIFY2(s)
-#define STRINGIFY2(s) #s
-
 uint64_t g_startup_time = 0;
 
 #if SOC_APB_BACKUP_DMA
@@ -271,23 +266,14 @@ static void do_core_init(void)
     esp_timer_early_init();
     esp_newlib_time_init();
 
-#ifdef CONFIG_VFS_SUPPORT_IO
-#ifdef CONFIG_ESP_CONSOLE_UART
-    esp_vfs_dev_uart_register();
-    const char *default_stdio_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM);
-#endif // CONFIG_ESP_CONSOLE_UART
-#ifdef CONFIG_ESP_CONSOLE_USB_CDC
-    ESP_ERROR_CHECK(esp_usb_console_init());
-    ESP_ERROR_CHECK(esp_vfs_dev_cdcacm_register());
-    const char *default_stdio_dev = "/dev/cdcacm";
-#endif // CONFIG_ESP_CONSOLE_USB_CDC
-#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
-    ESP_ERROR_CHECK(esp_vfs_dev_usb_serial_jtag_register());
-    const char *default_stdio_dev = "/dev/usbserjtag";
-#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
-#endif // CONFIG_VFS_SUPPORT_IO
+#if CONFIG_VFS_SUPPORT_IO
+    // VFS console register.
+    esp_err_t vfs_err = esp_vfs_console_register();
+    assert(vfs_err == ESP_OK && "Failed to register vfs console");
+#endif
 
 #if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
+    const static char *default_stdio_dev = "/dev/console/";
     esp_reent_init(_GLOBAL_REENT);
     _GLOBAL_REENT->_stdin  = fopen(default_stdio_dev, "r");
     _GLOBAL_REENT->_stdout = fopen(default_stdio_dev, "w");

+ 3 - 1
components/vfs/CMakeLists.txt

@@ -2,14 +2,16 @@ idf_component_register(SRCS "vfs.c"
                             "vfs_eventfd.c"
                             "vfs_uart.c"
                             "vfs_semihost.c"
+                            "vfs_console.c"
                     INCLUDE_DIRS include
+                    PRIV_INCLUDE_DIRS private_include
                     PRIV_REQUIRES driver)
 
 if(CONFIG_ESP_CONSOLE_USB_CDC)
     target_sources(${COMPONENT_LIB} PRIVATE "vfs_cdcacm.c")
 endif()
 
-if(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)
+if(CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG OR CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)
     target_sources(${COMPONENT_LIB} PRIVATE "vfs_usb_serial_jtag.c")
 endif()
 

+ 1 - 0
components/vfs/component.mk

@@ -1,3 +1,4 @@
+COMPONENT_PRIV_INCLUDEDIRS := private_include
 ifndef CONFIG_ESP_CONSOLE_USB_CDC
     COMPONENT_OBJEXCLUDE := vfs_cdcacm.o
 endif

+ 0 - 1
components/vfs/include/esp_vfs.h

@@ -246,7 +246,6 @@ typedef struct
 #endif // CONFIG_VFS_SUPPORT_SELECT
 } esp_vfs_t;
 
-
 /**
  * Register a virtual filesystem for given path prefix.
  *

+ 5 - 13
components/vfs/include/esp_vfs_cdcacm.h

@@ -1,16 +1,8 @@
-// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #pragma once
 

+ 24 - 0
components/vfs/include/esp_vfs_console.h

@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief add uart/usb_serial_jtag/usb_otg_acmcdc virtual filesystem driver
+ *
+ * This function is called from startup code to enable serial output
+ */
+esp_err_t esp_vfs_console_register(void);
+
+#ifdef __cplusplus
+}
+#endif

+ 5 - 13
components/vfs/include/esp_vfs_dev.h

@@ -1,16 +1,8 @@
-// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #pragma once
 

+ 5 - 13
components/vfs/include/esp_vfs_usb_serial_jtag.h

@@ -1,16 +1,8 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #pragma once
 

+ 101 - 0
components/vfs/private_include/esp_vfs_private.h

@@ -0,0 +1,101 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "esp_vfs.h"
+#include "esp_vfs_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct vfs_entry_ {
+    esp_vfs_t vfs;          // contains pointers to VFS functions
+    char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS
+    size_t path_prefix_len; // micro-optimization to avoid doing extra strlen
+    void* ctx;              // optional pointer which can be passed to VFS
+    int offset;             // index of this structure in s_vfs array
+} vfs_entry_t;
+
+
+/**
+ * @brief get pointer of uart vfs.
+ *
+ * This function is called in vfs_console in order to get the vfs implementation
+ * of uart.
+ *
+ * @return pointer to structure esp_vfs_t
+ */
+const esp_vfs_t *esp_vfs_uart_get_vfs(void);
+
+/**
+ * @brief get pointer of cdcacm vfs.
+ *
+ * This function is called in vfs_console in order to get the vfs implementation
+ * of cdcacm.
+ *
+ * @return pointer to structure esp_vfs_t
+ */
+const esp_vfs_t *esp_vfs_cdcacm_get_vfs(void);
+
+/**
+ * @brief get pointer of usb_serial_jtag vfs.
+ *
+ * This function is called in vfs_console in order to get the vfs implementation
+ * of usb_serial_jtag.
+ *
+ * @return pointer to structure esp_vfs_nonblocking_console_t
+ */
+const esp_vfs_t *esp_vfs_usb_serial_jtag_get_vfs(void);
+
+/**
+ * Register a virtual filesystem.
+ *
+ * @param base_path  file path prefix associated with the filesystem.
+ *                   Must be a zero-terminated C string, may be empty.
+ *                   If not empty, must be up to ESP_VFS_PATH_MAX
+ *                   characters long, and at least 2 characters long.
+ *                   Name must start with a "/" and must not end with "/".
+ *                   For example, "/data" or "/dev/spi" are valid.
+ *                   These VFSes would then be called to handle file paths such as
+ *                   "/data/myfile.txt" or "/dev/spi/0".
+ *                   In the special case of an empty base_path, a "fallback"
+ *                   VFS is registered. Such VFS will handle paths which are not
+ *                   matched by any other registered VFS.
+ * @param len  Length of the base_path.
+ * @param vfs  Pointer to esp_vfs_t, a structure which maps syscalls to
+ *             the filesystem driver functions. VFS component doesn't
+ *             assume ownership of this pointer.
+ * @param ctx  If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer
+ *             which should be passed to VFS functions. Otherwise, NULL.
+ * @param vfs_index Index for getting the vfs content.
+ *
+ * @return  ESP_OK if successful.
+ *          ESP_ERR_NO_MEM if too many VFSes are registered.
+ *          ESP_ERR_INVALID_ARG if given an invalid parameter.
+ */
+esp_err_t esp_vfs_register_common(const char *base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index);
+
+/**
+ * Get vfs fd with given path.
+ *
+ * @param path file path prefix associated with the filesystem.
+ *
+ * @return Pointer to the `vfs_entry_t` corresponding to the given path, which cannot be NULL.
+ */
+const vfs_entry_t *get_vfs_for_path(const char *path);
+
+/**
+ * Get vfs fd with given vfs index.
+ *
+ * @param index VFS index.
+ *
+ * @return Pointer to the `vfs_entry_t` corresponding to the given path, which cannot be NULL.
+ */
+const vfs_entry_t *get_vfs_for_index(int index);
+
+#ifdef __cplusplus
+}
+#endif

+ 4 - 11
components/vfs/vfs.c

@@ -18,6 +18,7 @@
 #include "freertos/FreeRTOS.h"
 #include "freertos/semphr.h"
 #include "esp_vfs.h"
+#include "esp_vfs_private.h"
 #include "sdkconfig.h"
 
 #ifdef CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT
@@ -47,14 +48,6 @@ typedef struct {
     local_fd_t local_fd;
 } fd_table_t;
 
-typedef struct vfs_entry_ {
-    esp_vfs_t vfs;          // contains pointers to VFS functions
-    char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS
-    size_t path_prefix_len; // micro-optimization to avoid doing extra strlen
-    void* ctx;              // optional pointer which can be passed to VFS
-    int offset;             // index of this structure in s_vfs array
-} vfs_entry_t;
-
 typedef struct {
     bool isset; // none or at least one bit is set in the following 3 fd sets
     fd_set readfds;
@@ -68,7 +61,7 @@ static size_t s_vfs_count = 0;
 static fd_table_t s_fd_table[MAX_FDS] = { [0 ... MAX_FDS-1] = FD_TABLE_ENTRY_UNUSED };
 static _lock_t s_fd_table_lock;
 
-static esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index)
+esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index)
 {
     if (len != LEN_PATH_PREFIX_IGNORED) {
         /* empty prefix is allowed, "/" is not allowed */
@@ -263,7 +256,7 @@ esp_err_t esp_vfs_unregister_fd(esp_vfs_id_t vfs_id, int fd)
     return ret;
 }
 
-static inline const vfs_entry_t *get_vfs_for_index(int index)
+const vfs_entry_t *get_vfs_for_index(int index)
 {
     if (index < 0 || index >= s_vfs_count) {
         return NULL;
@@ -308,7 +301,7 @@ static const char* translate_path(const vfs_entry_t* vfs, const char* src_path)
     return src_path + vfs->path_prefix_len;
 }
 
-static const vfs_entry_t* get_vfs_for_path(const char* path)
+const vfs_entry_t* get_vfs_for_path(const char* path)
 {
     const vfs_entry_t* best_match = NULL;
     ssize_t best_match_prefix_len = -1;

+ 21 - 23
components/vfs/vfs_cdcacm.c

@@ -1,16 +1,8 @@
-// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #include <string.h>
 #include <stdbool.h>
@@ -309,17 +301,23 @@ void esp_vfs_dev_cdcacm_set_rx_line_endings(esp_line_endings_t mode)
     s_rx_mode = mode;
 }
 
+static const esp_vfs_t vfs = {
+    .flags = ESP_VFS_FLAG_DEFAULT,
+    .write = &cdcacm_write,
+    .open = &cdcacm_open,
+    .fstat = &cdcacm_fstat,
+    .close = &cdcacm_close,
+    .read = &cdcacm_read,
+    .fcntl = &cdcacm_fcntl,
+    .fsync = &cdcacm_fsync
+};
+
+const esp_vfs_t *esp_vfs_cdcacm_get_vfs(void)
+{
+    return &vfs;
+}
+
 esp_err_t esp_vfs_dev_cdcacm_register(void)
 {
-    const esp_vfs_t vfs = {
-        .flags = ESP_VFS_FLAG_DEFAULT,
-        .write = &cdcacm_write,
-        .open = &cdcacm_open,
-        .fstat = &cdcacm_fstat,
-        .close = &cdcacm_close,
-        .read = &cdcacm_read,
-        .fcntl = &cdcacm_fcntl,
-        .fsync = &cdcacm_fsync
-    };
     return esp_vfs_register("/dev/cdcacm", &vfs, NULL);
 }

+ 218 - 0
components/vfs/vfs_console.c

@@ -0,0 +1,218 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "esp_vfs_console.h"
+#include "esp_rom_sys.h"
+#include "esp_vfs_cdcacm.h"
+#include "esp_vfs_private.h"
+#include "esp_vfs_usb_serial_jtag.h"
+#include "esp_vfs_dev.h"
+#include "esp_private/usb_console.h"
+#include "sdkconfig.h"
+
+#define STRINGIFY(s) STRINGIFY2(s)
+#define STRINGIFY2(s) #s
+
+/**
+ * This file is to concentrate all the vfs(UART, USB_SERIAL_JTAG, CDCACM) console into one single file.
+ * Get the vfs information from their component (i.e. vfs_uart.c) through `esp_vfs_usb_xxx_get_console()`,
+ * which can help us to output some string to two different ports(i.e both through uart and usb_serial_jtag).
+ * Usually, we set a port as primary and another as secondary. For primary, it is used for all the features supported by each vfs implementation,
+ * while the secondary is only used for output.
+ */
+
+typedef struct {
+    int fd_primary;
+    int fd_secondary;
+} vfs_console_context_t;
+
+#if CONFIG_VFS_SUPPORT_IO
+// Primary register part.
+#ifdef CONFIG_ESP_CONSOLE_UART
+const static char *primary_path = "/dev/uart";
+#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+const static char *primary_path = "/dev/usbserjtag";
+#elif CONFIG_ESP_CONSOLE_USB_CDC
+const static char *primary_path = "/dev/cdcacm";
+#endif
+
+// Secondary register part.
+#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+const static char *secondary_path = "/dev/secondary";
+static int secondary_vfs_index;
+#endif // Secondary part
+
+static int primary_vfs_index;
+
+static vfs_console_context_t vfs_console= {0};
+
+int console_open(const char * path, int flags, int mode)
+{
+// Primary port open
+#if CONFIG_ESP_CONSOLE_UART
+    vfs_console.fd_primary = get_vfs_for_path(primary_path)->vfs.open("/"STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM), flags, mode);
+#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+    vfs_console.fd_primary = esp_vfs_usb_serial_jtag_get_vfs()->open("/", flags, mode);
+#elif CONFIG_ESP_CONSOLE_USB_CDC
+    vfs_console.fd_primary = esp_vfs_cdcacm_get_vfs()->open("/", flags, mode);
+#endif
+
+// Secondary port open
+#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+    vfs_console.fd_secondary = get_vfs_for_path(secondary_path)->vfs.open("/", flags, mode);
+#endif
+    return 0;
+}
+
+ssize_t console_write(int fd, const void *data, size_t size)
+{
+    // All function calls are to primary, except from write and close, which will be forwarded to both primary and secondary.
+    get_vfs_for_index(primary_vfs_index)->vfs.write(vfs_console.fd_primary, data, size);
+#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+    get_vfs_for_index(secondary_vfs_index)->vfs.write(vfs_console.fd_secondary, data, size);
+#endif
+    return size;
+}
+
+int console_fstat(int fd, struct stat * st)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.fstat(fd, st);
+}
+
+int console_close(int fd)
+{
+    // All function calls are to primary, except from write and close, which will be forwarded to both primary and secondary.
+    get_vfs_for_index(primary_vfs_index)->vfs.close(vfs_console.fd_primary);
+#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+    get_vfs_for_index(secondary_vfs_index)->vfs.close(vfs_console.fd_secondary);
+#endif
+    return 0;
+}
+
+ssize_t console_read(int fd, void * dst, size_t size)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.read(vfs_console.fd_primary, dst, size);
+}
+
+int console_fcntl(int fd, int cmd, int arg)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.fcntl(vfs_console.fd_primary, cmd, arg);
+}
+
+int console_fsync(int fd)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.fsync(vfs_console.fd_primary);
+}
+
+#ifdef CONFIG_VFS_SUPPORT_DIR
+int console_access(const char *path, int amode)
+{
+    // currently only UART support DIR.
+    return get_vfs_for_index(primary_vfs_index)->vfs.access("/"STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM), amode);
+}
+#endif // CONFIG_VFS_SUPPORT_DIR
+
+#ifdef CONFIG_VFS_SUPPORT_SELECT
+static esp_err_t console_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+        esp_vfs_select_sem_t select_sem, void **end_select_args)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.start_select(nfds, readfds, writefds, exceptfds, select_sem, end_select_args);
+}
+
+esp_err_t console_end_select(void *end_select_args)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.end_select(end_select_args);
+}
+
+#endif // CONFIG_VFS_SUPPORT_SELECT
+
+#ifdef CONFIG_VFS_SUPPORT_TERMIOS
+
+int console_tcsetattr(int fd, int optional_actions, const struct termios *p)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.tcsetattr(vfs_console.fd_primary, optional_actions, p);
+}
+
+int console_tcgetattr(int fd, struct termios *p)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.tcgetattr(vfs_console.fd_primary, p);
+}
+
+int console_tcdrain(int fd)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.tcdrain(vfs_console.fd_primary);
+}
+
+int console_tcflush(int fd, int select)
+{
+    return get_vfs_for_index(primary_vfs_index)->vfs.tcflush(vfs_console.fd_primary, select);
+}
+#endif // CONFIG_VFS_SUPPORT_TERMIOS
+
+static const esp_vfs_t vfs = {
+    .flags = ESP_VFS_FLAG_DEFAULT,
+    .write = &console_write,
+    .open = &console_open,
+    .fstat = &console_fstat,
+    .close = &console_close,
+    .read = &console_read,
+    .fcntl = &console_fcntl,
+    .fsync = &console_fsync,
+#ifdef CONFIG_VFS_SUPPORT_DIR
+    .access = &console_access,
+#endif // CONFIG_VFS_SUPPORT_DIR
+#ifdef CONFIG_VFS_SUPPORT_SELECT
+    .start_select = &console_start_select,
+    .end_select = &console_end_select,
+#endif // CONFIG_VFS_SUPPORT_SELECT
+#ifdef CONFIG_VFS_SUPPORT_TERMIOS
+    .tcsetattr = &console_tcsetattr,
+    .tcgetattr = &console_tcgetattr,
+    .tcdrain = &console_tcdrain,
+    .tcflush = &console_tcflush,
+#endif // CONFIG_VFS_SUPPORT_TERMIOS
+};
+
+esp_err_t esp_vfs_dev_console_register(void)
+{
+    return esp_vfs_register("/dev/console", &vfs, NULL);
+}
+
+esp_err_t esp_vfs_console_register(void)
+{
+    esp_err_t err = ESP_OK;
+// Primary register part.
+#ifdef CONFIG_ESP_CONSOLE_UART
+    const esp_vfs_t *uart_vfs = esp_vfs_uart_get_vfs();
+    err = esp_vfs_register_common(primary_path, strlen(primary_path), uart_vfs, NULL, &primary_vfs_index);
+#elif CONFIG_ESP_CONSOLE_USB_CDC
+    const esp_vfs_t *cdcacm_vfs = esp_vfs_cdcacm_get_vfs();
+    err = esp_usb_console_init();
+    if (err != ESP_OK) {
+        return err;
+    }
+    err = esp_vfs_register_common(primary_path, strlen(primary_path), cdcacm_vfs, NULL, &primary_vfs_index);
+#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+    const esp_vfs_t *usb_serial_jtag_vfs = esp_vfs_usb_serial_jtag_get_vfs();
+    err = esp_vfs_register_common(primary_path, strlen(primary_path), usb_serial_jtag_vfs, NULL, &primary_vfs_index);
+#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+    if (err != ESP_OK) {
+        return err;
+    }
+
+// Secondary register part.
+#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
+    const esp_vfs_t *usb_serial_jtag_vfs = esp_vfs_usb_serial_jtag_get_vfs();
+    err = esp_vfs_register_common(secondary_path, strlen(secondary_path), usb_serial_jtag_vfs, NULL, &secondary_vfs_index);
+    if(err != ESP_OK) {
+        return err;
+    }
+#endif
+    err = esp_vfs_dev_console_register();
+    return err;
+}
+
+#endif // CONFIG_VFS_SUPPORT_IO

+ 30 - 32
components/vfs/vfs_uart.c

@@ -1,16 +1,8 @@
-// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #include <string.h>
 #include <stdbool.h>
@@ -969,31 +961,37 @@ static int uart_tcflush(int fd, int select)
 }
 #endif // CONFIG_VFS_SUPPORT_TERMIOS
 
-void esp_vfs_dev_uart_register(void)
-{
-    esp_vfs_t vfs = {
-        .flags = ESP_VFS_FLAG_DEFAULT,
-        .write = &uart_write,
-        .open = &uart_open,
-        .fstat = &uart_fstat,
-        .close = &uart_close,
-        .read = &uart_read,
-        .fcntl = &uart_fcntl,
-        .fsync = &uart_fsync,
+static const esp_vfs_t vfs = {
+    .flags = ESP_VFS_FLAG_DEFAULT,
+    .write = &uart_write,
+    .open = &uart_open,
+    .fstat = &uart_fstat,
+    .close = &uart_close,
+    .read = &uart_read,
+    .fcntl = &uart_fcntl,
+    .fsync = &uart_fsync,
 #ifdef CONFIG_VFS_SUPPORT_DIR
-        .access = &uart_access,
+    .access = &uart_access,
 #endif // CONFIG_VFS_SUPPORT_DIR
 #ifdef CONFIG_VFS_SUPPORT_SELECT
-        .start_select = &uart_start_select,
-        .end_select = &uart_end_select,
+    .start_select = &uart_start_select,
+    .end_select = &uart_end_select,
 #endif // CONFIG_VFS_SUPPORT_SELECT
 #ifdef CONFIG_VFS_SUPPORT_TERMIOS
-        .tcsetattr = &uart_tcsetattr,
-        .tcgetattr = &uart_tcgetattr,
-        .tcdrain = &uart_tcdrain,
-        .tcflush = &uart_tcflush,
+    .tcsetattr = &uart_tcsetattr,
+    .tcgetattr = &uart_tcgetattr,
+    .tcdrain = &uart_tcdrain,
+    .tcflush = &uart_tcflush,
 #endif // CONFIG_VFS_SUPPORT_TERMIOS
-    };
+};
+
+const esp_vfs_t* esp_vfs_uart_get_vfs(void)
+{
+    return &vfs;
+}
+
+void esp_vfs_dev_uart_register(void)
+{
     ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL));
 }
 

+ 40 - 45
components/vfs/vfs_usb_serial_jtag.c

@@ -1,16 +1,8 @@
-// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 //This is a simple non-blocking (well, tx may spin for a bit if the buffer
 //is full) USB-serial-jtag driver. Select etc is not supported yet.
@@ -113,23 +105,21 @@ static int usb_serial_jtag_open(const char * path, int flags, int mode)
 static void usb_serial_jtag_tx_char(int fd, int c)
 {
     uint8_t cc=(uint8_t)c;
-    if (usb_serial_jtag_ll_txfifo_writable()) {
-        //We can write to the buffer. Immediately do so.
-        usb_serial_jtag_ll_write_txfifo(&cc, 1);
-        s_ctx.last_tx_ts = esp_timer_get_time();
-    } else {
-        //Try to write to the buffer as long as we still expect the buffer to have
-        //a chance of being emptied by an active host. Just drop the data if there's
-        //no chance anymore.
-        while ((esp_timer_get_time() - s_ctx.last_tx_ts) < TX_FLUSH_TIMEOUT_US) {
-            if (usb_serial_jtag_ll_txfifo_writable()) {
-                //Woohoo, we can write again. Do so and exit the while loop.
-                usb_serial_jtag_ll_write_txfifo(&cc, 1);
-                s_ctx.last_tx_ts = esp_timer_get_time();
-                break;
-            }
+    // Try to write to the buffer as long as we still expect the buffer to have
+    // a chance of being emptied by an active host. Just drop the data if there's
+    // no chance anymore.
+    // When we first try to send a character and the buffer is not accessible yet,
+    // we wait until the time has been more than TX_FLUSH_TIMEOUT_US since we successfully
+    // sent the last byte. If it takes longer than TX_FLUSH_TIMEOUT_US, we drop every
+    // byte until the buffer can be accessible again.
+    do {
+        if (usb_serial_jtag_ll_txfifo_writable()) {
+            usb_serial_jtag_ll_write_txfifo(&cc, 1);
+            s_ctx.last_tx_ts = esp_timer_get_time();
+            break;
         }
-    }
+    } while ((esp_timer_get_time() - s_ctx.last_tx_ts) < TX_FLUSH_TIMEOUT_US);
+
 }
 
 static int usb_serial_jtag_rx_char(int fd)
@@ -364,25 +354,30 @@ void esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(esp_line_endings_t mode)
     s_ctx.rx_mode = mode;
 }
 
+static const esp_vfs_t vfs = {
+    .flags = ESP_VFS_FLAG_DEFAULT,
+    .write = &usb_serial_jtag_write,
+    .open = &usb_serial_jtag_open,
+    .fstat = &usb_serial_jtag_fstat,
+    .close = &usb_serial_jtag_close,
+    .read = &usb_serial_jtag_read,
+    .fcntl = &usb_serial_jtag_fcntl,
+    .fsync = &usb_serial_jtag_fsync,
+#ifdef CONFIG_VFS_SUPPORT_TERMIOS
+    .tcsetattr = &usb_serial_jtag_tcsetattr,
+    .tcgetattr = &usb_serial_jtag_tcgetattr,
+    .tcdrain = &usb_serial_jtag_tcdrain,
+    .tcflush = &usb_serial_jtag_tcflush,
+#endif // CONFIG_VFS_SUPPORT_TERMIOS
+};
+
+const esp_vfs_t* esp_vfs_usb_serial_jtag_get_vfs(void)
+{
+    return &vfs;
+}
 
 esp_err_t esp_vfs_dev_usb_serial_jtag_register(void)
 {
-    esp_vfs_t vfs = {
-        .flags = ESP_VFS_FLAG_DEFAULT,
-        .write = &usb_serial_jtag_write,
-        .open = &usb_serial_jtag_open,
-        .fstat = &usb_serial_jtag_fstat,
-        .close = &usb_serial_jtag_close,
-        .read = &usb_serial_jtag_read,
-        .fcntl = &usb_serial_jtag_fcntl,
-        .fsync = &usb_serial_jtag_fsync,
-#ifdef CONFIG_VFS_SUPPORT_TERMIOS
-        .tcsetattr = &usb_serial_jtag_tcsetattr,
-        .tcgetattr = &usb_serial_jtag_tcgetattr,
-        .tcdrain = &usb_serial_jtag_tcdrain,
-        .tcflush = &usb_serial_jtag_tcflush,
-#endif // CONFIG_VFS_SUPPORT_TERMIOS
-    };
     // "/dev/usb_serial_jtag" unfortunately is too long for vfs
     return esp_vfs_register("/dev/usbserjtag", &vfs, NULL);
 }

+ 0 - 6
tools/ci/check_copyright_ignore.txt

@@ -2552,12 +2552,9 @@ components/unity/unity_runner.c
 components/usb/test/common/test_usb_mock_classes.c
 components/usb/test/common/test_usb_mock_classes.h
 components/usb/test/hcd/test_hcd_ctrl.c
-components/vfs/include/esp_vfs_cdcacm.h
 components/vfs/include/esp_vfs_common.h
-components/vfs/include/esp_vfs_dev.h
 components/vfs/include/esp_vfs_eventfd.h
 components/vfs/include/esp_vfs_semihost.h
-components/vfs/include/esp_vfs_usb_serial_jtag.h
 components/vfs/test/test_vfs_access.c
 components/vfs/test/test_vfs_append.c
 components/vfs/test/test_vfs_eventfd.c
@@ -2566,11 +2563,8 @@ components/vfs/test/test_vfs_lwip.c
 components/vfs/test/test_vfs_paths.c
 components/vfs/test/test_vfs_select.c
 components/vfs/test/test_vfs_uart.c
-components/vfs/vfs_cdcacm.c
 components/vfs/vfs_eventfd.c
 components/vfs/vfs_semihost.c
-components/vfs/vfs_uart.c
-components/vfs/vfs_usb_serial_jtag.c
 components/wear_levelling/Partition.cpp
 components/wear_levelling/SPI_Flash.cpp
 components/wear_levelling/WL_Ext_Perf.cpp