mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
vfs: introduce options to turn off some features
CONFIG_VFS_SUPPORT_IO: for basic I/O functions support CONFIG_VFS_SUPPORT_DIR: for file/directory functions support CONFIG_VFS_SUPPORT_SELECT: for select support
This commit is contained in:
parent
45e50f1f2a
commit
a3c0bcb0a0
@ -1,7 +1,56 @@
|
||||
menu "Virtual file system"
|
||||
|
||||
config VFS_SUPPORT_IO
|
||||
bool "Provide basic I/O functions"
|
||||
default y
|
||||
help
|
||||
If enabled, the following functions are provided by the VFS component.
|
||||
|
||||
open, close, read, write, pread, pwrite, lseek, fstat, fsync, ioctl, fcntl
|
||||
|
||||
Filesystem drivers can then be registered to handle these functions
|
||||
for specific paths.
|
||||
|
||||
Disabling this option can save memory when the support for these functions
|
||||
is not required.
|
||||
|
||||
config VFS_SUPPORT_DIR
|
||||
bool "Provide directory related functions"
|
||||
default y
|
||||
# If some filesystem is used, adding I/O support is probably needed and
|
||||
# is not a big overhead, compared to code size of the filesystem,
|
||||
# so make this depend on IO.
|
||||
depends on VFS_SUPPORT_IO
|
||||
help
|
||||
If enabled, the following functions are provided by the VFS component.
|
||||
|
||||
stat, link, unlink, rename, utime, access, truncate, rmdir, mkdir,
|
||||
opendir, closedir, readdir, readdir_r, seekdir, telldir, rewinddir
|
||||
|
||||
Filesystem drivers can then be registered to handle these functions
|
||||
for specific paths.
|
||||
|
||||
Disabling this option can save memory when the support for these functions
|
||||
is not required.
|
||||
|
||||
config VFS_SUPPORT_SELECT
|
||||
bool "Provide select function"
|
||||
default y
|
||||
# Dependency on !LWIP_USE_ONLY_LWIP_SELECT is for compatibility
|
||||
depends on VFS_SUPPORT_IO && !LWIP_USE_ONLY_LWIP_SELECT
|
||||
help
|
||||
If enabled, select function is provided by the VFS component, and can be used
|
||||
on peripheral file descriptors (such as UART) and sockets at the same time.
|
||||
|
||||
If disabled, the default select implementation will be provided by LWIP for
|
||||
sockets only.
|
||||
|
||||
Disabling this option can reduce code size if support for "select" on UART file
|
||||
descriptors is not required.
|
||||
|
||||
config VFS_SUPPRESS_SELECT_DEBUG_OUTPUT
|
||||
bool "Suppress select() related debug outputs"
|
||||
depends on VFS_SUPPORT_SELECT
|
||||
default y
|
||||
help
|
||||
Select() related functions might produce an unconveniently lot of
|
||||
@ -10,12 +59,16 @@ menu "Virtual file system"
|
||||
option.
|
||||
|
||||
config VFS_SUPPORT_TERMIOS
|
||||
bool "Add support for termios.h"
|
||||
bool "Provide termios.h functions"
|
||||
default y
|
||||
# Very likely, only makes sense for UART VFS driver, which itself depends on VFS_SUPPORT_IO
|
||||
depends on VFS_SUPPORT_IO
|
||||
help
|
||||
Disabling this option can save memory when the support for termios.h is not required.
|
||||
|
||||
menu "Host File System I/O (Semihosting)"
|
||||
depends on VFS_SUPPORT_IO
|
||||
|
||||
config SEMIHOSTFS_MAX_MOUNT_POINTS
|
||||
int "Maximum number of the host filesystem mount points"
|
||||
default 1
|
||||
|
@ -132,6 +132,7 @@ typedef struct
|
||||
int (*fstat_p)(void* ctx, int fd, struct stat * st); /*!< fstat with context pointer */
|
||||
int (*fstat)(int fd, struct stat * st); /*!< fstat without context pointer */
|
||||
};
|
||||
#ifdef CONFIG_VFS_SUPPORT_DIR
|
||||
union {
|
||||
int (*stat_p)(void* ctx, const char * path, struct stat * st); /*!< stat with context pointer */
|
||||
int (*stat)(const char * path, struct stat * st); /*!< stat without context pointer */
|
||||
@ -180,6 +181,7 @@ typedef struct
|
||||
int (*rmdir_p)(void* ctx, const char* name); /*!< rmdir with context pointer */
|
||||
int (*rmdir)(const char* name); /*!< rmdir without context pointer */
|
||||
};
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
union {
|
||||
int (*fcntl_p)(void* ctx, int fd, int cmd, int arg); /*!< fcntl with context pointer */
|
||||
int (*fcntl)(int fd, int cmd, int arg); /*!< fcntl without context pointer */
|
||||
@ -192,6 +194,7 @@ typedef struct
|
||||
int (*fsync_p)(void* ctx, int fd); /*!< fsync with context pointer */
|
||||
int (*fsync)(int fd); /*!< fsync without context pointer */
|
||||
};
|
||||
#ifdef CONFIG_VFS_SUPPORT_DIR
|
||||
union {
|
||||
int (*access_p)(void* ctx, const char *path, int amode); /*!< access with context pointer */
|
||||
int (*access)(const char *path, int amode); /*!< access without context pointer */
|
||||
@ -204,6 +207,7 @@ typedef struct
|
||||
int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times); /*!< utime with context pointer */
|
||||
int (*utime)(const char *path, const struct utimbuf *times); /*!< utime without context pointer */
|
||||
};
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
union {
|
||||
int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p); /*!< tcsetattr with context pointer */
|
||||
@ -234,7 +238,7 @@ typedef struct
|
||||
int (*tcsendbreak)(int fd, int duration); /*!< tcsendbreak without context pointer */
|
||||
};
|
||||
#endif // CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
/** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */
|
||||
esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args);
|
||||
/** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */
|
||||
@ -247,6 +251,7 @@ typedef struct
|
||||
void* (*get_socket_select_semaphore)(void);
|
||||
/** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */
|
||||
esp_err_t (*end_select)(void *end_select_args);
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
} esp_vfs_t;
|
||||
|
||||
|
||||
@ -406,23 +411,6 @@ void esp_vfs_select_triggered(esp_vfs_select_sem_t sem);
|
||||
*/
|
||||
void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken);
|
||||
|
||||
/**
|
||||
* @brief Implements the VFS layer for synchronous I/O multiplexing by poll()
|
||||
*
|
||||
* The implementation is based on esp_vfs_select. The parameters and return values are compatible with POSIX poll().
|
||||
*
|
||||
* @param fds Pointer to the array containing file descriptors and events poll() should consider.
|
||||
* @param nfds Number of items in the array fds.
|
||||
* @param timeout Poll() should wait at least timeout milliseconds. If the value is 0 then it should return
|
||||
* immediately. If the value is -1 then it should wait (block) until the event occurs.
|
||||
*
|
||||
* @return A positive return value indicates the number of file descriptors that have been selected. The 0
|
||||
* return value indicates a timed-out poll. -1 is return on failure and errno is set accordingly.
|
||||
*
|
||||
*/
|
||||
int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Implements the VFS layer of POSIX pread()
|
||||
|
@ -507,6 +507,52 @@ int esp_vfs_fstat(struct _reent *r, int fd, struct stat * st)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_vfs_fcntl_r(struct _reent *r, int fd, int cmd, int arg)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_vfs_ioctl(int fd, int cmd, ...)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, cmd);
|
||||
CHECK_AND_CALL(ret, r, vfs, ioctl, local_fd, cmd, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_vfs_fsync(int fd)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, fsync, local_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_DIR
|
||||
|
||||
int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_path(path);
|
||||
@ -520,6 +566,20 @@ int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_vfs_utime(const char *path, const struct utimbuf *times)
|
||||
{
|
||||
int ret;
|
||||
const vfs_entry_t* vfs = get_vfs_for_path(path);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL) {
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
const char* path_within_vfs = translate_path(vfs, path);
|
||||
CHECK_AND_CALL(ret, r, vfs, utime, path_within_vfs, times);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_vfs_link(struct _reent *r, const char* n1, const char* n2)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_path(n1);
|
||||
@ -712,50 +772,6 @@ int rmdir(const char* name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _fcntl_r(struct _reent *r, int fd, int cmd, int arg)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ioctl(int fd, int cmd, ...)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, cmd);
|
||||
CHECK_AND_CALL(ret, r, vfs, ioctl, local_fd, cmd, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fsync(int fd)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, fsync, local_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int access(const char *path, int amode)
|
||||
{
|
||||
int ret;
|
||||
@ -784,6 +800,10 @@ int truncate(const char *path, off_t length)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args)
|
||||
{
|
||||
for (int i = 0; i < end_index; ++i) {
|
||||
@ -1074,7 +1094,10 @@ void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken)
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
int tcgetattr(int fd, struct termios *p)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
@ -1174,95 +1197,10 @@ int tcsendbreak(int fd, int duration)
|
||||
}
|
||||
#endif // CONFIG_VFS_SUPPORT_TERMIOS
|
||||
|
||||
int esp_vfs_utime(const char *path, const struct utimbuf *times)
|
||||
{
|
||||
int ret;
|
||||
const vfs_entry_t* vfs = get_vfs_for_path(path);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL) {
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
const char* path_within_vfs = translate_path(vfs, path);
|
||||
CHECK_AND_CALL(ret, r, vfs, utime, path_within_vfs, times);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
struct timeval tv = {
|
||||
// timeout is in milliseconds
|
||||
.tv_sec = timeout / 1000,
|
||||
.tv_usec = (timeout % 1000) * 1000,
|
||||
};
|
||||
int max_fd = -1;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set errorfds;
|
||||
struct _reent* r = __getreent();
|
||||
int ret = 0;
|
||||
|
||||
if (fds == NULL) {
|
||||
__errno_r(r) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&errorfds);
|
||||
|
||||
for (int i = 0; i < nfds; ++i) {
|
||||
fds[i].revents = 0;
|
||||
|
||||
if (fds[i].fd < 0) {
|
||||
// revents should remain 0 and events ignored (according to the documentation of poll()).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[i].fd >= MAX_FDS) {
|
||||
fds[i].revents |= POLLNVAL;
|
||||
++ret;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
|
||||
FD_SET(fds[i].fd, &readfds);
|
||||
FD_SET(fds[i].fd, &errorfds);
|
||||
max_fd = MAX(max_fd, fds[i].fd);
|
||||
}
|
||||
|
||||
if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
|
||||
FD_SET(fds[i].fd, &writefds);
|
||||
FD_SET(fds[i].fd, &errorfds);
|
||||
max_fd = MAX(max_fd, fds[i].fd);
|
||||
}
|
||||
}
|
||||
|
||||
const int select_ret = esp_vfs_select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL: &tv);
|
||||
|
||||
if (select_ret > 0) {
|
||||
ret += select_ret;
|
||||
|
||||
for (int i = 0; i < nfds; ++i) {
|
||||
if (FD_ISSET(fds[i].fd, &readfds)) {
|
||||
fds[i].revents |= POLLIN;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fds[i].fd, &writefds)) {
|
||||
fds[i].revents |= POLLOUT;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fds[i].fd, &errorfds)) {
|
||||
fds[i].revents |= POLLERR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = select_ret;
|
||||
// keeping the errno from select()
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vfs_include_syscalls_impl(void)
|
||||
{
|
||||
|
@ -23,6 +23,14 @@
|
||||
#include "freertos/task.h"
|
||||
#include "esp_vfs.h"
|
||||
|
||||
#ifndef CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS
|
||||
#define CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS 1
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN
|
||||
#define CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN 128
|
||||
#endif
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_NONE
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "esp_semihost";
|
||||
|
@ -116,6 +116,8 @@ static vfs_uart_context_t* s_ctx[UART_NUM] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
typedef struct {
|
||||
esp_vfs_select_sem_t select_sem;
|
||||
fd_set *readfds;
|
||||
@ -132,6 +134,8 @@ static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static esp_err_t uart_end_select(void *end_select_args);
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static int uart_open(const char * path, int flags, int mode)
|
||||
{
|
||||
// this is fairly primitive, we should check if file is opened read only,
|
||||
@ -319,6 +323,8 @@ static int uart_fcntl(int fd, int cmd, int arg)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_DIR
|
||||
|
||||
static int uart_access(const char *path, int amode)
|
||||
{
|
||||
int ret = -1;
|
||||
@ -340,6 +346,8 @@ static int uart_access(const char *path, int amode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
|
||||
static int uart_fsync(int fd)
|
||||
{
|
||||
assert(fd >= 0 && fd < 3);
|
||||
@ -349,6 +357,8 @@ static int uart_fsync(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static esp_err_t register_select(uart_select_args_t *args)
|
||||
{
|
||||
esp_err_t ret = ESP_ERR_INVALID_ARG;
|
||||
@ -509,6 +519,8 @@ static esp_err_t uart_end_select(void *end_select_args)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p)
|
||||
{
|
||||
@ -972,9 +984,13 @@ void esp_vfs_dev_uart_register(void)
|
||||
.read = &uart_read,
|
||||
.fcntl = &uart_fcntl,
|
||||
.fsync = &uart_fsync,
|
||||
#ifdef CONFIG_VFS_SUPPORT_DIR
|
||||
.access = &uart_access,
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
#ifdef CONFIG_VFS_SUPPORT_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,
|
||||
|
Loading…
Reference in New Issue
Block a user