Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

305 lines
5.8 KiB

/*
* Copyright (c) 2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/fs/fs.h>
#include <nsi_errno.h>
#include "cmdline.h"
#include "soc.h"
#include "fuse_fs_access_bottom.h"
#define NUMBER_OF_OPEN_FILES 128
static struct fs_file_t files[NUMBER_OF_OPEN_FILES];
static uint8_t file_handles[NUMBER_OF_OPEN_FILES];
static const char default_fuse_mountpoint[] = "flash";
static const char *fuse_mountpoint;
static ssize_t get_new_file_handle(void)
{
size_t idx;
for (idx = 0; idx < ARRAY_SIZE(file_handles); ++idx) {
if (file_handles[idx] == 0) {
++file_handles[idx];
return idx;
}
}
return -ENOMEM;
}
static void release_file_handle(size_t handle)
{
if (handle < ARRAY_SIZE(file_handles)) {
--file_handles[handle];
}
}
static int ffa_stat_top(const char *path, struct ffa_dirent *entry_bottom)
{
struct fs_dirent entry;
int err;
err = fs_stat(path, &entry);
if (err != 0) {
return nsi_errno_to_mid(-err);
}
entry_bottom->size = entry.size;
if (entry.type == FS_DIR_ENTRY_DIR) {
entry_bottom->is_directory = true;
} else {
entry_bottom->is_directory = false;
}
return 0;
}
static int ffa_readmount_top(int *mnt_nbr, const char **mnt_name)
{
int err = fs_readmount(mnt_nbr, mnt_name);
return nsi_errno_to_mid(-err);
}
/* Status shared between readdir_* calls */
static struct {
struct fs_dir_t dir;
struct fs_dirent entry;
} readdir_status;
static int ffa_readdir_start(const char *path)
{
int err;
fs_dir_t_init(&readdir_status.dir);
err = fs_opendir(&readdir_status.dir, path);
return nsi_errno_to_mid(-err);
}
static int ffa_readdir_read_next(struct ffa_dirent *entry_bottom)
{
int err;
err = fs_readdir(&readdir_status.dir, &readdir_status.entry);
if (err) {
return nsi_errno_to_mid(-err);
}
entry_bottom->name = readdir_status.entry.name;
entry_bottom->size = readdir_status.entry.size;
if (readdir_status.entry.type == FS_DIR_ENTRY_DIR) {
entry_bottom->is_directory = true;
} else {
entry_bottom->is_directory = false;
}
return 0;
}
static void ffa_readdir_end(void)
{
(void)fs_closedir(&readdir_status.dir);
}
static int ffa_create_top(const char *path, uint64_t *fh)
{
int err;
ssize_t handle;
handle = get_new_file_handle();
if (handle < 0) {
return nsi_errno_to_mid(-handle);
}
*fh = handle;
err = fs_open(&files[handle], path, FS_O_CREATE | FS_O_WRITE);
if (err != 0) {
release_file_handle(handle);
*fh = INVALID_FILE_HANDLE;
return nsi_errno_to_mid(-err);
}
return 0;
}
static int ffa_release_top(uint64_t fh)
{
fs_close(&files[fh]);
release_file_handle(fh);
return 0;
}
static int ffa_read_top(uint64_t fh, char *buf, size_t size, off_t off)
{
int err;
err = fs_seek(&files[fh], off, FS_SEEK_SET);
if (err == 0) {
err = fs_read(&files[fh], buf, size);
}
return nsi_errno_to_mid(-err);
}
static int ffa_write_top(uint64_t fh, const char *buf, size_t size, off_t off)
{
int err;
err = fs_seek(&files[fh], off, FS_SEEK_SET);
if (err == 0) {
err = fs_write(&files[fh], buf, size);
}
return nsi_errno_to_mid(-err);
}
static int ffa_ftruncate_top(uint64_t fh, off_t size)
{
int err = fs_truncate(&files[fh], size);
return nsi_errno_to_mid(-err);
}
static int ffa_truncate_top(const char *path, off_t size)
{
int err;
static struct fs_file_t file;
err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
if (err != 0) {
return nsi_errno_to_mid(-err);
}
err = fs_truncate(&file, size);
if (err != 0) {
fs_close(&file);
} else {
err = fs_close(&file);
}
return nsi_errno_to_mid(-err);
}
static int ffa_mkdir_top(const char *path)
{
int err = fs_mkdir(path);
return nsi_errno_to_mid(-err);
}
static int ffa_unlink_top(const char *path)
{
int err = fs_unlink(path);
return nsi_errno_to_mid(-err);
}
struct ffa_op_callbacks op_callbacks = {
.readdir_start = ffa_readdir_start,
.readdir_read_next = ffa_readdir_read_next,
.readdir_end = ffa_readdir_end,
.stat = ffa_stat_top,
.readmount = ffa_readmount_top,
.mkdir = ffa_mkdir_top,
.create = ffa_create_top,
.release = ffa_release_top,
.read = ffa_read_top,
.write = ffa_write_top,
.ftruncate = ffa_ftruncate_top,
.truncate = ffa_truncate_top,
.unlink = ffa_unlink_top,
.rmdir = ffa_unlink_top,
};
static void fuse_top_dispath_thread(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
ARG_UNUSED(arg3);
#define COOLDOWN_TIME 10
int cooldown_count = 0;
while (true) {
if (ffa_is_op_pended()) {
ffa_run_pending_op();
cooldown_count = COOLDOWN_TIME;
} else {
if (cooldown_count > 0) {
k_sleep(K_MSEC(1));
cooldown_count--;
} else {
k_sleep(K_MSEC(20));
}
}
}
}
K_THREAD_DEFINE(fuse_op_handler, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE,
fuse_top_dispath_thread, NULL, NULL, NULL, 100, 0, 0);
static void fuse_fs_access_init(void)
{
size_t i = 0;
while (i < ARRAY_SIZE(files)) {
fs_file_t_init(&files[i]);
++i;
}
if (fuse_mountpoint == NULL) {
fuse_mountpoint = default_fuse_mountpoint;
}
ffsa_init_bottom(fuse_mountpoint, &op_callbacks);
}
static void fuse_fs_access_cleanup(void)
{
if (fuse_mountpoint == NULL) {
return;
}
ffsa_cleanup_bottom(fuse_mountpoint);
}
static void fuse_fs_access_options(void)
{
static struct args_struct_t fuse_fs_access_options[] = {
{ .manual = false,
.is_mandatory = false,
.is_switch = false,
.option = "flash-mount",
.name = "path",
.type = 's',
.dest = (void *)&fuse_mountpoint,
.call_when_found = NULL,
.descript = "Path to the directory where to mount flash" },
ARG_TABLE_ENDMARKER
};
native_add_command_line_opts(fuse_fs_access_options);
}
NATIVE_TASK(fuse_fs_access_options, PRE_BOOT_1, 1);
NATIVE_TASK(fuse_fs_access_init, PRE_BOOT_2, 1);
NATIVE_TASK(fuse_fs_access_cleanup, ON_EXIT, 1);