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>
181 lines
3.8 KiB
C
181 lines
3.8 KiB
C
/*
|
|
* 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);
|