vfs: implement fcntl via VFS interface

This commit is contained in:
Ivan Grokhotkov 2017-08-16 14:58:06 +08:00
parent 141b1174c6
commit 1e4587a09f
3 changed files with 55 additions and 9 deletions

View file

@ -17,6 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h>
#include "esp_err.h" #include "esp_err.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/reent.h> #include <sys/reent.h>
@ -140,6 +141,10 @@ typedef struct
int (*rmdir_p)(void* ctx, const char* name); int (*rmdir_p)(void* ctx, const char* name);
int (*rmdir)(const char* name); int (*rmdir)(const char* name);
}; };
union {
int (*fcntl_p)(void* ctx, int fd, int cmd, va_list args);
int (*fcntl)(int fd, int cmd, va_list args);
};
} esp_vfs_t; } esp_vfs_t;

View file

@ -472,3 +472,20 @@ int rmdir(const char* name)
CHECK_AND_CALL(ret, r, vfs, rmdir, path_within_vfs); CHECK_AND_CALL(ret, r, vfs, rmdir, path_within_vfs);
return ret; return ret;
} }
int fcntl(int fd, int cmd, ...)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
struct _reent* r = __getreent();
if (vfs == NULL) {
__errno_r(r) = EBADF;
return -1;
}
int local_fd = translate_fd(vfs, fd);
int ret;
va_list args;
va_start(args, cmd);
CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, args);
va_end(args);
return ret;
}

View file

@ -14,11 +14,13 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdarg.h>
#include <sys/errno.h>
#include <sys/lock.h>
#include <sys/fcntl.h>
#include "esp_vfs.h" #include "esp_vfs.h"
#include "esp_vfs_dev.h" #include "esp_vfs_dev.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "sys/errno.h"
#include "sys/lock.h"
#include "soc/uart_struct.h" #include "soc/uart_struct.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@ -48,6 +50,10 @@ static uart_dev_t* s_uarts[UART_NUM] = {&UART0, &UART1, &UART2};
static _lock_t s_uart_locks[UART_NUM]; static _lock_t s_uart_locks[UART_NUM];
// One-character buffer used for newline conversion code, per UART // One-character buffer used for newline conversion code, per UART
static int s_peek_char[UART_NUM] = { NONE, NONE, NONE }; static int s_peek_char[UART_NUM] = { NONE, NONE, NONE };
// Per-UART non-blocking flag. Note: default implementation does not honor this
// flag, all reads are non-blocking. This option becomes effective if UART
// driver is used.
static bool s_non_blocking[UART_NUM];
// Newline conversion mode when transmitting // Newline conversion mode when transmitting
static esp_line_endings_t s_tx_mode = static esp_line_endings_t s_tx_mode =
@ -122,8 +128,9 @@ static int uart_rx_char(int fd)
static int uart_rx_char_via_driver(int fd) static int uart_rx_char_via_driver(int fd)
{ {
uint8_t c; uint8_t c;
int n = uart_read_bytes(fd, &c, 1, portMAX_DELAY); int timeout = s_non_blocking[fd] ? 0 : portMAX_DELAY;
if (n == 0) { int n = uart_read_bytes(fd, &c, 1, timeout);
if (n <= 0) {
return NONE; return NONE;
} }
return c; return c;
@ -203,6 +210,8 @@ static ssize_t uart_read(int fd, void* data, size_t size)
uart_return_char(fd, c2); uart_return_char(fd, c2);
} }
} }
} else if (c == NONE) {
break;
} }
data_c[received] = (char) c; data_c[received] = (char) c;
++received; ++received;
@ -231,6 +240,25 @@ static int uart_close(int fd)
return 0; return 0;
} }
static int uart_fcntl(int fd, int cmd, va_list args)
{
assert(fd >=0 && fd < 3);
int result = 0;
if (cmd == F_GETFL) {
if (s_non_blocking[fd]) {
result |= O_NONBLOCK;
}
} else if (cmd == F_SETFL) {
int arg = va_arg(args, int);
s_non_blocking[fd] = (arg & O_NONBLOCK) != 0;
} else {
// unsupported operation
result = -1;
errno = ENOSYS;
}
return result;
}
void esp_vfs_dev_uart_register() void esp_vfs_dev_uart_register()
{ {
esp_vfs_t vfs = { esp_vfs_t vfs = {
@ -241,11 +269,7 @@ void esp_vfs_dev_uart_register()
.fstat = &uart_fstat, .fstat = &uart_fstat,
.close = &uart_close, .close = &uart_close,
.read = &uart_read, .read = &uart_read,
.lseek = NULL, .fcntl = &uart_fcntl
.stat = NULL,
.link = NULL,
.unlink = NULL,
.rename = NULL
}; };
ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL));
} }