Storage: New Virtual Mount API for FATFS disk images

This commit is contained in:
Willy-JL
2024-02-20 03:17:54 +00:00
parent 49a9b1f2b2
commit fab29dbc6f
10 changed files with 321 additions and 2 deletions

View File

@@ -714,3 +714,181 @@ void storage_ext_init(StorageData* storage) {
// do not notify on first launch, notifications app is waiting for our thread to read settings
storage_ext_tick_internal(storage, false);
}
#include "fatfs/ff_gen_drv.h"
#define SCSI_BLOCK_SIZE (0x200UL)
static File* mnt_image = NULL;
static StorageData* mnt_image_storage = NULL;
bool mnt_mounted = false;
;
FS_Error storage_process_virtual_init(StorageData* image_storage, File* image) {
if(mnt_image) return FSE_ALREADY_OPEN;
mnt_image = image;
mnt_image_storage = image_storage;
return FSE_OK;
}
FS_Error storage_process_virtual_format(StorageData* storage) {
#ifdef FURI_RAM_EXEC
UNUSED(storage);
return FSE_NOT_READY;
#else
if(!mnt_image) return FSE_NOT_READY;
SDData* sd_data = storage->data;
uint8_t* work = malloc(_MAX_SS);
SDError error = f_mkfs(sd_data->path, FM_ANY, 0, work, _MAX_SS);
free(work);
if(error != FR_OK) return FSE_INTERNAL;
return FSE_OK;
#endif
}
FS_Error storage_process_virtual_mount(StorageData* storage) {
if(!mnt_image) return FSE_NOT_READY;
SDData* sd_data = storage->data;
SDError error = f_mount(sd_data->fs, sd_data->path, 1);
if(error == FR_NO_FILESYSTEM) return FSE_INVALID_PARAMETER;
if(error != FR_OK) return FSE_INTERNAL;
mnt_mounted = true;
return FSE_OK;
}
FS_Error storage_process_virtual_unmount(StorageData* storage) {
if(!mnt_image) return FSE_NOT_READY;
SDData* sd_data = storage->data;
SDError error = f_mount(0, sd_data->path, 0);
if(error != FR_OK) return FSE_INTERNAL;
mnt_mounted = false;
return FSE_OK;
}
FS_Error storage_process_virtual_quit(StorageData* storage) {
if(!mnt_image) return FSE_NOT_READY;
if(mnt_mounted) storage_process_virtual_unmount(storage);
mnt_image = NULL;
mnt_image_storage = NULL;
return FSE_OK;
}
/**
* @brief Initializes a Drive
* @param pdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
static DSTATUS mnt_driver_initialize(BYTE pdrv) {
UNUSED(pdrv);
return RES_OK;
}
/**
* @brief Gets Disk Status
* @param pdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
static DSTATUS mnt_driver_status(BYTE pdrv) {
UNUSED(pdrv);
if(!mnt_image) return STA_NOINIT;
return RES_OK;
}
/**
* @brief Reads Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data buffer to store read data
* @param sector: Sector address (LBA)
* @param count: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
static DRESULT mnt_driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
UNUSED(pdrv);
if(!storage_ext_file_seek(mnt_image_storage, mnt_image, sector * SCSI_BLOCK_SIZE, true)) {
return RES_ERROR;
}
size_t size = count * SCSI_BLOCK_SIZE;
size_t read = storage_ext_file_read(mnt_image_storage, mnt_image, buff, size);
return read == size ? RES_OK : RES_ERROR;
}
/**
* @brief Writes Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data to be written
* @param sector: Sector address (LBA)
* @param count: Number of sectors to write (1..128)
* @retval DRESULT: Operation result
*/
static DRESULT mnt_driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
UNUSED(pdrv);
if(!storage_ext_file_seek(mnt_image_storage, mnt_image, sector * SCSI_BLOCK_SIZE, true)) {
return RES_ERROR;
}
size_t size = count * SCSI_BLOCK_SIZE;
size_t wrote = storage_ext_file_write(mnt_image_storage, mnt_image, buff, size);
return wrote == size ? RES_OK : RES_ERROR;
}
/**
* @brief I/O control operation
* @param pdrv: Physical drive number (0..)
* @param cmd: Control code
* @param *buff: Buffer to send/receive control data
* @retval DRESULT: Operation result
*/
static DRESULT mnt_driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
DRESULT res = RES_ERROR;
DSTATUS status = mnt_driver_status(pdrv);
if(status & STA_NOINIT) return RES_NOTRDY;
switch(cmd) {
/* Make sure that no pending write process */
case CTRL_SYNC:
res = RES_OK;
break;
/* Get number of sectors on the disk (DWORD) */
case GET_SECTOR_COUNT:
*(DWORD*)buff = storage_ext_file_size(mnt_image_storage, mnt_image) / SCSI_BLOCK_SIZE;
res = RES_OK;
break;
/* Get R/W sector size (WORD) */
case GET_SECTOR_SIZE:
*(WORD*)buff = SCSI_BLOCK_SIZE;
res = RES_OK;
break;
/* Get erase block size in unit of sector (DWORD) */
case GET_BLOCK_SIZE:
*(DWORD*)buff = SCSI_BLOCK_SIZE;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
return res;
}
static Diskio_drvTypeDef mnt_driver = {
mnt_driver_initialize,
mnt_driver_status,
mnt_driver_read,
mnt_driver_write,
mnt_driver_ioctl,
};
void storage_mnt_init(StorageData* storage) {
char path[4] = {0};
FATFS_LinkDriver(&mnt_driver, path);
SDData* sd_data = malloc(sizeof(SDData));
sd_data->fs = malloc(sizeof(FATFS));
sd_data->path = strdup(path);
storage->data = sd_data;
storage->fs_api = &fs_api;
}

View File

@@ -12,6 +12,12 @@ FS_Error sd_mount_card(StorageData* storage, bool notify);
FS_Error sd_unmount_card(StorageData* storage);
FS_Error sd_format_card(StorageData* storage);
FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info);
void storage_mnt_init(StorageData* storage);
FS_Error storage_process_virtual_init(StorageData* image_storage, File* image);
FS_Error storage_process_virtual_format(StorageData* storage);
FS_Error storage_process_virtual_mount(StorageData* storage);
FS_Error storage_process_virtual_unmount(StorageData* storage);
FS_Error storage_process_virtual_quit(StorageData* storage);
#ifdef __cplusplus
}
#endif