rt-thread/bsp/efm32/copy_this_file_dfs_elm.c
onelife.real ef6bbc34fa *** EFM32 branch ***
1. Add ENC28J60 Ethernet controller driver 
2. Add lwIP support (Please read "Readme.txt")
3. Add simple Http server demo application
4. Modify USART device write function to avoid sleep in ISR
5. Fix a bug in USART driver when using compiler optimization
6. Modify to make use the start-up code in libraries
7. Change the default build option for squeezing the executable file size
8. Modify source code alignment

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1622 bbd45198-f89e-11dd-88c7-29a3b14d5316
2011-07-08 07:13:20 +00:00

928 lines
18 KiB
C

#include <rtthread.h>
#include "ffconf.h"
#include "ff.h"
/* ELM FatFs provide a DIR struct */
#define HAVE_DIR_STRUCTURE
#include <dfs_fs.h>
#include <dfs_def.h>
#ifdef DFS_ELMFAT_INTERFACE_EFM
#include "diskio.h"
/* Disk status */
static volatile DSTATUS diskStat[_VOLUMES];
#endif
static rt_device_t disk[_VOLUMES] = {0};
static int elm_result_to_dfs(FRESULT result)
{
int status = DFS_STATUS_OK;
switch (result)
{
case FR_OK:
break;
case FR_NO_FILE:
case FR_NO_PATH:
case FR_NO_FILESYSTEM:
status = -DFS_STATUS_ENOENT;
break;
case FR_INVALID_NAME:
status = -DFS_STATUS_EINVAL;
break;
case FR_EXIST:
case FR_INVALID_OBJECT:
status = -DFS_STATUS_EEXIST;
break;
case FR_DISK_ERR:
case FR_NOT_READY:
case FR_INT_ERR:
status = -DFS_STATUS_EIO;
break;
case FR_WRITE_PROTECTED:
case FR_DENIED:
status = -DFS_STATUS_EROFS;
break;
case FR_MKFS_ABORTED:
status = -DFS_STATUS_EINVAL;
break;
default:
status = -1;
break;
}
return status;
}
int dfs_elm_mount(struct dfs_filesystem* fs, unsigned long rwflag, const void* data)
{
FATFS *fat;
FRESULT result;
rt_uint32_t index;
/* handle RT-Thread device routine */
for (index = 0; index < _VOLUMES; index ++)
{
if (disk[index] == RT_NULL)
{
break;
}
}
if (index == _VOLUMES) return -DFS_STATUS_ENOSPC;
/* get device */
disk[index] = fs->dev_id;
fat = (FATFS *) rt_malloc(sizeof(FATFS));
if (fat == RT_NULL)
{
return -1;
}
/* mount fatfs, always 0 logic driver */
result = f_mount(index, fat);
if (result == FR_OK)
fs->data = fat;
else
{
rt_free(fat);
return elm_result_to_dfs(result);
}
return 0;
}
int dfs_elm_unmount(struct dfs_filesystem* fs)
{
FATFS *fat;
FRESULT result;
rt_uint32_t index;
fat = (FATFS*) fs->data;
RT_ASSERT(fat != RT_NULL);
/* find the device index and then umount it */
for (index = 0; index < _VOLUMES; index ++)
{
if (disk[index] == fs->dev_id)
{
result = f_mount(index, RT_NULL);
if (result == FR_OK)
{
fs->data = RT_NULL;
disk[index] = RT_NULL;
rt_free(fat);
return DFS_STATUS_OK;
}
}
}
return -DFS_STATUS_ENOENT;
}
int dfs_elm_mkfs(const char* device_name)
{
BYTE drv;
rt_device_t dev;
FRESULT result;
/* find device name */
for (drv = 0; drv < _VOLUMES; drv ++)
{
dev = disk[drv];
if (rt_strncmp(dev->parent.name, device_name, RT_NAME_MAX) == 0)
{
/* 1: no partition table */
/* 0: auto selection of cluster size */
result = f_mkfs(drv, 1, 0);
if ( result != FR_OK)
{
rt_kprintf("format error\n");
return elm_result_to_dfs(result);
}
return DFS_STATUS_OK;
}
}
/* can't find device driver */
rt_kprintf("can not find device driver: %s\n", device_name);
return -DFS_STATUS_EIO;
}
int dfs_elm_statfs(struct dfs_filesystem* fs, struct statfs *buf)
{
FATFS *f;
FRESULT res;
char driver[4];
DWORD fre_clust, fre_sect, tot_sect;
RT_ASSERT(fs != RT_NULL);
RT_ASSERT(buf != RT_NULL);
f = (FATFS*) fs->data;
rt_snprintf(driver, sizeof(driver), "%d:", f->drv);
res = f_getfree(driver, &fre_clust, &f);
if (res) return elm_result_to_dfs(res);
/* Get total sectors and free sectors */
tot_sect = (f->n_fatent - 2) * f->csize;
fre_sect = fre_clust * f->csize;
buf->f_bfree = fre_sect;
buf->f_blocks = tot_sect;
buf->f_bsize = 512;
return 0;
}
int dfs_elm_open(struct dfs_fd* file)
{
FIL* fd;
BYTE mode;
FRESULT result;
char *drivers_fn;
#if (_VOLUMES > 1)
int vol;
extern int elm_get_vol(FATFS *fat);
/* add path for ELM FatFS driver support */
vol = elm_get_vol((FATFS *)file->fs->data);
if (vol < 0) return -DFS_STATUS_ENOENT;
drivers_fn = rt_malloc(256);
if (drivers_fn == RT_NULL) return -DFS_STATUS_ENOMEM;
rt_snprintf(drivers_fn, 256, "%d:%s", vol, file->path);
#else
drivers_fn = file->path;
#endif
if (file->flags & DFS_O_DIRECTORY)
{
DIR *dir;
if (file->flags & DFS_O_CREAT)
{
result = f_mkdir(drivers_fn);
if (result != FR_OK)
{
#if _VOLUMES > 1
rt_free(drivers_fn);
#endif
return elm_result_to_dfs(result);
}
}
/* open directory */
dir = (DIR *)rt_malloc(sizeof(DIR));
if (dir == RT_NULL)
{
#if _VOLUMES > 1
rt_free(drivers_fn);
#endif
return -DFS_STATUS_ENOMEM;
}
result = f_opendir(dir, drivers_fn);
#if _VOLUMES > 1
rt_free(drivers_fn);
#endif
if (result != FR_OK)
{
rt_free(dir);
return elm_result_to_dfs(result);
}
file->data = dir;
return DFS_STATUS_OK;
}
else
{
mode = FA_READ;
if (file->flags & DFS_O_WRONLY) mode |= FA_WRITE;
if ((file->flags & DFS_O_ACCMODE) & DFS_O_RDWR) mode |= FA_WRITE;
/* Opens the file, if it is existing. If not, a new file is created. */
if (file->flags & DFS_O_CREAT) mode |= FA_OPEN_ALWAYS;
/* Creates a new file. If the file is existing, it is truncated and overwritten. */
if (file->flags & DFS_O_TRUNC) mode |= FA_CREATE_ALWAYS;
/* Creates a new file. The function fails if the file is already existing. */
if (file->flags & DFS_O_EXCL) mode |= FA_CREATE_NEW;
/* allocate a fd */
fd = (FIL*)rt_malloc(sizeof(FIL));
if (fd == RT_NULL)
{
return -DFS_STATUS_ENOMEM;
}
result = f_open(fd, drivers_fn, mode);
#if _VOLUMES > 1
rt_free(drivers_fn);
#endif
if (result == FR_OK)
{
file->pos = fd->fptr;
file->size = fd->fsize;
file->data = fd;
if (file->flags & DFS_O_APPEND)
{
file->pos = f_lseek(fd, fd->fsize);
}
}
else
{
/* open failed, return */
rt_free(fd);
return elm_result_to_dfs(result);
}
}
return DFS_STATUS_OK;
}
int dfs_elm_close(struct dfs_fd* file)
{
FRESULT result;
result = FR_OK;
if (file->type == FT_DIRECTORY)
{
DIR* dir;
dir = (DIR*)(file->data);
RT_ASSERT(dir != RT_NULL);
/* release memory */
rt_free(dir);
}
else if (file->type == FT_REGULAR)
{
FIL* fd;
fd = (FIL*)(file->data);
RT_ASSERT(fd != RT_NULL);
result = f_close(fd);
if (result == FR_OK)
{
/* release memory */
rt_free(fd);
}
}
return elm_result_to_dfs(result);
}
int dfs_elm_ioctl(struct dfs_fd* file, int cmd, void* args)
{
return -DFS_STATUS_ENOSYS;
}
int dfs_elm_read(struct dfs_fd* file, void* buf, rt_size_t len)
{
FIL* fd;
FRESULT result;
UINT byte_read;
if (file->type == FT_DIRECTORY)
{
return -DFS_STATUS_EISDIR;
}
fd = (FIL*)(file->data);
RT_ASSERT(fd != RT_NULL);
result = f_read(fd, buf, len, &byte_read);
/* update position */
file->pos = fd->fptr;
if (result == FR_OK) return byte_read;
return elm_result_to_dfs(result);
}
int dfs_elm_write(struct dfs_fd* file, const void* buf, rt_size_t len)
{
FIL* fd;
FRESULT result;
UINT byte_write;
if (file->type == FT_DIRECTORY)
{
return -DFS_STATUS_EISDIR;
}
fd = (FIL*)(file->data);
RT_ASSERT(fd != RT_NULL);
result = f_write(fd, buf, len, &byte_write);
/* update position and file size */
file->pos = fd->fptr;
file->size = fd->fsize;
if (result == FR_OK) return byte_write;
return elm_result_to_dfs(result);
}
int dfs_elm_flush(struct dfs_fd* file)
{
FIL* fd;
FRESULT result;
fd = (FIL*)(file->data);
RT_ASSERT(fd != RT_NULL);
result = f_sync(fd);
return elm_result_to_dfs(result);
}
int dfs_elm_lseek(struct dfs_fd* file, rt_off_t offset)
{
FRESULT result;
if (file->type == FT_REGULAR)
{
FIL* fd;
/* regular file type */
fd = (FIL*)(file->data);
RT_ASSERT(fd != RT_NULL);
result = f_lseek(fd, offset);
if (result == FR_OK)
{
/* return current position */
return fd->fptr;
}
}
else if (file->type == FT_DIRECTORY)
{
/* which is a directory */
DIR* dir;
dir = (DIR*)(file->data);
RT_ASSERT(dir != RT_NULL);
result = f_seekdir(dir, offset / sizeof(struct dirent));
if (result == FR_OK)
{
/* update file position */
file->pos = offset;
return file->pos;
}
}
return elm_result_to_dfs(result);
}
int dfs_elm_getdents(struct dfs_fd* file, struct dirent* dirp, rt_uint32_t count)
{
DIR* dir;
FILINFO fno;
FRESULT result;
rt_uint32_t index;
struct dirent* d;
dir = (DIR*)(file->data);
RT_ASSERT(dir != RT_NULL);
/* make integer count */
count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
if ( count == 0 ) return -DFS_STATUS_EINVAL;
#if _USE_LFN
/* allocate long file name */
fno.lfname = rt_malloc(256);
fno.lfsize = 256;
#endif
index = 0;
while (1)
{
char *fn;
d = dirp + index;
result = f_readdir(dir, &fno);
if (result != FR_OK || fno.fname[0] == 0) break;
#if _USE_LFN
fn = *fno.lfname? fno.lfname : fno.fname;
#else
fn = fno.fname;
#endif
d->d_type = DFS_DT_UNKNOWN;
if (fno.fattrib & AM_DIR) d->d_type = DFS_DT_DIR;
else d->d_type = DFS_DT_REG;
d->d_namlen = rt_strlen(fn);
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
rt_strncpy(d->d_name, fn, rt_strlen(fn) + 1);
index ++;
if ( index * sizeof(struct dirent) >= count )
break;
}
#if _USE_LFN
rt_free(fno.lfname);
#endif
if (index == 0)
return elm_result_to_dfs(result);
file->pos += index * sizeof(struct dirent);
return index * sizeof(struct dirent);
}
int dfs_elm_unlink(struct dfs_filesystem* fs, const char* path)
{
FRESULT result;
#if _VOLUMES > 1
int vol;
char *drivers_fn;
extern int elm_get_vol(FATFS *fat);
/* add path for ELM FatFS driver support */
vol = elm_get_vol((FATFS *)fs->data);
if (vol < 0) return -DFS_STATUS_ENOENT;
drivers_fn = rt_malloc(256);
if (drivers_fn == RT_NULL) return -DFS_STATUS_ENOMEM;
rt_snprintf(drivers_fn, 256, "%d:%s", vol, path);
#else
const char *drivers_fn;
drivers_fn = path;
#endif
result = f_unlink(drivers_fn);
#if _VOLUMES > 1
rt_free(drivers_fn);
#endif
return elm_result_to_dfs(result);
}
int dfs_elm_rename(struct dfs_filesystem* fs, const char* oldpath, const char* newpath)
{
FRESULT result;
#if _VOLUMES > 1
char *drivers_oldfn, *drivers_newfn;
int vol;
extern int elm_get_vol(FATFS *fat);
/* add path for ELM FatFS driver support */
vol = elm_get_vol((FATFS *)fs->data);
if (vol < 0) return -DFS_STATUS_ENOENT;
drivers_oldfn = rt_malloc(256);
if (drivers_oldfn == RT_NULL) return -DFS_STATUS_ENOMEM;
drivers_newfn = rt_malloc(256);
if (drivers_newfn == RT_NULL)
{
rt_free(drivers_oldfn);
return -DFS_STATUS_ENOMEM;
}
rt_snprintf(drivers_oldfn, 256, "%d:%s", vol, oldpath);
rt_snprintf(drivers_newfn, 256, "%d:%s", vol, newpath);
#else
const char *drivers_oldfn, *drivers_newfn;
drivers_oldfn = oldpath;
drivers_newfn = newpath;
#endif
result = f_rename(drivers_oldfn, drivers_newfn);
#if _VOLUMES > 1
rt_free(drivers_oldfn);
rt_free(drivers_newfn);
#endif
return elm_result_to_dfs(result);
}
int dfs_elm_stat(struct dfs_filesystem* fs, const char *path, struct stat *st)
{
FILINFO file_info;
FRESULT result;
#if _VOLUMES > 1
int vol;
char *drivers_fn;
extern int elm_get_vol(FATFS *fat);
/* add path for ELM FatFS driver support */
vol = elm_get_vol((FATFS *)fs->data);
if (vol < 0) return -DFS_STATUS_ENOENT;
drivers_fn = rt_malloc(256);
if (drivers_fn == RT_NULL) return -DFS_STATUS_ENOMEM;
rt_snprintf(drivers_fn, 256, "%d:%s", vol, path);
#else
const char *drivers_fn;
drivers_fn = path;
#endif
#if _USE_LFN
/* allocate long file name */
file_info.lfname = rt_malloc(256);
file_info.lfsize = 256;
#endif
result = f_stat(drivers_fn, &file_info);
#if _VOLUMES > 1
rt_free(drivers_fn);
#endif
if (result == FR_OK)
{
/* convert to dfs stat structure */
st->st_dev = 0;
st->st_mode = DFS_S_IFREG | DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH |
DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH;
if (file_info.fattrib & AM_DIR)
{
st->st_mode &= ~DFS_S_IFREG;
st->st_mode |= DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH;
}
if (file_info.fattrib & AM_RDO)
st->st_mode &= ~(DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH);
st->st_size = file_info.fsize;
st->st_mtime = file_info.ftime;
st->st_blksize = 512;
}
#if _USE_LFN
rt_free(file_info.lfname);
#endif
return elm_result_to_dfs(result);
}
static const struct dfs_filesystem_operation dfs_elm =
{
"elm",
dfs_elm_mount,
dfs_elm_unmount,
dfs_elm_mkfs,
dfs_elm_statfs,
dfs_elm_open,
dfs_elm_close,
dfs_elm_ioctl,
dfs_elm_read,
dfs_elm_write,
dfs_elm_flush,
dfs_elm_lseek,
dfs_elm_getdents,
dfs_elm_unlink,
dfs_elm_stat,
dfs_elm_rename,
};
int elm_init(void)
{
#ifdef DFS_ELMFAT_INTERFACE_EFM
int i;
for (i = 0; i < _VOLUMES; i++)
{
diskStat[i] = STA_NOINIT;
}
#endif
/* register fatfs file system */
dfs_register(&dfs_elm);
return 0;
}
/*
* RT-Thread Device Interface for ELM FatFs
*/
#ifdef DFS_ELMFAT_INTERFACE_EFM
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber */
)
{
rt_device_t device = disk[drv];
if (!device)
{
return RES_ERROR;
}
if (diskStat[drv] & STA_NODISK)
{
/* No card in the socket */
return diskStat[drv];
}
/* Initialize hardware: the actual operation is performed in dfs_mount() */
diskStat[drv] &= ~STA_NOINIT;
return diskStat[drv];
}
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber */
)
{
return diskStat[drv];
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
rt_device_t device = disk[drv];
if (!device)
{
return RES_ERROR;
}
if (!count)
{
return RES_PARERR;
}
if (diskStat[drv] & STA_NOINIT)
{
return RES_NOTRDY;
}
if (rt_device_read(device, sector, buff, count) != count)
{
return RES_ERROR;
}
else
{
return RES_OK;
}
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
rt_device_t device = disk[drv];
if (!device)
{
return RES_ERROR;
}
if (!count)
{
return RES_PARERR;
}
if (diskStat[drv] & STA_NOINIT)
{
return RES_NOTRDY;
}
if (diskStat[drv] & STA_PROTECT)
{
return RES_WRPRT;
}
if (rt_device_write(device, sector, buff, count) != count)
{
return RES_ERROR;
}
else
{
return RES_OK;
}
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive data block */
)
{
rt_device_t device = disk[drv];
if (!device)
{
return RES_ERROR;
}
if (diskStat[drv] & STA_NOINIT)
{
return RES_NOTRDY;
}
if (rt_device_control(device, ctrl, buff) != RT_EOK)
{
return RES_ERROR;
}
else
{
return RES_OK;
}
}
#else
#include "diskio.h"
/* Inidialize a Drive */
DSTATUS disk_initialize (BYTE drv)
{
return 0;
}
/* Return Disk Status */
DSTATUS disk_status (BYTE drv)
{
return 0;
}
/* Read Sector(s) */
DRESULT disk_read (BYTE drv, BYTE *buff, DWORD sector, BYTE count)
{
rt_size_t result;
rt_device_t device = disk[drv];
result = rt_device_read(device, sector, buff, count);
if (result == count)
{
return RES_OK;
}
return RES_ERROR;
}
/* Write Sector(s) */
DRESULT disk_write (BYTE drv, const BYTE *buff, DWORD sector, BYTE count)
{
rt_size_t result;
rt_device_t device = disk[drv];
result = rt_device_write(device, sector, buff, count);
if (result == count)
{
return RES_OK;
}
return RES_ERROR;
}
/* Miscellaneous Functions */
DRESULT disk_ioctl (BYTE drv, BYTE ctrl, void *buff)
{
rt_device_t device = disk[drv];
if (device == RT_NULL) return RES_ERROR;
if (ctrl == GET_SECTOR_COUNT)
{
struct rt_device_blk_geometry geometry;
rt_memset(&geometry, 0, sizeof(geometry));
rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
*(DWORD*)buff = geometry.sector_count;
if (geometry.sector_count == 0) return RES_ERROR;
}
else if (ctrl == GET_SECTOR_SIZE)
{
struct rt_device_blk_geometry geometry;
rt_memset(&geometry, 0, sizeof(geometry));
rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
*(WORD*)buff = geometry.bytes_per_sector;
}
else if (ctrl == GET_BLOCK_SIZE) /* Get erase block size in unit of sectors (DWORD) */
{
struct rt_device_blk_geometry geometry;
rt_memset(&geometry, 0, sizeof(geometry));
rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
*(DWORD*)buff = geometry.block_size/geometry.bytes_per_sector;
}
return RES_OK;
}
#endif
rt_time_t get_fattime()
{
return 0;
}
#if _FS_REENTRANT
int ff_cre_syncobj(BYTE drv, _SYNC_t* m)
{
char name[8];
rt_mutex_t mutex;
rt_snprintf(name, sizeof(name), "fat%d", drv);
mutex = rt_mutex_create(name, RT_IPC_FLAG_FIFO);
if (mutex != RT_NULL)
{
*m = mutex;
return RT_TRUE;
}
return RT_FALSE;
}
int ff_del_syncobj(_SYNC_t m)
{
rt_mutex_delete(m);
return RT_TRUE;
}
int ff_req_grant(_SYNC_t m)
{
if (rt_mutex_take(m, _FS_TIMEOUT) == RT_EOK) return RT_TRUE;
return RT_FALSE;
}
void ff_rel_grant(_SYNC_t m)
{
rt_mutex_release(m);
}
#endif