diff options
| author | prife <[email protected]> | 2013-01-08 20:30:57 +0800 |
|---|---|---|
| committer | prife <[email protected]> | 2013-01-08 20:30:57 +0800 |
| commit | 4bc0347b114e65ad68fd8d6a4a0201686af4a6b9 (patch) | |
| tree | b1209011764fbf73ccf31852bb755dcf7880347f /components/dfs | |
| parent | 1e6bf8671ca3b4e5c305cab47d2b397e9e60253f (diff) | |
update dfs_xxx_mkfs in jffs2 nand uffs.c to use new args
Diffstat (limited to 'components/dfs')
| -rw-r--r-- | components/dfs/filesystems/jffs2/dfs_jffs2.c | 2 | ||||
| -rw-r--r-- | components/dfs/filesystems/uffs/dfs_uffs.c | 1314 |
2 files changed, 657 insertions, 659 deletions
diff --git a/components/dfs/filesystems/jffs2/dfs_jffs2.c b/components/dfs/filesystems/jffs2/dfs_jffs2.c index 8bd483e9a4..04022f4cc7 100644 --- a/components/dfs/filesystems/jffs2/dfs_jffs2.c +++ b/components/dfs/filesystems/jffs2/dfs_jffs2.c @@ -222,7 +222,7 @@ static int dfs_jffs2_unmount(struct dfs_filesystem* fs) return -DFS_STATUS_ENOENT; } -static int dfs_jffs2_mkfs(const char* device_name) +static int dfs_jffs2_mkfs(rt_device_t dev_id) { /* just erase all blocks on this nand partition */ return -DFS_STATUS_ENOSYS; diff --git a/components/dfs/filesystems/uffs/dfs_uffs.c b/components/dfs/filesystems/uffs/dfs_uffs.c index d4997faa98..6072910058 100644 --- a/components/dfs/filesystems/uffs/dfs_uffs.c +++ b/components/dfs/filesystems/uffs/dfs_uffs.c @@ -1,658 +1,656 @@ -/*
- * File : rtthread.h
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006-2012, RT-Thread Development Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE.
- *
- * Change Logs:
- * Date Author Notes
- * 2011-10-22 prife the first version
- * 2012-03-28 prife use mtd device interface
- * 2012-04-05 prife update uffs with official repo and use uffs_UnMount/Mount
-*/
-#include <rtthread.h>
-
-#include <dfs_fs.h>
-#include <dfs_def.h>
-#include <rtdevice.h>
-#include "dfs_uffs.h"
-
-#include "uffs/uffs_fd.h" /* posix file api is here */
-#include "uffs/uffs_mtb.h"
-#include "uffs/uffs_mem.h"
-#include "uffs/uffs_utils.h"
-
-/*
- * RT-Thread DFS Interface for uffs
- */
-#define UFFS_DEVICE_MAX 2 /* the max partions on a nand deivce*/
-#define UFFS_MOUNT_PATH_MAX 128 /* the mount point max length */
-#define FILE_PATH_MAX 256 /* the longest file path */
-
-struct _nand_dev
-{
- struct rt_mtd_nand_device * dev;
- struct uffs_StorageAttrSt storage;
- uffs_Device uffs_dev;
- uffs_MountTable mount_table;
- char mount_path[UFFS_MOUNT_PATH_MAX];
- void * data; /* when uffs use static buf, it will save ptr here */
-};
-/* make sure the following struct var had been initilased to 0! */
-static struct _nand_dev nand_part[UFFS_DEVICE_MAX] = {0};
-
-static int uffs_result_to_dfs(int result)
-{
- int status = -1;
-
- result = result < 0 ? -result : result;
- switch (result)
- {
- case UENOERR:/** no error */
- break;
- case UEACCES:/** Tried to open read-only file for writing, or files sharing mode
- does not allow specified operations, or given path is directory */
- status = -DFS_STATUS_EINVAL;
- break;/* no suitable */
- case UEEXIST: /** _O_CREAT and _O_EXCL flags specified, but filename already exists */
- status = -DFS_STATUS_EEXIST;
- break;
- case UEINVAL: /** Invalid oflag or pmode argument */
- status = -DFS_STATUS_EINVAL;
- break;
- case UEMFILE: /** No more file handles available(too many open files) */
- status = -1;
- break;
- case UENOENT: /** file or path not found */
- status = -DFS_STATUS_ENOENT;
- break;
- case UETIME: /** can't set file time */
- status = -1;
- break;
- case UEBADF: /** invalid file handle */
- status = -DFS_STATUS_EBADF;
- break;
- case UENOMEM:/** no enough memory */
- status = -DFS_STATUS_ENOSPC;
- break;
- case UEIOERR: /** I/O error from lower level flash operation */
- status = -DFS_STATUS_EIO;
- break;
- case UENOTDIR: /** Not a directory */
- status = -DFS_STATUS_ENOTDIR;
- break;
- case UEISDIR: /** Is a directory */
- status = -DFS_STATUS_EISDIR;
- break;
- case UEUNKNOWN_ERR:
- default:
- status = -1;
- break; /* unknown error! */
- }
-
- return status;
-}
-
-static URET _device_init(uffs_Device *dev)
-{
- dev->attr->_private = NULL; // hook nand_chip data structure to attr->_private
- dev->ops = (struct uffs_FlashOpsSt *)&nand_ops;
-
- return U_SUCC;
-}
-
-static URET _device_release(uffs_Device *dev)
-{
- return U_SUCC;
-}
-
-static int init_uffs_fs(
- struct _nand_dev * nand_part)
-{
- uffs_MountTable * mtb;
- struct rt_mtd_nand_device * nand;
- struct uffs_StorageAttrSt * flash_storage;
-
- mtb = &nand_part->mount_table;
- nand = nand_part->dev;
- flash_storage = &nand_part->storage;
-
- /* setup nand storage attributes */
- uffs_setup_storage(flash_storage, nand);
-
- /* register mount table */
- if(mtb->dev)
- {
- /* set memory allocator for uffs */
-#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
- uffs_MemSetupSystemAllocator(&mtb->dev->mem);
-#endif
- /* setup device init/release entry */
- mtb->dev->Init = _device_init;
- mtb->dev->Release = _device_release;
- mtb->dev->attr = flash_storage;
-
- uffs_RegisterMountTable(mtb);
- }
- /* mount uffs partion on nand device */
- return uffs_Mount(nand_part->mount_path) == U_SUCC ? 0 : -1;
-}
-
-static int dfs_uffs_mount(
- struct dfs_filesystem* fs,
- unsigned long rwflag,
- const void* data)
-{
- rt_base_t index;
- uffs_MountTable * mount_part;
- struct rt_mtd_nand_device * dev;
-
- RT_ASSERT(rt_strlen(fs->path) < (UFFS_MOUNT_PATH_MAX-1));
- dev = RT_MTD_NAND_DEVICE(fs->dev_id);
-
- /*1. find a empty entry in partition table */
- for (index = 0; index < UFFS_DEVICE_MAX ; index ++)
- {
- if (nand_part[index].dev == RT_NULL)
- break;
- }
- if (index == UFFS_DEVICE_MAX)
- return -DFS_STATUS_ENOENT;
-
- /*2. fill partition structure */
- nand_part[index].dev = dev;
-
- /* make a right mount path for uffs, end with '/' */
- rt_snprintf(nand_part[index].mount_path, UFFS_MOUNT_PATH_MAX, "%s/", fs->path);
- if (nand_part[index].mount_path[1] == '/')
- nand_part[index].mount_path[1] = 0;
-
- mount_part = &(nand_part[index].mount_table);
- mount_part->mount = nand_part[index].mount_path;
- mount_part->dev = &(nand_part[index].uffs_dev);
- rt_memset(mount_part->dev, 0, sizeof(uffs_Device));//in order to make uffs happy.
- mount_part->dev->_private = dev; /* save dev_id into uffs */
- mount_part->start_block = dev->block_start;
- mount_part->end_block = dev->block_end;
- /*3. mount uffs */
- if (init_uffs_fs(&nand_part[index]) < 0)
- {
- return uffs_result_to_dfs(uffs_get_error());
- }
- return 0;
-}
-
-static int dfs_uffs_unmount(struct dfs_filesystem* fs)
-{
- rt_base_t index;
- int result;
-
- /* find the device index and then unmount it */
- for (index = 0; index < UFFS_DEVICE_MAX; index++)
- {
- if (nand_part[index].dev == RT_MTD_NAND_DEVICE(fs->dev_id))
- {
- nand_part[index].dev = RT_NULL;
- result = uffs_UnMount(nand_part[index].mount_path);
- if (result != U_SUCC)
- break;
-
- result = uffs_UnRegisterMountTable(& nand_part[index].mount_table);
- return (result == U_SUCC) ? DFS_STATUS_OK : -1;
- }
- }
- return -DFS_STATUS_ENOENT;
-}
-
-static int dfs_uffs_mkfs(const char* device_name)
-{
- rt_base_t index;
- rt_uint32_t block;
- struct rt_mtd_nand_device * mtd;
-
- /*1. find the device index */
- for (index = 0; index < UFFS_DEVICE_MAX; index++)
- {
- if (rt_strncmp(nand_part[index].dev->parent.parent.name,
- device_name, RT_NAME_MAX) == 0)
- break;
- }
-
- if (index == UFFS_DEVICE_MAX)
- {
- /* can't find device driver */
- rt_kprintf("can not find device driver: %s\n", device_name);
- return -DFS_STATUS_ENOENT;
- }
-
- /*2. then unmount the partition */
- uffs_Mount(nand_part[index].mount_path);
- mtd = nand_part[index].dev;
-
- /*3. erase all blocks on the partition */
- block = mtd->block_start;
- for (; block <= mtd->block_end; block++)
- {
- rt_mtd_nand_erase_block(mtd, block);
- if (rt_mtd_nand_check_block(mtd, block) != RT_EOK)
- {
- rt_kprintf("found bad block %d\n", block);
- rt_mtd_nand_mark_badblock(mtd, block);
- }
- }
-
- /*4. remount it */
- if (init_uffs_fs(&nand_part[index]) < 0)
- {
- return uffs_result_to_dfs(uffs_get_error());
- }
- return DFS_STATUS_OK;
-}
-
-static int dfs_uffs_statfs(struct dfs_filesystem* fs,
- struct statfs *buf)
-{
- rt_base_t index;
- struct rt_mtd_nand_device * mtd = RT_MTD_NAND_DEVICE(fs->dev_id);
-
- RT_ASSERT(mtd != RT_NULL);
-
- /* find the device index */
- for (index = 0; index < UFFS_DEVICE_MAX; index++)
- {
- if (nand_part[index].dev == (void *)mtd)
- break;
- }
- if (index == UFFS_DEVICE_MAX)
- return -DFS_STATUS_ENOENT;
-
- buf->f_bsize = mtd->page_size;
- buf->f_blocks = mtd->pages_per_block*
- (mtd->block_end - mtd->block_start + 1);
- buf->f_bfree = uffs_GetDeviceFree(&nand_part[index].uffs_dev) / mtd->page_size;
-
- return 0;
-}
-
-static int dfs_uffs_open(struct dfs_fd* file)
-{
- int fd;
- int oflag, mode;
- char * file_path;
-
- oflag = file->flags;
- if (oflag & DFS_O_DIRECTORY) /* operations about dir */
- {
- uffs_DIR * dir;
-
- if (oflag & DFS_O_CREAT) /* create a dir*/
- {
- if (uffs_mkdir(file->path) < 0)
- return uffs_result_to_dfs(uffs_get_error());
- }
- /* open dir */
- file_path = rt_malloc(FILE_PATH_MAX);
- if(file_path == RT_NULL)
- return -DFS_STATUS_ENOMEM;
-
- if (file->path[0] == '/' && !(file->path[1] == 0))
- rt_snprintf(file_path, FILE_PATH_MAX, "%s/", file->path);
- else
- {
- file_path[0] = '/';
- file_path[1] = 0;
- }
-
- dir = uffs_opendir(file_path);
-
- if (dir == RT_NULL)
- {
- rt_free(file_path);
- return uffs_result_to_dfs(uffs_get_error());
- }
- /* save this pointer,will used by dfs_uffs_getdents*/
- file->data = dir;
- rt_free(file_path);
- return DFS_STATUS_OK;
- }
- /* regular file operations */
- /* int uffs_open(const char *name, int oflag, ...); what is this?
- * uffs_open can open dir!! **/
- mode = 0;
- if (oflag & DFS_O_RDONLY) mode |= UO_RDONLY;
- if (oflag & DFS_O_WRONLY) mode |= UO_WRONLY;
- if (oflag & DFS_O_RDWR) mode |= UO_RDWR;
- /* Opens the file, if it is existing. If not, a new file is created. */
- if (oflag & DFS_O_CREAT) mode |= UO_CREATE;
- /* Creates a new file. If the file is existing, it is truncated and overwritten. */
- if (oflag & DFS_O_TRUNC) mode |= UO_TRUNC;
- /* Creates a new file. The function fails if the file is already existing. */
- if (oflag & DFS_O_EXCL) mode |= UO_EXCL;
-
- fd = uffs_open(file->path, mode);
- if (fd < 0)
- {
- return uffs_result_to_dfs(uffs_get_error());
- }
-
- /* save this pointer, it will be used when calling read()��write(),
- * flush(), seek(), and will be free when calling close()*/
-
- file->data = (void *)fd;
- file->pos = uffs_seek(fd, 0, USEEK_CUR);
- file->size = uffs_seek(fd, 0, USEEK_END);
- uffs_seek(fd, file->pos, USEEK_SET);
-
- if (oflag & DFS_O_APPEND)
- {
- file->pos = uffs_seek(fd, 0, USEEK_END);
- }
- return 0;
-}
-
-static int dfs_uffs_close(struct dfs_fd* file)
-{
- int oflag;
- int fd;
-
- oflag = file->flags;
- if (oflag & DFS_O_DIRECTORY)
- {
- /* operations about dir */
- if (uffs_closedir((uffs_DIR *)(file->data)) < 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- return 0;
- }
- /* regular file operations */
- fd = (int)(file->data);
-
- if (uffs_close(fd) == 0)
- return 0;
-
- return uffs_result_to_dfs(uffs_get_error());
-}
-
-static int dfs_uffs_ioctl(struct dfs_fd * file, int cmd, void* args)
-{
- return -DFS_STATUS_ENOSYS;
-}
-
-static int dfs_uffs_read(struct dfs_fd * file, void* buf, rt_size_t len)
-{
- int fd;
- int char_read;
-
- fd = (int)(file->data);
- char_read = uffs_read(fd, buf, len);
- if (char_read < 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- /* update position */
- file->pos = uffs_seek(fd, 0, USEEK_CUR);
- return char_read;
-}
-
-static int dfs_uffs_write(struct dfs_fd* file,
- const void* buf,
- rt_size_t len)
-{
- int fd;
- int char_write;
-
- fd = (int)(file->data);
-
- char_write = uffs_write(fd, buf, len);
- if (char_write < 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- /* update position */
- file->pos = uffs_seek(fd, 0, USEEK_CUR);
- return char_write;
-}
-
-static int dfs_uffs_flush(struct dfs_fd* file)
-{
- int fd;
- int result;
-
- fd = (int)(file->data);
-
- result = uffs_flush(fd);
- if (result < 0 )
- return uffs_result_to_dfs(uffs_get_error());
- return 0;
-}
-
-int uffs_seekdir(uffs_DIR *dir, long offset)
-{
- int i = 0;
-
- while(i < offset)
- {
- if (uffs_readdir(dir) == RT_NULL)
- return -1;
- i++;
- }
- return 0;
-}
-
-
-static int dfs_uffs_seek(struct dfs_fd* file,
- rt_off_t offset)
-{
- int result;
-
- /* set offset as current offset */
- if (file->type == FT_DIRECTORY)
- {
- uffs_rewinddir((uffs_DIR *)(file->data));
- result = uffs_seekdir((uffs_DIR *)(file->data), offset/sizeof(struct dirent));
- if (result >= 0)
- {
- file->pos = offset;
- return offset;
- }
- }
- else if (file->type == FT_REGULAR)
- {
- result = uffs_seek((int)(file->data), offset, USEEK_SET);
- if (result >= 0)
- return offset;
- }
-
- return uffs_result_to_dfs(uffs_get_error());
-}
-
-/* return the size of struct dirent*/
-static int dfs_uffs_getdents(
- struct dfs_fd* file,
- struct dirent* dirp,
- rt_uint32_t count)
-{
- rt_uint32_t index;
- char * file_path;
- struct dirent* d;
- uffs_DIR* dir;
- struct uffs_dirent * uffs_d;
-
- dir = (uffs_DIR*)(file->data);
- RT_ASSERT(dir != RT_NULL);
-
- /* round count, count is always 1 */
- count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
- if (count == 0) return -DFS_STATUS_EINVAL;
-
- /* allocate file name */
- file_path = rt_malloc(FILE_PATH_MAX);
- if (file_path == RT_NULL)
- return -DFS_STATUS_ENOMEM;
-
- index = 0;
- /* usually, the while loop should only be looped only once! */
- while (1)
- {
- struct uffs_stat s;
-
- d = dirp + index;
-
- uffs_d = uffs_readdir(dir);
- if (uffs_d == RT_NULL)
- {
- rt_free(file_path);
- return (uffs_result_to_dfs(uffs_get_error()));
- }
-
- if (file->path[0] == '/' && !(file->path[1] == 0))
- rt_snprintf(file_path, FILE_PATH_MAX, "%s/%s", file->path, uffs_d->d_name);
- else
- rt_strncpy(file_path, uffs_d->d_name, FILE_PATH_MAX);
-
- uffs_stat(file_path, &s);
- switch(s.st_mode & US_IFMT) /* file type mark */
- {
- case US_IFREG: /* directory */
- d->d_type = DFS_DT_REG;
- break;
- case US_IFDIR: /* regular file */
- d->d_type = DFS_DT_DIR;
- break;
- case US_IFLNK: /* symbolic link */
- case US_IREAD: /* read permission */
- case US_IWRITE:/* write permission */
- default:
- d->d_type = DFS_DT_UNKNOWN;
- break;
- }
-
- /* write the rest args of struct dirent* dirp */
- d->d_namlen = rt_strlen(uffs_d->d_name);
- d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
- rt_strncpy(d->d_name, uffs_d->d_name, rt_strlen(uffs_d->d_name) + 1);
-
- index ++;
- if (index * sizeof(struct dirent) >= count)
- break;
- }
-
- /* free file name buf */
- rt_free(file_path);
-
- if (index == 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- file->pos += index * sizeof(struct dirent);
-
- return index * sizeof(struct dirent);
-}
-
-static int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* path)
-{
- int result;
- struct uffs_stat s;
-
- /* judge file type, dir is to be delete by uffs_rmdir, others by uffs_remove */
- if (uffs_lstat(path, &s) < 0)
- {
- return uffs_result_to_dfs(uffs_get_error());
- }
-
- switch(s.st_mode & US_IFMT)
- {
- case US_IFREG:
- result = uffs_remove(path);
- break;
- case US_IFDIR:
- result = uffs_rmdir(path);
- break;
- default:
- /* unknown file type */
- return -1;
- }
- if (result < 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- return 0;
-}
-
-static int dfs_uffs_rename(
- struct dfs_filesystem* fs,
- const char* oldpath,
- const char* newpath)
-{
- int result;
-
- result = uffs_rename(oldpath, newpath);
- if (result < 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- return 0;
-}
-
-static int dfs_uffs_stat(struct dfs_filesystem* fs, const char *path, struct stat *st)
-{
- int result;
- struct uffs_stat s;
- struct rt_mtd_nand_device * mtd;
-
- result = uffs_stat(path, &s);
- if (result < 0)
- return uffs_result_to_dfs(uffs_get_error());
-
- /* convert uffs stat to dfs stat structure */
- /* FIXME, these field may not be the same */
- st->st_dev = 0;
- st->st_mode = s.st_mode;
- st->st_size = s.st_size;
- st->st_mtime = s.st_mtime;
-
- mtd = RT_MTD_NAND_DEVICE(fs->dev_id);
- st->st_blksize = mtd->page_size;
-
- return 0;
-}
-
-static const struct dfs_filesystem_operation dfs_uffs_ops =
-{
- "uffs", /* file system type: uffs */
-#if RTTHREAD_VERSION >= 10100
- DFS_FS_FLAG_FULLPATH,
-#else
-#error "uffs can only work with rtthread whose version should >= 1.01\n"
-#endif
- dfs_uffs_mount,
- dfs_uffs_unmount,
- dfs_uffs_mkfs,
- dfs_uffs_statfs,
-
- dfs_uffs_open,
- dfs_uffs_close,
- dfs_uffs_ioctl,
- dfs_uffs_read,
- dfs_uffs_write,
- dfs_uffs_flush,
- dfs_uffs_seek,
- dfs_uffs_getdents,
- dfs_uffs_unlink,
- dfs_uffs_stat,
- dfs_uffs_rename,
-};
-
-int dfs_uffs_init(void)
-{
- /* register uffs file system */
- dfs_register(&dfs_uffs_ops);
-
- if (uffs_InitObjectBuf() == U_SUCC)
- {
- if (uffs_DirEntryBufInit() == U_SUCC)
- {
- uffs_InitGlobalFsLock();
- return RT_EOK;
- }
- }
- return -RT_ERROR;
-}
+/* + * File : rtthread.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006-2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE. + * + * Change Logs: + * Date Author Notes + * 2011-10-22 prife the first version + * 2012-03-28 prife use mtd device interface + * 2012-04-05 prife update uffs with official repo and use uffs_UnMount/Mount +*/ +#include <rtthread.h> + +#include <dfs_fs.h> +#include <dfs_def.h> +#include <rtdevice.h> +#include "dfs_uffs.h" + +#include "uffs/uffs_fd.h" /* posix file api is here */ +#include "uffs/uffs_mtb.h" +#include "uffs/uffs_mem.h" +#include "uffs/uffs_utils.h" + +/* + * RT-Thread DFS Interface for uffs + */ +#define UFFS_DEVICE_MAX 2 /* the max partions on a nand deivce*/ +#define UFFS_MOUNT_PATH_MAX 128 /* the mount point max length */ +#define FILE_PATH_MAX 256 /* the longest file path */ + +struct _nand_dev +{ + struct rt_mtd_nand_device * dev; + struct uffs_StorageAttrSt storage; + uffs_Device uffs_dev; + uffs_MountTable mount_table; + char mount_path[UFFS_MOUNT_PATH_MAX]; + void * data; /* when uffs use static buf, it will save ptr here */ +}; +/* make sure the following struct var had been initilased to 0! */ +static struct _nand_dev nand_part[UFFS_DEVICE_MAX] = {0}; + +static int uffs_result_to_dfs(int result) +{ + int status = -1; + + result = result < 0 ? -result : result; + switch (result) + { + case UENOERR:/** no error */ + break; + case UEACCES:/** Tried to open read-only file for writing, or files sharing mode + does not allow specified operations, or given path is directory */ + status = -DFS_STATUS_EINVAL; + break;/* no suitable */ + case UEEXIST: /** _O_CREAT and _O_EXCL flags specified, but filename already exists */ + status = -DFS_STATUS_EEXIST; + break; + case UEINVAL: /** Invalid oflag or pmode argument */ + status = -DFS_STATUS_EINVAL; + break; + case UEMFILE: /** No more file handles available(too many open files) */ + status = -1; + break; + case UENOENT: /** file or path not found */ + status = -DFS_STATUS_ENOENT; + break; + case UETIME: /** can't set file time */ + status = -1; + break; + case UEBADF: /** invalid file handle */ + status = -DFS_STATUS_EBADF; + break; + case UENOMEM:/** no enough memory */ + status = -DFS_STATUS_ENOSPC; + break; + case UEIOERR: /** I/O error from lower level flash operation */ + status = -DFS_STATUS_EIO; + break; + case UENOTDIR: /** Not a directory */ + status = -DFS_STATUS_ENOTDIR; + break; + case UEISDIR: /** Is a directory */ + status = -DFS_STATUS_EISDIR; + break; + case UEUNKNOWN_ERR: + default: + status = -1; + break; /* unknown error! */ + } + + return status; +} + +static URET _device_init(uffs_Device *dev) +{ + dev->attr->_private = NULL; // hook nand_chip data structure to attr->_private + dev->ops = (struct uffs_FlashOpsSt *)&nand_ops; + + return U_SUCC; +} + +static URET _device_release(uffs_Device *dev) +{ + return U_SUCC; +} + +static int init_uffs_fs( + struct _nand_dev * nand_part) +{ + uffs_MountTable * mtb; + struct rt_mtd_nand_device * nand; + struct uffs_StorageAttrSt * flash_storage; + + mtb = &nand_part->mount_table; + nand = nand_part->dev; + flash_storage = &nand_part->storage; + + /* setup nand storage attributes */ + uffs_setup_storage(flash_storage, nand); + + /* register mount table */ + if(mtb->dev) + { + /* set memory allocator for uffs */ +#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0 + uffs_MemSetupSystemAllocator(&mtb->dev->mem); +#endif + /* setup device init/release entry */ + mtb->dev->Init = _device_init; + mtb->dev->Release = _device_release; + mtb->dev->attr = flash_storage; + + uffs_RegisterMountTable(mtb); + } + /* mount uffs partion on nand device */ + return uffs_Mount(nand_part->mount_path) == U_SUCC ? 0 : -1; +} + +static int dfs_uffs_mount( + struct dfs_filesystem* fs, + unsigned long rwflag, + const void* data) +{ + rt_base_t index; + uffs_MountTable * mount_part; + struct rt_mtd_nand_device * dev; + + RT_ASSERT(rt_strlen(fs->path) < (UFFS_MOUNT_PATH_MAX-1)); + dev = RT_MTD_NAND_DEVICE(fs->dev_id); + + /*1. find a empty entry in partition table */ + for (index = 0; index < UFFS_DEVICE_MAX ; index ++) + { + if (nand_part[index].dev == RT_NULL) + break; + } + if (index == UFFS_DEVICE_MAX) + return -DFS_STATUS_ENOENT; + + /*2. fill partition structure */ + nand_part[index].dev = dev; + + /* make a right mount path for uffs, end with '/' */ + rt_snprintf(nand_part[index].mount_path, UFFS_MOUNT_PATH_MAX, "%s/", fs->path); + if (nand_part[index].mount_path[1] == '/') + nand_part[index].mount_path[1] = 0; + + mount_part = &(nand_part[index].mount_table); + mount_part->mount = nand_part[index].mount_path; + mount_part->dev = &(nand_part[index].uffs_dev); + rt_memset(mount_part->dev, 0, sizeof(uffs_Device));//in order to make uffs happy. + mount_part->dev->_private = dev; /* save dev_id into uffs */ + mount_part->start_block = dev->block_start; + mount_part->end_block = dev->block_end; + /*3. mount uffs */ + if (init_uffs_fs(&nand_part[index]) < 0) + { + return uffs_result_to_dfs(uffs_get_error()); + } + return 0; +} + +static int dfs_uffs_unmount(struct dfs_filesystem* fs) +{ + rt_base_t index; + int result; + + /* find the device index and then unmount it */ + for (index = 0; index < UFFS_DEVICE_MAX; index++) + { + if (nand_part[index].dev == RT_MTD_NAND_DEVICE(fs->dev_id)) + { + nand_part[index].dev = RT_NULL; + result = uffs_UnMount(nand_part[index].mount_path); + if (result != U_SUCC) + break; + + result = uffs_UnRegisterMountTable(& nand_part[index].mount_table); + return (result == U_SUCC) ? DFS_STATUS_OK : -1; + } + } + return -DFS_STATUS_ENOENT; +} + +static int dfs_uffs_mkfs(rt_device_t dev_id) +{ + rt_base_t index; + rt_uint32_t block; + struct rt_mtd_nand_device * mtd; + + /*1. find the device index */ + for (index = 0; index < UFFS_DEVICE_MAX; index++) + { + if (nand_part[index].dev == (struct rt_mtd_nand_device *)dev_id) + break; + } + + if (index == UFFS_DEVICE_MAX) + { + /* can't find device driver */ + return -DFS_STATUS_ENOENT; + } + + /*2. then unmount the partition */ + uffs_Mount(nand_part[index].mount_path); + mtd = nand_part[index].dev; + + /*3. erase all blocks on the partition */ + block = mtd->block_start; + for (; block <= mtd->block_end; block++) + { + rt_mtd_nand_erase_block(mtd, block); + if (rt_mtd_nand_check_block(mtd, block) != RT_EOK) + { + rt_kprintf("found bad block %d\n", block); + rt_mtd_nand_mark_badblock(mtd, block); + } + } + + /*4. remount it */ + if (init_uffs_fs(&nand_part[index]) < 0) + { + return uffs_result_to_dfs(uffs_get_error()); + } + return DFS_STATUS_OK; +} + +static int dfs_uffs_statfs(struct dfs_filesystem* fs, + struct statfs *buf) +{ + rt_base_t index; + struct rt_mtd_nand_device * mtd = RT_MTD_NAND_DEVICE(fs->dev_id); + + RT_ASSERT(mtd != RT_NULL); + + /* find the device index */ + for (index = 0; index < UFFS_DEVICE_MAX; index++) + { + if (nand_part[index].dev == (void *)mtd) + break; + } + if (index == UFFS_DEVICE_MAX) + return -DFS_STATUS_ENOENT; + + buf->f_bsize = mtd->page_size; + buf->f_blocks = mtd->pages_per_block* + (mtd->block_end - mtd->block_start + 1); + buf->f_bfree = uffs_GetDeviceFree(&nand_part[index].uffs_dev) / mtd->page_size; + + return 0; +} + +static int dfs_uffs_open(struct dfs_fd* file) +{ + int fd; + int oflag, mode; + char * file_path; + + oflag = file->flags; + if (oflag & DFS_O_DIRECTORY) /* operations about dir */ + { + uffs_DIR * dir; + + if (oflag & DFS_O_CREAT) /* create a dir*/ + { + if (uffs_mkdir(file->path) < 0) + return uffs_result_to_dfs(uffs_get_error()); + } + /* open dir */ + file_path = rt_malloc(FILE_PATH_MAX); + if(file_path == RT_NULL) + return -DFS_STATUS_ENOMEM; + + if (file->path[0] == '/' && !(file->path[1] == 0)) + rt_snprintf(file_path, FILE_PATH_MAX, "%s/", file->path); + else + { + file_path[0] = '/'; + file_path[1] = 0; + } + + dir = uffs_opendir(file_path); + + if (dir == RT_NULL) + { + rt_free(file_path); + return uffs_result_to_dfs(uffs_get_error()); + } + /* save this pointer,will used by dfs_uffs_getdents*/ + file->data = dir; + rt_free(file_path); + return DFS_STATUS_OK; + } + /* regular file operations */ + /* int uffs_open(const char *name, int oflag, ...); what is this? + * uffs_open can open dir!! **/ + mode = 0; + if (oflag & DFS_O_RDONLY) mode |= UO_RDONLY; + if (oflag & DFS_O_WRONLY) mode |= UO_WRONLY; + if (oflag & DFS_O_RDWR) mode |= UO_RDWR; + /* Opens the file, if it is existing. If not, a new file is created. */ + if (oflag & DFS_O_CREAT) mode |= UO_CREATE; + /* Creates a new file. If the file is existing, it is truncated and overwritten. */ + if (oflag & DFS_O_TRUNC) mode |= UO_TRUNC; + /* Creates a new file. The function fails if the file is already existing. */ + if (oflag & DFS_O_EXCL) mode |= UO_EXCL; + + fd = uffs_open(file->path, mode); + if (fd < 0) + { + return uffs_result_to_dfs(uffs_get_error()); + } + + /* save this pointer, it will be used when calling read()��write(), + * flush(), seek(), and will be free when calling close()*/ + + file->data = (void *)fd; + file->pos = uffs_seek(fd, 0, USEEK_CUR); + file->size = uffs_seek(fd, 0, USEEK_END); + uffs_seek(fd, file->pos, USEEK_SET); + + if (oflag & DFS_O_APPEND) + { + file->pos = uffs_seek(fd, 0, USEEK_END); + } + return 0; +} + +static int dfs_uffs_close(struct dfs_fd* file) +{ + int oflag; + int fd; + + oflag = file->flags; + if (oflag & DFS_O_DIRECTORY) + { + /* operations about dir */ + if (uffs_closedir((uffs_DIR *)(file->data)) < 0) + return uffs_result_to_dfs(uffs_get_error()); + + return 0; + } + /* regular file operations */ + fd = (int)(file->data); + + if (uffs_close(fd) == 0) + return 0; + + return uffs_result_to_dfs(uffs_get_error()); +} + +static int dfs_uffs_ioctl(struct dfs_fd * file, int cmd, void* args) +{ + return -DFS_STATUS_ENOSYS; +} + +static int dfs_uffs_read(struct dfs_fd * file, void* buf, rt_size_t len) +{ + int fd; + int char_read; + + fd = (int)(file->data); + char_read = uffs_read(fd, buf, len); + if (char_read < 0) + return uffs_result_to_dfs(uffs_get_error()); + + /* update position */ + file->pos = uffs_seek(fd, 0, USEEK_CUR); + return char_read; +} + +static int dfs_uffs_write(struct dfs_fd* file, + const void* buf, + rt_size_t len) +{ + int fd; + int char_write; + + fd = (int)(file->data); + + char_write = uffs_write(fd, buf, len); + if (char_write < 0) + return uffs_result_to_dfs(uffs_get_error()); + + /* update position */ + file->pos = uffs_seek(fd, 0, USEEK_CUR); + return char_write; +} + +static int dfs_uffs_flush(struct dfs_fd* file) +{ + int fd; + int result; + + fd = (int)(file->data); + + result = uffs_flush(fd); + if (result < 0 ) + return uffs_result_to_dfs(uffs_get_error()); + return 0; +} + +int uffs_seekdir(uffs_DIR *dir, long offset) +{ + int i = 0; + + while(i < offset) + { + if (uffs_readdir(dir) == RT_NULL) + return -1; + i++; + } + return 0; +} + + +static int dfs_uffs_seek(struct dfs_fd* file, + rt_off_t offset) +{ + int result; + + /* set offset as current offset */ + if (file->type == FT_DIRECTORY) + { + uffs_rewinddir((uffs_DIR *)(file->data)); + result = uffs_seekdir((uffs_DIR *)(file->data), offset/sizeof(struct dirent)); + if (result >= 0) + { + file->pos = offset; + return offset; + } + } + else if (file->type == FT_REGULAR) + { + result = uffs_seek((int)(file->data), offset, USEEK_SET); + if (result >= 0) + return offset; + } + + return uffs_result_to_dfs(uffs_get_error()); +} + +/* return the size of struct dirent*/ +static int dfs_uffs_getdents( + struct dfs_fd* file, + struct dirent* dirp, + rt_uint32_t count) +{ + rt_uint32_t index; + char * file_path; + struct dirent* d; + uffs_DIR* dir; + struct uffs_dirent * uffs_d; + + dir = (uffs_DIR*)(file->data); + RT_ASSERT(dir != RT_NULL); + + /* round count, count is always 1 */ + count = (count / sizeof(struct dirent)) * sizeof(struct dirent); + if (count == 0) return -DFS_STATUS_EINVAL; + + /* allocate file name */ + file_path = rt_malloc(FILE_PATH_MAX); + if (file_path == RT_NULL) + return -DFS_STATUS_ENOMEM; + + index = 0; + /* usually, the while loop should only be looped only once! */ + while (1) + { + struct uffs_stat s; + + d = dirp + index; + + uffs_d = uffs_readdir(dir); + if (uffs_d == RT_NULL) + { + rt_free(file_path); + return (uffs_result_to_dfs(uffs_get_error())); + } + + if (file->path[0] == '/' && !(file->path[1] == 0)) + rt_snprintf(file_path, FILE_PATH_MAX, "%s/%s", file->path, uffs_d->d_name); + else + rt_strncpy(file_path, uffs_d->d_name, FILE_PATH_MAX); + + uffs_stat(file_path, &s); + switch(s.st_mode & US_IFMT) /* file type mark */ + { + case US_IFREG: /* directory */ + d->d_type = DFS_DT_REG; + break; + case US_IFDIR: /* regular file */ + d->d_type = DFS_DT_DIR; + break; + case US_IFLNK: /* symbolic link */ + case US_IREAD: /* read permission */ + case US_IWRITE:/* write permission */ + default: + d->d_type = DFS_DT_UNKNOWN; + break; + } + + /* write the rest args of struct dirent* dirp */ + d->d_namlen = rt_strlen(uffs_d->d_name); + d->d_reclen = (rt_uint16_t)sizeof(struct dirent); + rt_strncpy(d->d_name, uffs_d->d_name, rt_strlen(uffs_d->d_name) + 1); + + index ++; + if (index * sizeof(struct dirent) >= count) + break; + } + + /* free file name buf */ + rt_free(file_path); + + if (index == 0) + return uffs_result_to_dfs(uffs_get_error()); + + file->pos += index * sizeof(struct dirent); + + return index * sizeof(struct dirent); +} + +static int dfs_uffs_unlink(struct dfs_filesystem* fs, const char* path) +{ + int result; + struct uffs_stat s; + + /* judge file type, dir is to be delete by uffs_rmdir, others by uffs_remove */ + if (uffs_lstat(path, &s) < 0) + { + return uffs_result_to_dfs(uffs_get_error()); + } + + switch(s.st_mode & US_IFMT) + { + case US_IFREG: + result = uffs_remove(path); + break; + case US_IFDIR: + result = uffs_rmdir(path); + break; + default: + /* unknown file type */ + return -1; + } + if (result < 0) + return uffs_result_to_dfs(uffs_get_error()); + + return 0; +} + +static int dfs_uffs_rename( + struct dfs_filesystem* fs, + const char* oldpath, + const char* newpath) +{ + int result; + + result = uffs_rename(oldpath, newpath); + if (result < 0) + return uffs_result_to_dfs(uffs_get_error()); + + return 0; +} + +static int dfs_uffs_stat(struct dfs_filesystem* fs, const char *path, struct stat *st) +{ + int result; + struct uffs_stat s; + struct rt_mtd_nand_device * mtd; + + result = uffs_stat(path, &s); + if (result < 0) + return uffs_result_to_dfs(uffs_get_error()); + + /* convert uffs stat to dfs stat structure */ + /* FIXME, these field may not be the same */ + st->st_dev = 0; + st->st_mode = s.st_mode; + st->st_size = s.st_size; + st->st_mtime = s.st_mtime; + + mtd = RT_MTD_NAND_DEVICE(fs->dev_id); + st->st_blksize = mtd->page_size; + + return 0; +} + +static const struct dfs_filesystem_operation dfs_uffs_ops = +{ + "uffs", /* file system type: uffs */ +#if RTTHREAD_VERSION >= 10100 + DFS_FS_FLAG_FULLPATH, +#else +#error "uffs can only work with rtthread whose version should >= 1.01\n" +#endif + dfs_uffs_mount, + dfs_uffs_unmount, + dfs_uffs_mkfs, + dfs_uffs_statfs, + + dfs_uffs_open, + dfs_uffs_close, + dfs_uffs_ioctl, + dfs_uffs_read, + dfs_uffs_write, + dfs_uffs_flush, + dfs_uffs_seek, + dfs_uffs_getdents, + dfs_uffs_unlink, + dfs_uffs_stat, + dfs_uffs_rename, +}; + +int dfs_uffs_init(void) +{ + /* register uffs file system */ + dfs_register(&dfs_uffs_ops); + + if (uffs_InitObjectBuf() == U_SUCC) + { + if (uffs_DirEntryBufInit() == U_SUCC) + { + uffs_InitGlobalFsLock(); + return RT_EOK; + } + } + return -RT_ERROR; +} |
