subsys: disk: Add support for multiple disk interfaces
Add support for enabling multiple disk interfaces (Flash, RAM) simultaneously in Zephyr by introducing a simple disk interface framework where we can register multiple disks which would interface with different storage devices. This would enable us to have multiple instances of FATFS in Zephyr. Add support for mass storage drive disk name which will be used as an argument when calling the disk interface API's. Enable multiple volumes support configuration in ELM FAT library. Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
This commit is contained in:
parent
b99ff6f9e1
commit
2b5b7da9f3
10 changed files with 358 additions and 41 deletions
|
@ -1,2 +1,3 @@
|
|||
zephyr_sources_ifdef(CONFIG_DISK_ACCESS_RAM disk_access_ram.c)
|
||||
zephyr_sources_ifdef(CONFIG_DISK_ACCESS disk_access.c)
|
||||
zephyr_sources_ifdef(CONFIG_DISK_ACCESS_FLASH disk_access_flash.c)
|
||||
zephyr_sources_ifdef(CONFIG_DISK_ACCESS_RAM disk_access_ram.c)
|
||||
|
|
|
@ -13,9 +13,28 @@ config DISK_ACCESS
|
|||
help
|
||||
Enable disk access over a supported media backend like FLASH or RAM
|
||||
|
||||
config DISK_ACCESS_MAX_VOLUMES
|
||||
int
|
||||
default 8
|
||||
prompt "Maximum Disk Interfaces"
|
||||
help
|
||||
Maximum number of disk access interfaces supported
|
||||
|
||||
config SYS_LOG_DISK_LEVEL
|
||||
int
|
||||
prompt "File System log level"
|
||||
depends on SYS_LOG
|
||||
default 0
|
||||
help
|
||||
Sets log level for Disk drivers.
|
||||
Levels are:
|
||||
- 0 OFF, do not write
|
||||
- 1 ERROR, only write SYS_LOG_ERR
|
||||
- 2 WARNING, write SYS_LOG_WRN in addition to previous level
|
||||
- 3 INFO, write SYS_LOG_INF in addition to previous levels
|
||||
- 4 DEBUG, write SYS_LOG_DBG in addition to previous levels
|
||||
|
||||
if DISK_ACCESS
|
||||
choice
|
||||
prompt "Storage backend selection"
|
||||
|
||||
config DISK_ACCESS_RAM
|
||||
bool "RAM Disk"
|
||||
|
@ -30,10 +49,28 @@ config DISK_ACCESS_FLASH
|
|||
help
|
||||
Flash device is used for the file system.
|
||||
|
||||
endchoice
|
||||
endif # DISK_ACCESS
|
||||
|
||||
if DISK_ACCESS_RAM
|
||||
|
||||
config DISK_RAM_VOLUME_NAME
|
||||
string
|
||||
prompt "RAM Disk mount point or drive name"
|
||||
default "RAM"
|
||||
help
|
||||
Disk name as per file system naming guidelines.
|
||||
|
||||
endif # DISK_ACCESS_RAM
|
||||
|
||||
if DISK_ACCESS_FLASH
|
||||
|
||||
config DISK_FLASH_VOLUME_NAME
|
||||
string
|
||||
prompt "Flash mount point or drive name"
|
||||
default "NAND"
|
||||
help
|
||||
Disk name as per file system naming guidelines.
|
||||
|
||||
config DISK_FLASH_DEV_NAME
|
||||
string
|
||||
prompt "Flash device name to be used as storage backend"
|
||||
|
@ -73,5 +110,4 @@ config DISK_VOLUME_SIZE
|
|||
This is the file system volume size in bytes.
|
||||
|
||||
endif # DISK_ACCESS_FLASH
|
||||
endif # DISK_ACCESS
|
||||
endmenu
|
||||
|
|
180
subsys/disk/disk_access.c
Normal file
180
subsys/disk/disk_access.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <misc/util.h>
|
||||
#include <init.h>
|
||||
#include <disk_access.h>
|
||||
#include <errno.h>
|
||||
#include <device.h>
|
||||
|
||||
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_DISK_LEVEL
|
||||
#include <logging/sys_log.h>
|
||||
|
||||
/* list of mounted file systems */
|
||||
static sys_dlist_t disk_access_list;
|
||||
|
||||
/* lock to protect storage layer registration */
|
||||
static struct k_mutex mutex;
|
||||
|
||||
struct disk_info *disk_access_get_di(const char *name)
|
||||
{
|
||||
struct disk_info *disk = NULL, *itr;
|
||||
size_t name_len = strlen(name);
|
||||
sys_dnode_t *node;
|
||||
|
||||
k_mutex_lock(&mutex, K_FOREVER);
|
||||
SYS_DLIST_FOR_EACH_NODE(&disk_access_list, node) {
|
||||
itr = CONTAINER_OF(node, struct disk_info, node);
|
||||
|
||||
/*
|
||||
* Move to next node if mount point length is
|
||||
* shorter than longest_match match or if path
|
||||
* name is shorter than the mount point name.
|
||||
*/
|
||||
if (strlen(itr->name) != name_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for disk name match */
|
||||
if (strncmp(name, itr->name, name_len) == 0) {
|
||||
disk = itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
k_mutex_unlock(&mutex);
|
||||
|
||||
return disk;
|
||||
}
|
||||
|
||||
int disk_access_init(const char *pdrv)
|
||||
{
|
||||
struct disk_info *disk = disk_access_get_di(pdrv);
|
||||
int rc = -EINVAL;
|
||||
|
||||
if ((disk != NULL) || (disk->ops != NULL) ||
|
||||
(disk->ops->init != NULL)) {
|
||||
rc = disk->ops->init(disk);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disk_access_status(const char *pdrv)
|
||||
{
|
||||
struct disk_info *disk = disk_access_get_di(pdrv);
|
||||
int rc = -EINVAL;
|
||||
|
||||
if ((disk != NULL) || (disk->ops != NULL) ||
|
||||
(disk->ops->status != NULL)) {
|
||||
rc = disk->ops->status(disk);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disk_access_read(const char *pdrv, u8_t *data_buf,
|
||||
u32_t start_sector, u32_t num_sector)
|
||||
{
|
||||
struct disk_info *disk = disk_access_get_di(pdrv);
|
||||
int rc = -EINVAL;
|
||||
|
||||
if ((disk != NULL) || (disk->ops != NULL) ||
|
||||
(disk->ops->read != NULL)) {
|
||||
rc = disk->ops->read(disk, data_buf, start_sector, num_sector);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disk_access_write(const char *pdrv, const u8_t *data_buf,
|
||||
u32_t start_sector, u32_t num_sector)
|
||||
{
|
||||
struct disk_info *disk = disk_access_get_di(pdrv);
|
||||
int rc = -EINVAL;
|
||||
|
||||
if ((disk != NULL) || (disk->ops != NULL) ||
|
||||
(disk->ops->write != NULL)) {
|
||||
rc = disk->ops->write(disk, data_buf, start_sector, num_sector);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disk_access_ioctl(const char *pdrv, u8_t cmd, void *buf)
|
||||
{
|
||||
struct disk_info *disk = disk_access_get_di(pdrv);
|
||||
int rc = -EINVAL;
|
||||
|
||||
if ((disk != NULL) || (disk->ops != NULL) ||
|
||||
(disk->ops->ioctl != NULL)) {
|
||||
rc = disk->ops->ioctl(disk, cmd, buf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disk_access_register(struct disk_info *disk)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
k_mutex_lock(&mutex, K_FOREVER);
|
||||
if ((disk == NULL) || (disk->name == NULL)) {
|
||||
SYS_LOG_ERR("invalid disk interface!!");
|
||||
rc = -EINVAL;
|
||||
goto reg_err;
|
||||
}
|
||||
|
||||
if (disk_access_get_di(disk->name) != NULL) {
|
||||
SYS_LOG_ERR("disk interface already registered!!");
|
||||
rc = -EINVAL;
|
||||
goto reg_err;
|
||||
}
|
||||
|
||||
/* append to the disk list */
|
||||
sys_dlist_append(&disk_access_list, &disk->node);
|
||||
SYS_LOG_DBG("disk interface(%s) registred", name);
|
||||
reg_err:
|
||||
k_mutex_unlock(&mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int disk_access_unregister(struct disk_info *disk)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
k_mutex_lock(&mutex, K_FOREVER);
|
||||
if ((disk == NULL) || (disk->name == NULL)) {
|
||||
SYS_LOG_ERR("invalid disk interface!!");
|
||||
rc = -EINVAL;
|
||||
goto unreg_err;
|
||||
}
|
||||
|
||||
if (disk_access_get_di(disk->name) == NULL) {
|
||||
SYS_LOG_ERR("disk interface not registered!!");
|
||||
rc = -EINVAL;
|
||||
goto unreg_err;
|
||||
}
|
||||
/* remove disk node from the list */
|
||||
sys_dlist_remove(&disk->node);
|
||||
SYS_LOG_DBG("disk interface(%s) unregistred", name);
|
||||
unreg_err:
|
||||
k_mutex_unlock(&mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int disk_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
k_mutex_init(&mutex);
|
||||
sys_dlist_init(&disk_access_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(disk_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
|
@ -10,6 +10,7 @@
|
|||
#include <misc/util.h>
|
||||
#include <disk_access.h>
|
||||
#include <errno.h>
|
||||
#include <init.h>
|
||||
#include <device.h>
|
||||
#include <flash.h>
|
||||
|
||||
|
@ -40,7 +41,7 @@ static off_t lba_to_address(u32_t sector_num)
|
|||
return flash_addr;
|
||||
}
|
||||
|
||||
int disk_access_status(void)
|
||||
static int disk_flash_access_status(struct disk_info *disk)
|
||||
{
|
||||
if (!flash_dev) {
|
||||
return DISK_STATUS_NOMEDIA;
|
||||
|
@ -49,7 +50,7 @@ int disk_access_status(void)
|
|||
return DISK_STATUS_OK;
|
||||
}
|
||||
|
||||
int disk_access_init(void)
|
||||
static int disk_flash_access_init(struct disk_info *disk)
|
||||
{
|
||||
if (flash_dev) {
|
||||
return 0;
|
||||
|
@ -63,8 +64,8 @@ int disk_access_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int disk_access_read(u8_t *buff, u32_t start_sector,
|
||||
u32_t sector_count)
|
||||
static int disk_flash_access_read(struct disk_info *disk, u8_t *buff,
|
||||
u32_t start_sector, u32_t sector_count)
|
||||
{
|
||||
off_t fl_addr;
|
||||
u32_t remaining;
|
||||
|
@ -185,8 +186,8 @@ static int update_flash_block(off_t start_addr, u32_t size, const void *buff)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int disk_access_write(const u8_t *buff, u32_t start_sector,
|
||||
u32_t sector_count)
|
||||
static int disk_flash_access_write(struct disk_info *disk, const u8_t *buff,
|
||||
u32_t start_sector, u32_t sector_count)
|
||||
{
|
||||
off_t fl_addr;
|
||||
u32_t remaining;
|
||||
|
@ -254,7 +255,7 @@ int disk_access_write(const u8_t *buff, u32_t start_sector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int disk_access_ioctl(u8_t cmd, void *buff)
|
||||
static int disk_flash_access_ioctl(struct disk_info *disk, u8_t cmd, void *buff)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DISK_IOCTL_CTRL_SYNC:
|
||||
|
@ -274,3 +275,25 @@ int disk_access_ioctl(u8_t cmd, void *buff)
|
|||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct disk_operations flash_disk_ops = {
|
||||
.init = disk_flash_access_init,
|
||||
.status = disk_flash_access_status,
|
||||
.read = disk_flash_access_read,
|
||||
.write = disk_flash_access_write,
|
||||
.ioctl = disk_flash_access_ioctl,
|
||||
};
|
||||
|
||||
static struct disk_info flash_disk = {
|
||||
.name = CONFIG_DISK_FLASH_VOLUME_NAME,
|
||||
.ops = &flash_disk_ops,
|
||||
};
|
||||
|
||||
static int disk_flash_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return disk_access_register(&flash_disk);
|
||||
}
|
||||
|
||||
SYS_INIT(disk_flash_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <misc/__assert.h>
|
||||
#include <disk_access.h>
|
||||
#include <errno.h>
|
||||
#include <init.h>
|
||||
#include <device.h>
|
||||
|
||||
#define RAMDISK_SECTOR_SIZE 512
|
||||
|
||||
|
@ -33,31 +35,33 @@ static void *lba_to_address(u32_t lba)
|
|||
return &ramdisk_buf[(lba * RAMDISK_SECTOR_SIZE)];
|
||||
}
|
||||
|
||||
int disk_access_status(void)
|
||||
static int disk_ram_access_status(struct disk_info *disk)
|
||||
{
|
||||
return DISK_STATUS_OK;
|
||||
}
|
||||
|
||||
int disk_access_init(void)
|
||||
static int disk_ram_access_init(struct disk_info *disk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_access_read(u8_t *buff, u32_t sector, u32_t count)
|
||||
static int disk_ram_access_read(struct disk_info *disk, u8_t *buff,
|
||||
u32_t sector, u32_t count)
|
||||
{
|
||||
memcpy(buff, lba_to_address(sector), count * RAMDISK_SECTOR_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_access_write(const u8_t *buff, u32_t sector, u32_t count)
|
||||
static int disk_ram_access_write(struct disk_info *disk, const u8_t *buff,
|
||||
u32_t sector, u32_t count)
|
||||
{
|
||||
memcpy(lba_to_address(sector), buff, count * RAMDISK_SECTOR_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_access_ioctl(u8_t cmd, void *buff)
|
||||
static int disk_ram_access_ioctl(struct disk_info *disk, u8_t cmd, void *buff)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DISK_IOCTL_CTRL_SYNC:
|
||||
|
@ -77,3 +81,25 @@ int disk_access_ioctl(u8_t cmd, void *buff)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct disk_operations ram_disk_ops = {
|
||||
.init = disk_ram_access_init,
|
||||
.status = disk_ram_access_status,
|
||||
.read = disk_ram_access_read,
|
||||
.write = disk_ram_access_write,
|
||||
.ioctl = disk_ram_access_ioctl,
|
||||
};
|
||||
|
||||
static struct disk_info ram_disk = {
|
||||
.name = CONFIG_DISK_RAM_VOLUME_NAME,
|
||||
.ops = &ram_disk_ops,
|
||||
};
|
||||
|
||||
static int disk_ram_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return disk_access_register(&ram_disk);
|
||||
}
|
||||
|
||||
SYS_INIT(disk_ram_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue