blob: 37268e29ccb88c9d41550d8e5f421e7880d9efc9 [file] [log] [blame]
#include <stdio.h>
#include <kernel/mutex.h>
#include <malloc.h>
#include <dev/driver.h>
#include <dev/class/block.h>
#include <err.h>
#include "ff.h"
#include "diskio.h"
static struct {
FATFS work;
struct device *dev;
} mount_table[_VOLUMES];
status_t ffs_mount(size_t index, struct device *dev)
{
FRESULT res;
if (index >= countof(mount_table))
return ERR_INVALID_ARGS;
if (dev && mount_table[index].dev)
return ERR_ALREADY_MOUNTED;
if (dev) {
mount_table[index].dev = dev;
res = f_mount(index, &mount_table[index].work);
if (res != FR_OK)
return ERR_INVALID_ARGS;
} else {
mount_table[index].dev = NULL;
res = f_mount(index, NULL);
if (res != FR_OK)
return ERR_NOT_FOUND;
}
return NO_ERROR;
}
#if _USE_LFN == 3
void *ff_memalloc(UINT size)
{
return malloc(size);
}
void ff_memfree(void *mblock)
{
free(mblock);
}
#endif
#if _FS_REENTRANT
int ff_cre_syncobj(BYTE vol, _SYNC_t *sobj)
{
*sobj = malloc(sizeof(mutex_t));
if (!*sobj)
return false;
mutex_init(*sobj);
return true;
}
int ff_del_syncobj(_SYNC_t sobj)
{
mutex_destroy(sobj);
free(sobj);
return true;
}
int ff_req_grant(_SYNC_t sobj)
{
mutex_acquire(sobj);
return true;
}
void ff_rel_grant(_SYNC_t sobj)
{
mutex_release(sobj);
}
#endif
DSTATUS disk_initialize(BYTE pdrv)
{
return RES_OK;
}
DSTATUS disk_status(BYTE pdrv)
{
return RES_OK;
}
DRESULT disk_read(BYTE pdrv, BYTE* buf, DWORD sector, BYTE count)
{
ssize_t ret;
struct device *dev = mount_table[pdrv].dev;
if (!dev)
return RES_NOTRDY;
ret = class_block_read(dev, sector, buf, count);
if (ret < 0)
return RES_ERROR;
return RES_OK;
}
#if _READONLY == 0
DRESULT disk_write(BYTE pdrv, const BYTE* buf, DWORD sector, BYTE count)
{
ssize_t ret;
struct device *dev = mount_table[pdrv].dev;
if (!dev)
return RES_NOTRDY;
ret = class_block_write(dev, sector, buf, count);
if (ret < 0)
return RES_ERROR;
return RES_OK;
}
#endif
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buf)
{
ssize_t ret;
struct device *dev = mount_table[pdrv].dev;
if (!dev)
return RES_NOTRDY;
switch (cmd) {
case GET_SECTOR_SIZE: {
WORD *val = buf;
ret = class_block_get_size(dev);
if (ret < 0)
return RES_ERROR;
*val = ret;
}
break;
case GET_BLOCK_SIZE: {
DWORD *val = buf;
ret = class_block_get_size(dev);
if (ret < 0)
return RES_ERROR;
*val = ret;
}
break;
case GET_SECTOR_COUNT: {
DWORD *val = buf;
ret = class_block_get_count(dev);
if (ret < 0)
return RES_ERROR;
*val = ret;
}
break;
}
return RES_OK;
}
DWORD get_fattime(void)
{
return
((2013 - 1980) << 25) | // year
(1 << 21) | // month
(1 << 16) | // day
(0 << 11) | // hour
(0 << 5) | // minute
(0 << 0) // even second
;
}
FILE *fopen(const char *filename, const char *mode)
{
FRESULT res;
BYTE flags = 0;
FIL *fil;
int i;
fil = malloc(sizeof(FIL));
if (!fil)
return NULL;
for (i=0; mode[i] != 0; i++) {
switch (mode[i]) {
case 'w':
flags |= FA_WRITE | FA_CREATE_ALWAYS;
break;
case 'r':
flags |= FA_READ;
break;
case '+':
flags |= FA_READ | FA_WRITE;
break;
}
}
res = f_open(fil, filename, flags);
if (res != FR_OK) {
free(fil);
return NULL;
}
return (FILE *) fil;
}
int fclose(FILE *stream)
{
FRESULT res;
FIL *fil = (FIL *) stream;
res = f_close(fil);
if (res != FR_OK)
return -1;
free(fil);
return 0;
}
size_t fread(void *ptr, size_t size, size_t count, FILE *stream)
{
FRESULT res;
FIL *fil = (FIL *) stream;
UINT bread;
res = f_read(fil, ptr, size * count, &bread);
if (res != FR_OK)
return 0;
return bread;
}
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream)
{
FRESULT res;
FIL *fil = (FIL *) stream;
UINT bwrite;
res = f_write(fil, ptr, size * count, &bwrite);
if (res != FR_OK)
return 0;
return bwrite;
}
int fflush(FILE *stream)
{
FRESULT res;
FIL *fil;
if (!stream)
return 0;
fil = (FIL *) stream;
res = f_sync(fil);
if (res != FR_OK)
return -1;
return 0;
}
int feof(FILE *stream)
{
FIL *fil = (FIL *) stream;
return f_eof(fil);
}
int fseek(FILE *stream, long offset, int whence)
{
FRESULT res;
FIL *fil = (FIL *) stream;
long o;
switch (whence) {
case SEEK_SET:
o = offset;
break;
case SEEK_CUR:
o = offset + f_tell(fil);
break;
case SEEK_END:
o = f_size(fil) + offset;
if (o < 0)
o = 0;
break;
default:
return -1;
}
res = f_lseek(fil, o);
if (res != FR_OK)
return -1;
return 0;
}
long ftell(FILE *stream)
{
FIL *fil = (FIL *) stream;
return f_tell(fil);
}