29#include "module_debug.h"
33#define FATFS_FS_DRIVER_MOUNT_INFO_MAX ((int)(sizeof(fs_driver_mount_info) / sizeof(fs_driver_mount_info[0])))
36#define FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(varname) \
37 const char *modified_##varname;
39#define FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(varname, fd) \
41 if ((fd)->unit != 0) \
43 int strlen_##varname; \
44 char *modified_scope_##varname; \
46 strlen_##varname = strlen(varname); \
47 modified_scope_##varname = __builtin_alloca(3 + strlen_##varname + 1); \
48 modified_scope_##varname[0] = '0' + (fd)->unit; \
49 modified_scope_##varname[1] = ':'; \
50 modified_scope_##varname[2] = '/'; \
51 memcpy((modified_scope_##varname) + 3, varname, strlen_##varname); \
52 modified_scope_##varname[3 + strlen_##varname] = '\x00'; \
53 modified_##varname = modified_scope_##varname; \
57 modified_##varname = varname; \
64static int _fs_lock_sema_id = -1;
67static int _fs_init_lock(
void)
71 M_DEBUG(
"%s\n", __func__);
77 if ((_fs_lock_sema_id = CreateSema(&sp)) < 0) {
85static void _fs_lock(
void)
89 WaitSema(_fs_lock_sema_id);
93static void _fs_unlock(
void)
97 SignalSema(_fs_lock_sema_id);
101static void fs_reset(
void)
103 M_DEBUG(
"%s\n", __func__);
105 if (_fs_lock_sema_id >= 0)
106 DeleteSema(_fs_lock_sema_id);
111static void fatfs_fs_driver_initialize_all_mount_info(
void)
114 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i += 1) {
115 memset(&(fs_driver_mount_info[i].fatfs), 0,
sizeof(fs_driver_mount_info[i].fatfs));
116 fs_driver_mount_info[i].mounted_bd = NULL;
120static int fatfs_fs_driver_find_mount_info_index_from_block_device(
const struct block_device *bd)
123 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i += 1) {
124 if (fs_driver_mount_info[i].mounted_bd == bd) {
131static int fatfs_fs_driver_find_mount_info_index_free(
void)
133 return fatfs_fs_driver_find_mount_info_index_from_block_device(NULL);
136struct block_device *fatfs_fs_driver_get_mounted_bd_from_index(
int mount_info_index)
139 if (mount_info_index > FATFS_FS_DRIVER_MOUNT_INFO_MAX) {
142 mounted_bd = fs_driver_mount_info[mount_info_index].mounted_bd;
146static FRESULT fatfs_fs_driver_mount_bd(
int mount_info_index,
struct block_device *bd)
151 M_DEBUG(
"%s\n", __func__);
153 mount_point[0] =
'0' + mount_info_index;
154 mount_point[1] =
':';
155 mount_point[2] =
'\x00';
157 fs_driver_mount_info[mount_info_index].mounted_bd = bd;
158 ret = f_mount(&(fs_driver_mount_info[mount_info_index].fatfs), mount_point, 1);
160 fs_driver_mount_info[mount_info_index].mounted_bd = NULL;
165static void fatfs_fs_driver_unmount_bd(
int mount_info_index)
168 mount_point[0] =
'0' + mount_info_index;
169 mount_point[1] =
':';
170 mount_point[2] =
'\x00';
172 f_unmount(mount_point);
173 fs_driver_mount_info[mount_info_index].mounted_bd = NULL;
176static void fatfs_fs_driver_stop_single_bd(
int mount_info_index)
180 mounted_bd = fatfs_fs_driver_get_mounted_bd_from_index(mount_info_index);
181 if (mounted_bd != NULL) {
182 fatfs_fs_driver_unmount_bd(mount_info_index);
183 mounted_bd->stop(mounted_bd);
187static void fatfs_fs_driver_stop_all_bd(
void)
190 for (i = 0; i < FATFS_FS_DRIVER_MOUNT_INFO_MAX; i += 1) {
191 fatfs_fs_driver_stop_single_bd(i);
197 int mount_info_index;
199 M_DEBUG(
"%s\n", __func__);
202 mount_info_index = fatfs_fs_driver_find_mount_info_index_free();
203 if (mount_info_index != -1) {
204 M_DEBUG(
"connect_bd: trying to mount to index %d\n", mount_info_index);
205 if (fatfs_fs_driver_mount_bd(mount_info_index, bd) == FR_OK) {
211 M_DEBUG(
"connect_bd: failed to mount device\n");
217 int mount_info_index;
220 mount_info_index = fatfs_fs_driver_find_mount_info_index_from_block_device(bd);
221 if (mount_info_index != -1) {
222 fatfs_fs_driver_unmount_bd(mount_info_index);
230static FIL fil_structures[MAX_FILES];
233static DIR dir_structures[MAX_DIRS];
235static FIL *fs_find_free_fil_structure(
void)
239 M_DEBUG(
"%s\n", __func__);
241 for (i = 0; i < MAX_FILES; i++) {
242 if (fil_structures[i].obj.fs == NULL) {
243 return &fil_structures[i];
249static DIR *fs_find_free_dir_structure(
void)
253 M_DEBUG(
"%s\n", __func__);
255 for (i = 0; i < MAX_DIRS; i++) {
256 if (dir_structures[i].obj.fs == NULL) {
257 return &dir_structures[i];
264static int fs_open(
iop_file_t *fd,
const char *name,
int flags,
int mode)
266 M_DEBUG(
"%s: %s flags=%X mode=%X\n", __func__, name, flags, mode);
269 BYTE f_mode = FA_OPEN_EXISTING;
270 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
274 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, fd);
279 fd->privdata = fs_find_free_fil_structure();
280 if (fd->privdata == NULL) {
286 if (flags & O_RDONLY)
288 if (flags & O_WRONLY)
291 f_mode |= FA_OPEN_ALWAYS;
293 f_mode |= FA_CREATE_ALWAYS;
294 if (flags & O_APPEND)
295 f_mode |= FA_OPEN_APPEND;
297 ret = f_open(fd->privdata, modified_name, f_mode);
313 M_DEBUG(
"%s\n", __func__);
320 ret = f_close(fd->privdata);
330s64 fs_lseek64(
iop_file_t *fd, s64 offset,
int whence)
332 M_DEBUG(
"%s\n", __func__);
336 if (fd->privdata == NULL)
341 FIL *file = (FIL *)(fd->privdata);
343 FSIZE_t off = offset;
350 off = file->obj.objsize + offset;
354 res = f_lseek(file, off);
357 return (res == FR_OK) ? (s64)(file->fptr) : -res;
360static int fs_lseek(
iop_file_t *fd,
int offset,
int whence)
362 return fs_lseek64(fd, (s64)offset, whence);
366static int fs_write(
iop_file_t *fd,
void *buffer,
int size)
368 M_DEBUG(
"%s\n", __func__);
373 if (fd->privdata == NULL)
378 ret = f_write(fd->privdata, buffer, size, &bw);
381 return (ret == FR_OK) ? bw : 0;
385static int fs_read(
iop_file_t *fd,
void *buffer,
int size)
387 M_DEBUG(
"%s\n", __func__);
392 if (fd->privdata == NULL)
397 ret = f_read(fd->privdata, buffer, size, &br);
400 return (ret == FR_OK) ? br : 0;
404static int fs_remove(
iop_file_t *fd,
const char *name)
406 M_DEBUG(
"%s\n", __func__);
409 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
411 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, fd);
415 ret = f_unlink(modified_name);
422static int fs_mkdir(
iop_file_t *fd,
const char *name,
int mode)
424 M_DEBUG(
"%s\n", __func__);
427 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
431 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, fd);
435 ret = f_mkdir(modified_name);
442static int fs_dopen(
iop_file_t *fd,
const char *name)
444 M_DEBUG(
"%s: unit %d name %s\n", __func__, fd->unit, name);
447 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
449 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, fd);
454 fd->privdata = fs_find_free_dir_structure();
455 if (fd->privdata == NULL) {
460 ret = f_opendir(fd->privdata, modified_name);
474 M_DEBUG(
"%s\n", __func__);
481 ret = f_closedir(fd->privdata);
491static void fileInfoToStat(FILINFO *fno,
iox_stat_t *stat)
493 WORD fdate = fno->fdate;
494 WORD ftime = fno->ftime;
495 unsigned char stime[8];
499 stat->size = (
unsigned int)(fno->fsize);
500 stat->hisize = (
unsigned int)(fno->fsize>>32);
503 if (fno->fattrib & AM_DIR) {
508 if (!(fno->fattrib & AM_RDO)) {
519 stime[4] = (fdate & 31);
520 stime[5] = (fdate >> 5) & 15;
522 year = (fdate >> 9) + 1980;
523 stime[6] = year & 0xff;
524 stime[7] = (year >> 8) & 0xff;
526 stime[3] = (ftime >> 11);
527 stime[2] = (ftime >> 5) & 63;
528 stime[1] = (ftime << 1) & 31;
530 memcpy(stat->ctime, stime,
sizeof(stime));
531 memcpy(stat->atime, stime,
sizeof(stime));
532 memcpy(stat->mtime, stime,
sizeof(stime));
538 M_DEBUG(
"%s\n", __func__);
543 if (fd->privdata == NULL)
548 ret = f_readdir(fd->privdata, &fno);
550 if (ret == FR_OK && fno.fname[0]) {
551 strncpy(buffer->name, fno.fname, 255);
552 fileInfoToStat(&fno, &(buffer->stat));
565 M_DEBUG(
"%s: unit %d name %s\n", __func__, fd->unit, name);
569 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(name);
573 const char *name_no_leading_slash = name;
574 while (*name_no_leading_slash ==
'/') {
575 name_no_leading_slash += 1;
577 if ((strcmp(name_no_leading_slash,
"") == 0) || (strcmp(name_no_leading_slash,
".") == 0)) {
578 if (fatfs_fs_driver_get_mounted_bd_from_index(fd->unit) == NULL) {
582 memset(stat, 0,
sizeof(*stat));
588 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(name, fd);
592 ret = f_stat(modified_name, &fno);
595 fileInfoToStat(&fno, stat);
604static int get_frag_list(FIL *file,
void *rdata,
unsigned int rdatalen)
606 bd_fragment_t *f = (bd_fragment_t*)rdata;
607 int iMaxFragments = rdatalen /
sizeof(bd_fragment_t);
611 struct block_device* bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
613 DWORD iClusterStart = file->obj.sclust;
614 DWORD iClusterCurrent = iClusterStart;
617 DWORD iClusterNext = get_fat(&file->obj, iClusterCurrent);
618 if (iClusterNext != (iClusterCurrent + 1)) {
620 M_DEBUG(
"fragment: %uc - %uc + 1\n", iClusterStart, iClusterCurrent + 1);
621 if (iFragCount < iMaxFragments) {
622 u64 sector = clst2sect(file->obj.fs, iClusterStart) + bd->sectorOffset;
623 f[iFragCount].sector = sector;
624 f[iFragCount].count = clst2sect(file->obj.fs, iClusterCurrent) - clst2sect(file->obj.fs, iClusterStart) + file->obj.fs->csize;
625 DEBUG_U64_2XU32(sector);
626 M_DEBUG(
" - sectors: 0x%08x%08x count %u\n", sector_u32[1], sector_u32[0], f[iFragCount].
count);
629 iClusterStart = iClusterNext;
631 iClusterCurrent = iClusterNext;
632 }
while(iClusterCurrent < file->obj.fs->n_fatent);
638int fs_ioctl2(
iop_file_t *fd,
int cmd,
void *data,
unsigned int datalen,
void *rdata,
unsigned int rdatalen)
640 M_DEBUG(
"%s cmd=%d\n", __func__, cmd);
643 FIL *file = ((FIL *)(fd->privdata));
661 ret = file->obj.sclust;
665 if (rdata == NULL || rdatalen <
sizeof(u64))
672 struct block_device* bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
674 *(u64*)rdata = clst2sect(file->obj.fs, file->obj.sclust) + bd->sectorOffset;
678 struct block_device *mounted_bd = fatfs_fs_driver_get_mounted_bd_from_index(fd->unit);
679 ret = (mounted_bd == NULL) ? -
ENXIO : *(int *)(mounted_bd->name);
683 strncpy(rdata, mounted_bd->name, rdatalen);
687 ret = get_frag_list(file, NULL, 0) == 1 ? 1 : 0;
690 ret = get_frag_list(file, rdata, rdatalen);
695 if (rdata == NULL || rdatalen <
sizeof(u32))
701 struct block_device* bd = fatfs_fs_driver_get_mounted_bd_from_index(file->obj.fs->pdrv);
706 *(u32*)rdata = bd->devNr;
720int fs_ioctl(
iop_file_t *fd,
int cmd,
void *data)
722 return fs_ioctl2(fd, cmd, data, 1024, NULL, 0);
725int fs_rename(
iop_file_t *fd,
const char *path,
const char *newpath)
727 M_DEBUG(
"%s\n", __func__);
730 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(path);
731 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_DEFINITIONS(newpath);
733 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(path, fd);
734 FATFS_FS_DRIVER_NAME_ALLOC_ON_STACK_IMPLEMENTATION(newpath, fd);
737 if (strcmp(modified_path, modified_newpath) == 0) {
743 ret = f_rename(modified_path, modified_newpath);
749static int fs_devctl(
iop_file_t *fd,
const char *name,
int cmd,
void *arg,
unsigned int arglen,
void *buf,
unsigned int buflen)
764 fatfs_fs_driver_stop_all_bd();
769 fatfs_fs_driver_stop_single_bd(fd->unit);
784IOMANX_RETURN_VALUE_IMPL(0);
785IOMANX_RETURN_VALUE_IMPL(
EIO);
788 IOMANX_RETURN_VALUE(0),
789 IOMANX_RETURN_VALUE(0),
790 IOMANX_RETURN_VALUE(
EIO),
804 IOMANX_RETURN_VALUE(
EIO),
806 IOMANX_RETURN_VALUE(
EIO),
807 IOMANX_RETURN_VALUE(
EIO),
808 IOMANX_RETURN_VALUE(
EIO),
809 IOMANX_RETURN_VALUE(
EIO),
812 IOMANX_RETURN_VALUE(
EIO),
813 IOMANX_RETURN_VALUE(
EIO),
827 M_DEBUG(
"%s\n", __func__);
830 fatfs_fs_driver_initialize_all_mount_info();
832 DelDrv(fs_driver.name);
833 return (AddDrv(&fs_driver) == 0 ? 0 : -1);
#define USBMASS_IOCTL_GET_CLUSTER
#define USBMASS_IOCTL_GET_DRIVERNAME
u32 count
start sector of fragmented bd/file
#define USBMASS_DEVCTL_STOP_ALL
#define USBMASS_DEVCTL_STOP_UNIT
#define USBMASS_IOCTL_RENAME
#define USBMASS_IOCTL_GET_DEVICE_NUMBER
#define USBMASS_IOCTL_GET_LBA
#define USBMASS_IOCTL_GET_FRAGLIST
#define USBMASS_IOCTL_CHECK_CHAIN