627 lines
13 KiB
C
627 lines
13 KiB
C
#include "os/os.h"
|
|
#include "os/str.h"
|
|
#include "os/mem.h"
|
|
#include <common/bk_include.h>
|
|
|
|
#if CONFIG_LITTLEFS
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include "littlefs_adapter.h"
|
|
#include "bk_filesystem.h"
|
|
#include "bk_partition.h"
|
|
|
|
#include "lfs.h"
|
|
|
|
#define FS_LITTLEFS "littlefs"
|
|
|
|
#define USE_RAMBD 1
|
|
#define USE_FILEBD 2
|
|
#define USE_FLASHBD 3
|
|
|
|
#define USE_BD USE_FLASHBD
|
|
|
|
#if (USE_BD == USE_RAMBD)
|
|
|
|
#include "lfs_rambd.h"
|
|
|
|
static int setup_lfs_config(struct lfs_config *config, const struct bk_little_fs_partition *part) {
|
|
static const struct lfs_rambd_config defaults = {
|
|
.erase_value=-1,
|
|
.buffer = NULL,
|
|
};
|
|
int ret;
|
|
|
|
config->context = os_malloc(sizeof(lfs_rambd_t));
|
|
if (!config->context)
|
|
return -1;
|
|
|
|
config->read = lfs_rambd_read;
|
|
config->prog = lfs_rambd_prog;
|
|
config->erase = lfs_rambd_erase;
|
|
config->sync = lfs_rambd_sync;
|
|
|
|
config->read_size = 16;
|
|
config->prog_size = 16;
|
|
config->block_size = 4096;
|
|
config->block_count = 128;
|
|
config->cache_size = 16;
|
|
config->lookahead_size = 16;
|
|
config->block_cycles = 500;
|
|
|
|
ret = lfs_rambd_createcfg(config, &defaults);
|
|
if (ret) {
|
|
printf("create rambd failed : %d\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void teardown_lfs_config(struct lfs_config *config) {
|
|
lfs_rambd_destroy(config);
|
|
|
|
if (config->context) {
|
|
os_free(config->context);
|
|
config->context = NULL;
|
|
}
|
|
}
|
|
|
|
#elif (USE_BD == USE_FILEBD)
|
|
|
|
#include "lfs_filebd.h"
|
|
|
|
static int setup_lfs_config(struct lfs_config *config, const struct bk_little_fs_partition *part) {
|
|
static const struct lfs_filebd_config defaults = {
|
|
.erase_value=-1
|
|
};
|
|
int ret;
|
|
|
|
if (!part || !part->part_file.file_path) {
|
|
printf("no file_path\n");
|
|
return -1;
|
|
}
|
|
|
|
config->context = os_malloc(sizeof(lfs_filebd_t));
|
|
if (!config->context)
|
|
return -1;
|
|
|
|
config->read = lfs_filebd_read;
|
|
config->prog = lfs_filebd_prog;
|
|
config->erase = lfs_filebd_erase;
|
|
config->sync = lfs_filebd_sync;
|
|
|
|
config->read_size = 16;
|
|
config->prog_size = 16;
|
|
config->block_size = 4096;
|
|
config->block_count = 128;
|
|
config->cache_size = 16;
|
|
config->lookahead_size = 16;
|
|
config->block_cycles = 500;
|
|
|
|
ret = lfs_filebd_createcfg(config, part->part_file.file_path, &defaults);
|
|
if (ret) {
|
|
printf("create filebd failed : %d\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void teardown_lfs_config(struct lfs_config *config) {
|
|
lfs_filebd_destroy(config);
|
|
|
|
if (config->context) {
|
|
os_free(config->context);
|
|
config->context = NULL;
|
|
}
|
|
}
|
|
|
|
#elif (USE_BD == USE_FLASHBD)
|
|
|
|
#include "lfs_flashbd.h"
|
|
|
|
static int setup_lfs_config(struct lfs_config *config, const struct bk_little_fs_partition *part) {
|
|
static const struct lfs_flashbd_config defaults = {
|
|
.erase_value=-1
|
|
};
|
|
lfs_flashbd_t *bd;
|
|
int ret;
|
|
|
|
if (!part || !part->part_flash.start_addr || !part->part_flash.size) {
|
|
printf("no start_addr or size\n");
|
|
return -1;
|
|
}
|
|
|
|
config->context = os_malloc(sizeof(lfs_flashbd_t));
|
|
if (!config->context)
|
|
return -1;
|
|
|
|
bd = (lfs_flashbd_t *)config->context;
|
|
bd->start_addr = part->part_flash.start_addr;
|
|
bd->end_addr = part->part_flash.start_addr + part->part_flash.size;
|
|
|
|
if (part->part_type == LFS_FLASH) {
|
|
config->read = lfs_flashbd_read;
|
|
config->prog = lfs_flashbd_prog;
|
|
config->erase = lfs_flashbd_erase;
|
|
config->sync = lfs_flashbd_sync;
|
|
} else if (part->part_type == LFS_SPI_FLASH) {
|
|
ret = lfs_spi_flashbd_init();
|
|
if (ret) {
|
|
os_free(config->context);
|
|
return -1;
|
|
}
|
|
config->read = lfs_spi_flashbd_read;
|
|
config->prog = lfs_spi_flashbd_prog;
|
|
config->erase = lfs_spi_flashbd_erase;
|
|
config->sync = lfs_spi_flashbd_sync;
|
|
} else {
|
|
os_free(config->context);
|
|
return -1;
|
|
}
|
|
|
|
config->read_size = 16;
|
|
config->prog_size = 16;
|
|
config->block_size = 4096;
|
|
config->block_count = part->part_flash.size / config->block_size;
|
|
config->cache_size = 16;
|
|
config->lookahead_size = 16;
|
|
config->block_cycles = 500;
|
|
|
|
ret = lfs_flashbd_createcfg(config, &defaults);
|
|
if (ret) {
|
|
printf("create flashbd failed : %d\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void teardown_lfs_config(struct lfs_config *config) {
|
|
lfs_flashbd_destroy(config);
|
|
|
|
if (config->context) {
|
|
os_free(config->context);
|
|
config->context = NULL;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
static int _bk_lfs_mkfs(const char *partition_name, const void *data) {
|
|
const struct bk_little_fs_partition *part;
|
|
struct lfs_config config;
|
|
lfs_t lfs;
|
|
int ret;
|
|
|
|
part = (const struct bk_little_fs_partition *)data;
|
|
|
|
memset(&lfs, 0, sizeof(lfs_t));
|
|
memset(&config, 0, sizeof(struct lfs_config));
|
|
|
|
ret = setup_lfs_config(&config, part);
|
|
if (ret) {
|
|
return -1;
|
|
}
|
|
|
|
ret = lfs_format(&lfs, &config);
|
|
if (ret) {
|
|
teardown_lfs_config(&config);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _bk_lfs_mount(struct bk_filesystem *fs, unsigned long mount_flags, const void *data) {
|
|
const struct bk_little_fs_partition *part;
|
|
static struct lfs_config* config;
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
part = (const struct bk_little_fs_partition *)data;
|
|
lfs = (lfs_t *)os_malloc(sizeof(lfs_t) + 8 + sizeof(struct lfs_config));
|
|
if (!lfs)
|
|
return -1;
|
|
|
|
memset(lfs, 0, sizeof(lfs_t));
|
|
config = (struct lfs_config *)(lfs + 1);
|
|
memset(config, 0, sizeof(struct lfs_config));
|
|
|
|
ret = setup_lfs_config(config, part);
|
|
if (ret) {
|
|
os_free(lfs);
|
|
return -1;
|
|
}
|
|
|
|
ret = lfs_mount(lfs, config);
|
|
if (ret) {
|
|
teardown_lfs_config(config);
|
|
os_free(lfs);
|
|
return -1;
|
|
}
|
|
|
|
fs->fs_data = lfs;
|
|
return 0;
|
|
}
|
|
|
|
static int _bk_lfs_unmount(struct bk_filesystem *fs) {
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
ret = lfs_unmount(lfs);
|
|
|
|
if (lfs->cfg) {
|
|
teardown_lfs_config((struct lfs_config *)lfs->cfg);
|
|
}
|
|
|
|
os_free(lfs);
|
|
fs->fs_data = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_unmount2(struct bk_filesystem *fs, int flag) {
|
|
return _bk_lfs_unmount(fs);
|
|
}
|
|
|
|
static int _bk_lfs_statfs(struct bk_filesystem *fs, struct statfs *buf) {
|
|
lfs_t *lfs;
|
|
lfs_ssize_t in_use;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
in_use = lfs_fs_size(lfs);
|
|
if (in_use < 0)
|
|
return -1;
|
|
|
|
buf->f_bsize = lfs->cfg->block_size;
|
|
buf->f_blocks = lfs->cfg->block_count;
|
|
buf->f_bfree = lfs->cfg->block_count - in_use;
|
|
buf->f_bavail = lfs->cfg->block_count - in_use;
|
|
return 0;
|
|
}
|
|
|
|
static struct bk_filesystem_ops g_lfs_fs_ops = {
|
|
.mount = _bk_lfs_mount,
|
|
.unmount = _bk_lfs_unmount,
|
|
.unmount2 = _bk_lfs_unmount2,
|
|
.mkfs = _bk_lfs_mkfs,
|
|
.statfs = _bk_lfs_statfs,
|
|
};
|
|
|
|
static int file_flags_to_lfs(int oflags) {
|
|
int lfsOpenFlag = 0;
|
|
|
|
if (oflags & O_CREAT) {
|
|
lfsOpenFlag |= LFS_O_CREAT;
|
|
}
|
|
|
|
if (oflags & O_EXCL) {
|
|
lfsOpenFlag |= LFS_O_EXCL;
|
|
}
|
|
|
|
if (oflags & O_TRUNC) {
|
|
lfsOpenFlag |= LFS_O_TRUNC;
|
|
}
|
|
|
|
if (oflags & O_APPEND) {
|
|
lfsOpenFlag |= LFS_O_APPEND;
|
|
}
|
|
|
|
if (oflags & O_RDWR) {
|
|
lfsOpenFlag |= LFS_O_RDWR;
|
|
}
|
|
|
|
if (oflags & O_WRONLY) {
|
|
lfsOpenFlag |= LFS_O_WRONLY;
|
|
}
|
|
|
|
if (oflags == O_RDONLY) {
|
|
lfsOpenFlag |= LFS_O_RDONLY;
|
|
}
|
|
|
|
return lfsOpenFlag;
|
|
}
|
|
|
|
static int _bk_lfs_open(struct bk_file *file, const char *path, int oflag) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
|
|
lfs_file = (lfs_file_t *)os_malloc(sizeof(lfs_file_t));
|
|
if (!lfs_file)
|
|
return -1;
|
|
|
|
memset(lfs_file, 0, sizeof(lfs_file_t));
|
|
|
|
oflag = file_flags_to_lfs(oflag);
|
|
ret = lfs_file_open(lfs, lfs_file, file->path, oflag);
|
|
if (ret) {
|
|
os_free(lfs_file);
|
|
return -1;
|
|
}
|
|
|
|
file->f_data = lfs_file;
|
|
return 0;
|
|
}
|
|
|
|
static int _bk_lfs_close(struct bk_file *file) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
ret = lfs_file_close(lfs, lfs_file);
|
|
|
|
os_free(file->f_data);
|
|
file->f_data = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t _bk_lfs_read(struct bk_file *file, void *buf, size_t count) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
ret = lfs_file_read(lfs, lfs_file, buf, count);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t _bk_lfs_write(struct bk_file *file, const void *buf, size_t count) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
ret = lfs_file_write(lfs, lfs_file, buf, count);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static off_t _bk_lfs_lseek(struct bk_file *file, off_t offset, int whence) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
ret = lfs_file_seek(lfs, lfs_file, offset, whence);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if CONFIG_STARBURST_AIDIALOG_SDK
|
|
static off_t _bk_lfs_ftell(struct bk_file *file) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
return lfs_file_tell(lfs, lfs_file);
|
|
}
|
|
|
|
static int _bk_lfs_feof(struct bk_file *file) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
//bk_printf("[%s][%d]size:%d, pos:%d\r\n", __FILE__, __LINE__, lfs_file_size(lfs, lfs_file), lfs_file_tell(lfs, lfs_file));
|
|
return lfs_file_size(lfs, lfs_file)<=lfs_file_tell(lfs, lfs_file);
|
|
}
|
|
#endif
|
|
|
|
static int _bk_lfs_unlink(struct bk_filesystem *fs, const char *pathname) {
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
ret = lfs_remove(lfs, pathname);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_stat(struct bk_filesystem *fs, const char *pathname, struct stat *statbuf) {
|
|
struct lfs_info info;
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
ret = lfs_stat(lfs, pathname, &info);
|
|
if (ret == 0) {
|
|
statbuf->st_size = info.size;
|
|
if (info.type == LFS_TYPE_REG)
|
|
statbuf->st_mode = S_IFREG;
|
|
else
|
|
statbuf->st_mode = S_IFDIR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_rename(struct bk_filesystem *fs, const char *oldpath, const char *newpath) {
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
ret = lfs_rename(lfs, oldpath, newpath);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_fsync(struct bk_file *file) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
ret = lfs_file_sync(lfs, lfs_file);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_ftruncate(struct bk_file *file, off_t offset) {
|
|
lfs_t *lfs;
|
|
lfs_file_t *lfs_file;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)file->filesystem->fs_data;
|
|
lfs_file = (lfs_file_t *)file->f_data;
|
|
|
|
ret = lfs_file_truncate(lfs, lfs_file, offset);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_fcntl(struct bk_file *file, int cmd, void *args) {
|
|
return -1;
|
|
}
|
|
|
|
static int _bk_lfs_opendir(bk_dir *dir, const char *pathname) {
|
|
lfs_t *lfs;
|
|
lfs_dir_t *lfs_dir;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)dir->filesystem->fs_data;
|
|
|
|
lfs_dir = (lfs_dir_t *)os_malloc(sizeof(lfs_dir_t));
|
|
if (!lfs_dir)
|
|
return -1;
|
|
memset(lfs_dir, 0, sizeof(lfs_dir_t));
|
|
|
|
ret = lfs_dir_open(lfs, lfs_dir, pathname);
|
|
if (ret) {
|
|
os_free(lfs_dir);
|
|
return -1;
|
|
}
|
|
|
|
dir->dir_data = lfs_dir;
|
|
return 0;
|
|
}
|
|
|
|
static int _bk_lfs_readdir(bk_dir *dir, struct dirent *entry) {
|
|
lfs_t *lfs;
|
|
lfs_dir_t *lfs_dir;
|
|
struct lfs_info info;
|
|
int ret;
|
|
int len;
|
|
|
|
lfs = (lfs_t *)dir->filesystem->fs_data;
|
|
lfs_dir = (lfs_dir_t *)dir->dir_data;
|
|
|
|
ret = lfs_dir_read(lfs, lfs_dir, &info);
|
|
if (ret <= 0) //error or no more entry
|
|
return -1;
|
|
|
|
entry->d_ino = 0;
|
|
if (info.type == LFS_TYPE_REG)
|
|
entry->d_type = DT_REG;
|
|
else if (info.type == LFS_TYPE_DIR)
|
|
entry->d_type = DT_DIR;
|
|
else
|
|
entry->d_type = DT_UNKNOWN;
|
|
entry->d_reclen = sizeof(struct dirent);
|
|
|
|
if (sizeof(entry->d_name) - 1 < strlen(info.name))
|
|
len = sizeof(entry->d_name) - 1;
|
|
else
|
|
len = strlen(info.name);
|
|
strncpy(entry->d_name, info.name, len + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _bk_lfs_closedir(bk_dir *dir) {
|
|
lfs_t *lfs;
|
|
lfs_dir_t *lfs_dir;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)dir->filesystem->fs_data;
|
|
lfs_dir = (lfs_dir_t *)dir->dir_data;
|
|
|
|
ret = lfs_dir_close(lfs, lfs_dir);
|
|
|
|
os_free(lfs_dir);
|
|
dir->dir_data = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_mkdir(struct bk_filesystem *fs, const char *pathname) {
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
|
|
ret = lfs_mkdir(lfs, pathname);
|
|
return ret;
|
|
}
|
|
|
|
static int _bk_lfs_rmdir(struct bk_filesystem *fs, const char *pathname) {
|
|
lfs_t *lfs;
|
|
int ret;
|
|
|
|
lfs = (lfs_t *)fs->fs_data;
|
|
|
|
ret = lfs_remove(lfs, pathname);
|
|
return ret;
|
|
}
|
|
|
|
static struct bk_file_ops g_lfs_file_ops = {
|
|
.open = _bk_lfs_open,
|
|
.close = _bk_lfs_close,
|
|
.read = _bk_lfs_read,
|
|
.write = _bk_lfs_write,
|
|
.lseek = _bk_lfs_lseek,
|
|
.unlink = _bk_lfs_unlink,
|
|
.stat = _bk_lfs_stat,
|
|
.rename = _bk_lfs_rename,
|
|
.fsync = _bk_lfs_fsync,
|
|
.ftruncate = _bk_lfs_ftruncate,
|
|
.fcntl = _bk_lfs_fcntl,
|
|
|
|
.opendir = _bk_lfs_opendir,
|
|
.readdir = _bk_lfs_readdir,
|
|
.closedir = _bk_lfs_closedir,
|
|
.mkdir = _bk_lfs_mkdir,
|
|
.rmdir = _bk_lfs_rmdir,
|
|
#if CONFIG_STARBURST_AIDIALOG_SDK
|
|
.ftell = _bk_lfs_ftell,
|
|
.feof = _bk_lfs_feof,
|
|
#endif
|
|
};
|
|
|
|
int bk_lfs_init(void) {
|
|
return bk_register_filesystem(FS_LITTLEFS, &g_lfs_fs_ops, &g_lfs_file_ops);
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
int bk_lfs_init(void) {
|
|
return 0;
|
|
}
|
|
|
|
#endif
|