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:
Ramakrishna Pallala 2018-05-04 19:17:58 +05:30 committed by Anas Nashif
commit 2b5b7da9f3
10 changed files with 358 additions and 41 deletions

View file

@ -147,11 +147,11 @@
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define _VOLUMES 1
#define _VOLUMES 8
/* Number of volumes (logical drives) to be used. */
#define _STR_VOLUME_ID 0
#define _STR_VOLUME_ID 1
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* _STR_VOLUME_ID switches string support of volume ID.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive

View file

@ -29,13 +29,17 @@
#include <ffconf.h>
#include <disk_access.h>
static const char* const pdrv_str[] = {_VOLUME_STRS};
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status(BYTE pdrv)
{
if (disk_access_status() != 0) {
__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
if (disk_access_status(pdrv_str[pdrv]) != 0) {
return STA_NOINIT;
} else {
return RES_OK;
@ -43,12 +47,14 @@ DSTATUS disk_status(BYTE pdrv)
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/* Initialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize(BYTE pdrv)
{
if (disk_access_init() != 0) {
__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
if (disk_access_init(pdrv_str[pdrv]) != 0) {
return STA_NOINIT;
} else {
return RES_OK;
@ -61,7 +67,9 @@ DSTATUS disk_initialize(BYTE pdrv)
DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
if (disk_access_read(buff, sector, count) != 0) {
__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
if (disk_access_read(pdrv_str[pdrv], buff, sector, count) != 0) {
return RES_ERROR;
} else {
return RES_OK;
@ -74,7 +82,9 @@ DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
/*-----------------------------------------------------------------------*/
DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
if(disk_access_write(buff, sector, count) != 0) {
__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
if(disk_access_write(pdrv_str[pdrv], buff, sector, count) != 0) {
return RES_ERROR;
} else {
return RES_OK;
@ -89,21 +99,26 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
{
int ret = RES_OK;
__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
switch (cmd) {
case CTRL_SYNC:
if(disk_access_ioctl(DISK_IOCTL_CTRL_SYNC, buff) != 0) {
if(disk_access_ioctl(pdrv_str[pdrv],
DISK_IOCTL_CTRL_SYNC, buff) != 0) {
ret = RES_ERROR;
}
break;
case GET_SECTOR_COUNT:
if (disk_access_ioctl(DISK_IOCTL_GET_SECTOR_COUNT, buff) != 0) {
if (disk_access_ioctl(pdrv_str[pdrv],
DISK_IOCTL_GET_SECTOR_COUNT, buff) != 0) {
ret = RES_ERROR;
}
break;
case GET_BLOCK_SIZE:
if (disk_access_ioctl(DISK_IOCTL_GET_ERASE_BLOCK_SZ, buff) != 0) {
if (disk_access_ioctl(pdrv_str[pdrv],
DISK_IOCTL_GET_ERASE_BLOCK_SZ, buff) != 0) {
ret = RES_ERROR;
}
break;

View file

@ -17,7 +17,9 @@
#ifndef _DISK_ACCESS_H_
#define _DISK_ACCESS_H_
#include <kernel.h>
#include <zephyr/types.h>
#include <misc/dlist.h>
#ifdef __cplusplus
extern "C" {
@ -42,6 +44,24 @@ extern "C" {
#define DISK_STATUS_NOMEDIA 0x02
#define DISK_STATUS_WR_PROTECT 0x04
struct disk_operations;
struct disk_info {
sys_dnode_t node;
char *name;
const struct disk_operations *ops;
};
struct disk_operations {
int (*init)(struct disk_info *disk);
int (*status)(struct disk_info *disk);
int (*read)(struct disk_info *disk, u8_t *data_buf,
u32_t start_sector, u32_t num_sector);
int (*write)(struct disk_info *disk, const u8_t *data_buf,
u32_t start_sector, u32_t num_sector);
int (*ioctl)(struct disk_info *disk, u8_t cmd, void *buff);
};
/*
* @brief perform any initialization
*
@ -50,7 +70,7 @@ extern "C" {
*
* @return 0 on success, negative errno code on fail
*/
int disk_access_init(void);
int disk_access_init(const char *pdrv);
/*
* @brief Get the status of disk
@ -59,7 +79,7 @@ int disk_access_init(void);
*
* @return DISK_STATUS_OK or other DISK_STATUS_*s
*/
int disk_access_status(void);
int disk_access_status(const char *pdrv);
/*
* @brief read data from disk
@ -72,8 +92,8 @@ int disk_access_status(void);
*
* @return 0 on success, negative errno code on fail
*/
int disk_access_read(u8_t *data_buf, u32_t start_sector,
u32_t num_sector);
int disk_access_read(const char *pdrv, u8_t *data_buf,
u32_t start_sector, u32_t num_sector);
/*
* @brief write data to disk
@ -86,8 +106,8 @@ int disk_access_read(u8_t *data_buf, u32_t start_sector,
*
* @return 0 on success, negative errno code on fail
*/
int disk_access_write(const u8_t *data_buf, u32_t start_sector,
u32_t num_sector);
int disk_access_write(const char *pdrv, const u8_t *data_buf,
u32_t start_sector, u32_t num_sector);
/*
* @brief Get/Configure disk parameters
@ -98,8 +118,11 @@ int disk_access_write(const u8_t *data_buf, u32_t start_sector,
*
* @return 0 on success, negative errno code on fail
*/
int disk_access_ioctl(u8_t cmd, void *buff);
int disk_access_ioctl(const char *pdrv, u8_t cmd, void *buff);
int disk_access_register(struct disk_info *disk);
int disk_access_unregister(struct disk_info *disk);
#ifdef __cplusplus
}

View file

@ -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)

View file

@ -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
View 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);

View file

@ -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);

View file

@ -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);

View file

@ -88,6 +88,13 @@ config USB_MASS_STORAGE
help
USB Mass Storage device class driver
config MASS_STORAGE_DISK_NAME
string "Mass storage disk or drive name"
depends on USB_MASS_STORAGE
default "RAM"
help
Mass storage device disk or drive name
config MASS_STORAGE_IN_EP_ADDR
hex
depends on USB_MASS_STORAGE

View file

@ -70,6 +70,7 @@ static u8_t page[BLOCK_SIZE];
/* Initialized during mass_storage_init() */
static u32_t memory_size;
static u32_t block_count;
static const char *disk_pdrv = CONFIG_MASS_STORAGE_DISK_NAME;
/* CSW Status */
enum Status {
@ -523,7 +524,7 @@ static void memoryVerify(u8_t *buf, u16_t size)
/* beginning of a new block -> load a whole block in RAM */
if (!(addr % BLOCK_SIZE)) {
SYS_LOG_DBG("Disk READ sector %d", addr/BLOCK_SIZE);
if (disk_access_read(page, addr/BLOCK_SIZE, 1)) {
if (disk_access_read(disk_pdrv, page, addr/BLOCK_SIZE, 1)) {
SYS_LOG_ERR("---- Disk Read Error %d", addr/BLOCK_SIZE);
}
}
@ -565,7 +566,8 @@ static void memoryWrite(u8_t *buf, u16_t size)
/* if the array is filled, write it in memory */
if (!((addr + size) % BLOCK_SIZE)) {
if (!(disk_access_status() & DISK_STATUS_WR_PROTECT)) {
if (!(disk_access_status(disk_pdrv) &
DISK_STATUS_WR_PROTECT)) {
SYS_LOG_DBG("Disk WRITE Qd %d", (addr/BLOCK_SIZE));
thread_op = THREAD_OP_WRITE_QUEUED; /* write_queued */
defered_wr_sz = size;
@ -789,7 +791,8 @@ static void mass_thread_main(int arg1, int unused)
switch (thread_op) {
case THREAD_OP_READ_QUEUED:
if (disk_access_read(page, (addr/BLOCK_SIZE), 1)) {
if (disk_access_read(disk_pdrv,
page, (addr/BLOCK_SIZE), 1)) {
SYS_LOG_ERR("!! Disk Read Error %d !",
addr/BLOCK_SIZE);
}
@ -797,7 +800,8 @@ static void mass_thread_main(int arg1, int unused)
thread_memory_read_done();
break;
case THREAD_OP_WRITE_QUEUED:
if (disk_access_write(page, (addr/BLOCK_SIZE), 1)) {
if (disk_access_write(disk_pdrv,
page, (addr/BLOCK_SIZE), 1)) {
SYS_LOG_ERR("!!!!! Disk Write Error %d !!!!!",
addr/BLOCK_SIZE);
}
@ -831,17 +835,19 @@ static int mass_storage_init(struct device *dev)
ARG_UNUSED(dev);
if (disk_access_init() != 0) {
if (disk_access_init(disk_pdrv) != 0) {
SYS_LOG_ERR("Storage init ERROR !!!! - Aborting USB init");
return 0;
}
if (disk_access_ioctl(DISK_IOCTL_GET_SECTOR_COUNT, &block_count)) {
if (disk_access_ioctl(disk_pdrv,
DISK_IOCTL_GET_SECTOR_COUNT, &block_count)) {
SYS_LOG_ERR("Unable to get sector count - Aborting USB init");
return 0;
}
if (disk_access_ioctl(DISK_IOCTL_GET_SECTOR_SIZE, &block_size)) {
if (disk_access_ioctl(disk_pdrv,
DISK_IOCTL_GET_SECTOR_SIZE, &block_size)) {
SYS_LOG_ERR("Unable to get sector size - Aborting USB init");
return 0;
}