556 lines
17 KiB
C
556 lines
17 KiB
C
#include <FreeRTOS.h>
|
|
#include <armv7-r/atomic.h>
|
|
#include <debug.h>
|
|
#include <disk.h>
|
|
#include <lib/list.h>
|
|
#include <param.h>
|
|
#include <semphr.h>
|
|
|
|
struct list_node g_disk_list;
|
|
QueueHandle_t g_disk_mutex;
|
|
|
|
static struct disk_info *disk_get_info(const char *disk_name)
|
|
{
|
|
struct disk_info *info;
|
|
|
|
xSemaphoreTake(g_disk_mutex, portMAX_DELAY);
|
|
/* matches nodes based on name */
|
|
list_for_every_entry (&g_disk_list, info, struct disk_info, node) {
|
|
if (!strcmp(disk_name, info->disk_name)) {
|
|
xSemaphoreGive(g_disk_mutex);
|
|
return info;
|
|
}
|
|
}
|
|
xSemaphoreGive(g_disk_mutex);
|
|
return NULL;
|
|
}
|
|
|
|
int disk_open(const char *disk_name, struct disk_dev *dev)
|
|
{
|
|
struct disk_info *info;
|
|
info = disk_get_info(disk_name);
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk devicve node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
if (NULL != dev->info) {
|
|
ssdk_printf(SSDK_ERR, "disk device is open.\n");
|
|
return -DISK_ERROR_BUSY;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk open:%s\n", info->disk_name);
|
|
dev->info = info;
|
|
dev->block_size = info->block_align_size;
|
|
dev->flags = DISK_FLAGS_REWR;
|
|
arch_atomic_add(&info->use_count, 1);
|
|
return 0;
|
|
}
|
|
|
|
int disk_close(struct disk_dev *dev)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk close:%s\n", info->disk_name);
|
|
dev->info = NULL;
|
|
arch_atomic_add(&info->use_count, -1);
|
|
return 0;
|
|
}
|
|
|
|
int disk_read(struct disk_dev *dev, disk_addr_t addr, uint8_t *dst,
|
|
disk_size_t size)
|
|
{
|
|
if (!(dev->flags & DISK_FLAGS_READ)) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"disk device does not support read operations \n");
|
|
return -DISK_ERROR_NO_PERMISSION;
|
|
}
|
|
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (addr + size > info->disk_size) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, addr:%lld size:%lld disk_size:%lld\n",
|
|
addr, size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk read:%s addr:%lld size:%lld\n",
|
|
info->disk_name, addr, size);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if ((info->cache) && !(dev->flags & DISK_FLAGS_DIRECT_IO)) {
|
|
return disk_cache_read(info->cache, dst, addr, size);
|
|
} else
|
|
#endif
|
|
if (info->disk_ops->disk_read)
|
|
return info->disk_ops->disk_read(info, dst, addr, size);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_write(struct disk_dev *dev, disk_addr_t addr, const uint8_t *src,
|
|
disk_size_t size)
|
|
{
|
|
if (!(dev->flags & DISK_FLAGS_WRITE)) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"disk device does not support write operations \n");
|
|
return -DISK_ERROR_NO_PERMISSION;
|
|
}
|
|
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (addr + size > info->disk_size) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, addr:%lld size:%lld disk_size:%lld\n",
|
|
addr, size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk write:%s addr:%lld size:%lld\n",
|
|
info->disk_name, addr, size);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if (info->cache) {
|
|
int ret = 0;
|
|
ret |= disk_cache_write(info->cache, src, addr, size);
|
|
|
|
/* DIRECT_IO situation,TODO */
|
|
if (dev->flags & DISK_FLAGS_DIRECT_IO)
|
|
ret |= disk_cache_sync_addr(info->cache, addr, size);
|
|
|
|
return ret;
|
|
} else
|
|
#endif
|
|
if (info->disk_ops->disk_write)
|
|
return info->disk_ops->disk_write(info, src, addr, size);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_read_block(struct disk_dev *dev, block_t block, uint8_t *dst,
|
|
block_count_t count)
|
|
{
|
|
if (!(dev->flags & DISK_FLAGS_READ)) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"disk device does not support read operations \n");
|
|
return -DISK_ERROR_NO_PERMISSION;
|
|
}
|
|
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (block + count > info->disk_size / dev->block_size) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, block:%lld count:%d block_size:0x%x "
|
|
"addr:%lld size:%lld disk_size:%lld\n",
|
|
block, count, dev->block_size,
|
|
(disk_addr_t)block * dev->block_size,
|
|
(disk_addr_t)count * dev->block_size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
/* mem alignment judgment */
|
|
if (!IS_ALIGNED(dst, info->mem_align_size)) {
|
|
ssdk_printf(SSDK_ERR, "mem addresses 0x%p not aligned to 0x%x\n", dst,
|
|
info->mem_align_size);
|
|
return -DISK_ERROR_NO_ALIGNED;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG,
|
|
"disk read block:%s block:%lld count:%d block_size:0x%x "
|
|
"addr:%lld size:%lld\n",
|
|
info->disk_name, block, count, dev->block_size,
|
|
(disk_addr_t)block * dev->block_size,
|
|
(disk_addr_t)count * dev->block_size);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if ((info->cache) && !(dev->flags & DISK_FLAGS_DIRECT_IO)) {
|
|
return disk_cache_read(info->cache, dst, block * dev->block_size,
|
|
count * dev->block_size);
|
|
} else
|
|
#endif
|
|
if (info->disk_ops->disk_read_block)
|
|
return info->disk_ops->disk_read_block(info, dst, block, count,
|
|
dev->block_size);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_write_block(struct disk_dev *dev, block_t block, const uint8_t *src,
|
|
block_count_t count)
|
|
{
|
|
if (!(dev->flags & DISK_FLAGS_WRITE)) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"disk device does not support write operations \n");
|
|
return -DISK_ERROR_NO_PERMISSION;
|
|
}
|
|
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (block + count > info->disk_size / dev->block_size) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, block:%lld count:%d block_size:0x%x "
|
|
"addr:%lld size:%lld disk_size:%lld\n",
|
|
block, count, dev->block_size,
|
|
(disk_addr_t)block * dev->block_size,
|
|
(disk_addr_t)count * dev->block_size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
/* mem alignment judgment */
|
|
if (!IS_ALIGNED(src, info->mem_align_size)) {
|
|
ssdk_printf(SSDK_ERR, "mem addresses %p not aligned to %d\n", src,
|
|
info->mem_align_size);
|
|
return -DISK_ERROR_NO_ALIGNED;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG,
|
|
"disk write block:%s block:%lld count:%d block_size:0x%x "
|
|
"addr:%lld size:%lld\n",
|
|
info->disk_name, block, count, dev->block_size,
|
|
(disk_addr_t)block * dev->block_size,
|
|
(disk_addr_t)count * dev->block_size);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if (info->cache) {
|
|
int ret = 0;
|
|
ret |= disk_cache_write(info->cache, src, block * dev->block_size,
|
|
count * dev->block_size);
|
|
|
|
/* DIRECT_IO situation,TODO */
|
|
if (dev->flags & DISK_FLAGS_DIRECT_IO)
|
|
ret |= disk_cache_sync_addr(info->cache, block * dev->block_size,
|
|
count * dev->block_size);
|
|
|
|
return ret;
|
|
} else
|
|
#endif
|
|
if (info->disk_ops->disk_write_block)
|
|
return info->disk_ops->disk_write_block(info, src, block, count,
|
|
dev->block_size);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_erase(struct disk_dev *dev, disk_addr_t addr, disk_size_t size,
|
|
disk_erase_flags flag)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (addr + size > info->disk_size) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, addr:%lld size:%lld disk_size:%lld\n",
|
|
addr, size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk erase:%s addr:%lld size:%lld flag:%d\n",
|
|
info->disk_name, addr, size, flag);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if (info->cache) {
|
|
int ret = 0;
|
|
ret |= disk_cache_erase(info->cache, addr, size, flag);
|
|
|
|
/* DIRECT_IO situation,TODO */
|
|
if (dev->flags & DISK_FLAGS_DIRECT_IO)
|
|
ret |= disk_cache_sync_addr(info->cache, addr, size);
|
|
|
|
return ret;
|
|
} else
|
|
#endif
|
|
if (info->disk_ops->disk_erase)
|
|
return info->disk_ops->disk_erase(info, addr, size, flag);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_erase_group(struct disk_dev *dev, uint32_t erase_block, uint32_t count,
|
|
disk_erase_flags flag)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (erase_block + count > info->disk_size / info->erase_size) {
|
|
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, erase_block:%d count:%d "
|
|
"erase_size:0x%x addr:%lld size:%lld disk_size:%lld\n",
|
|
erase_block, count, info->erase_size,
|
|
(disk_addr_t)erase_block * info->erase_size,
|
|
(disk_addr_t)count * info->erase_size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG,
|
|
"disk erase group:%s erase_block:%d count:%d erase_size:0x%x "
|
|
"addr:%lld size:%lld flag:%d\n",
|
|
info->disk_name, erase_block, count, info->erase_size,
|
|
(disk_addr_t)erase_block * info->erase_size,
|
|
(disk_addr_t)count * info->erase_size, flag);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if (info->cache) {
|
|
int ret = 0;
|
|
ret |= disk_cache_erase(info->cache, erase_block * info->erase_size,
|
|
count * info->erase_size, flag);
|
|
|
|
/* DIRECT_IO situation,TODO */
|
|
if (dev->flags & DISK_FLAGS_DIRECT_IO)
|
|
ret |= disk_cache_sync_addr(info->cache,
|
|
erase_block * info->erase_size,
|
|
count * info->erase_size);
|
|
|
|
return ret;
|
|
} else
|
|
#endif
|
|
if (info->disk_ops->disk_erase_group)
|
|
return info->disk_ops->disk_erase_group(info, erase_block, count,
|
|
info->erase_size, flag);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_sync(struct disk_dev *dev)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk sync:%s\n", info->disk_name);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if (info->cache)
|
|
return disk_cache_sync(info->cache);
|
|
else
|
|
#endif
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_sync_addr(struct disk_dev *dev, disk_addr_t addr, disk_size_t size)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
/* size range judgment */
|
|
if (addr + size > info->disk_size) {
|
|
ssdk_printf(SSDK_ERR,
|
|
"out of disk range, addr:%lld size:%lld disk_size:%lld\n",
|
|
addr, size, info->disk_size);
|
|
return -DISK_ERROR_OUT_RANGE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk sync addr:%s addr:%lld size:%lld\n",
|
|
info->disk_name, addr, size);
|
|
#ifdef CONFIG_DISK_CACHE
|
|
|
|
if (info->cache)
|
|
return disk_cache_sync_addr(info->cache, addr, size);
|
|
else
|
|
#endif
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
disk_addr_t disk_size(struct disk_dev *dev)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk size:%s size:%lld\n", info->disk_name,
|
|
info->disk_size);
|
|
return info->disk_size;
|
|
}
|
|
|
|
uint32_t disk_erase_size(struct disk_dev *dev)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk erase size:%s erase_size:0x%x\n",
|
|
info->disk_name, info->erase_size);
|
|
return info->erase_size;
|
|
}
|
|
|
|
uint32_t disk_get_block_size(struct disk_dev *dev)
|
|
{
|
|
ssdk_printf(SSDK_DEBUG, "disk get block size:%s block_size:0x%x\n",
|
|
dev->info->disk_name, dev->block_size);
|
|
return dev->block_size;
|
|
}
|
|
|
|
int disk_set_block_size(struct disk_dev *dev, uint32_t blk_sz)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
ssdk_printf(SSDK_DEBUG, "disk set block size:%s block_size:0x%x\n",
|
|
dev->info->disk_name, blk_sz);
|
|
|
|
/* blk_sz alignment judgment */
|
|
if (!IS_ALIGNED(blk_sz, info->block_align_size)) {
|
|
ssdk_printf(SSDK_ERR, "blk_sz %d not aligned to 0x%x\n", blk_sz,
|
|
info->block_align_size);
|
|
return -DISK_ERROR_NO_ALIGNED;
|
|
}
|
|
|
|
dev->block_size = blk_sz;
|
|
return 0;
|
|
}
|
|
|
|
int disk_set_flags(struct disk_dev *dev, bool mode, uint32_t flags)
|
|
{
|
|
if (mode)
|
|
dev->flags &= flags;
|
|
else
|
|
dev->flags |= ~flags;
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk set flags:%s flags:0x%x\n",
|
|
dev->info->disk_name, dev->flags);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t disk_get_flags(struct disk_dev *dev)
|
|
{
|
|
ssdk_printf(SSDK_DEBUG, "disk get flags:%s flags:0x%x\n",
|
|
dev->info->disk_name, dev->flags);
|
|
return dev->flags;
|
|
}
|
|
|
|
int disk_status(struct disk_dev *dev)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk status:%s\n", info->disk_name);
|
|
|
|
if (info->disk_ops->disk_status)
|
|
return info->disk_ops->disk_status(info);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int disk_ioctl(struct disk_dev *dev, uint32_t cmd, void *buff)
|
|
{
|
|
struct disk_info *info = dev->info;
|
|
|
|
if (NULL == info) {
|
|
ssdk_printf(SSDK_ERR, "no disk device node\n");
|
|
return -DISK_ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "disk ioctl:%s\n", info->disk_name);
|
|
|
|
if (info->disk_ops->disk_ioctl)
|
|
return info->disk_ops->disk_ioctl(info, cmd, buff);
|
|
else
|
|
return -DISK_ERROR_NO_FUN;
|
|
}
|
|
|
|
int register_disk(struct disk_info *disk)
|
|
{
|
|
int ret = 0;
|
|
ssdk_printf(SSDK_DEBUG,
|
|
"register disk :%s disk_size:%lld erase_size:0x%x\n",
|
|
disk->disk_name, disk->disk_size, disk->erase_size);
|
|
xSemaphoreTake(g_disk_mutex, portMAX_DELAY);
|
|
/* insert node */
|
|
list_add_tail(&g_disk_list, &disk->node);
|
|
disk->use_count = 0;
|
|
xSemaphoreGive(g_disk_mutex);
|
|
return ret;
|
|
}
|
|
|
|
int unregister_disk(struct disk_info *disk)
|
|
{
|
|
int ret = 0;
|
|
ssdk_printf(SSDK_DEBUG, "unregiste disk :%s\n", disk->disk_name);
|
|
xSemaphoreTake(g_disk_mutex, portMAX_DELAY);
|
|
|
|
if (disk->use_count) {
|
|
xSemaphoreGive(g_disk_mutex);
|
|
return -DISK_ERROR_BUSY;
|
|
}
|
|
|
|
/* remove nodes */
|
|
if (list_in_list(&disk->node))
|
|
list_delete(&disk->node);
|
|
|
|
xSemaphoreGive(g_disk_mutex);
|
|
return ret;
|
|
}
|
|
|
|
int disk_init(void)
|
|
{
|
|
ssdk_printf(SSDK_DEBUG, "disk init\n");
|
|
/* disk list node init */
|
|
list_initialize(&g_disk_list);
|
|
g_disk_mutex = xSemaphoreCreateMutex();
|
|
return 0;
|
|
}
|
|
|
|
int disk_exit(void)
|
|
{
|
|
ssdk_printf(SSDK_DEBUG, "disk exit\n");
|
|
/* disk list node init */
|
|
xSemaphoreGive(g_disk_mutex);
|
|
return 0;
|
|
}
|