|
|
|
/* vim: set ts=4 sw=4 et fdm=marker: */
|
|
|
|
#include <vxWorks.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <logLib.h>
|
|
|
|
#include <vxBusLib.h>
|
|
|
|
#include <semLib.h>
|
|
|
|
#include <taskLib.h>
|
|
|
|
#include <sysLib.h>
|
|
|
|
#include <tickLib.h>
|
|
|
|
#include <iosLib.h>
|
|
|
|
#include <errnoLib.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <hwif/vxbus/vxBus.h>
|
|
|
|
#include <hwif/vxbus/hwConf.h>
|
|
|
|
#include <hwif/vxbus/vxbPlbLib.h>
|
|
|
|
#include <hwif/util/hwMemLib.h>
|
|
|
|
#include <hwif/util/vxbParamSys.h>
|
|
|
|
#include <hwif/vxbus/vxbSpiLib.h>
|
|
|
|
#include <../h/flash/vxbFlash.h>
|
|
|
|
#include <../h/flash/vxbFlashCommon.h>
|
|
|
|
#include <usrLib.h>
|
|
|
|
|
|
|
|
#define LFS_NO_ASSERT 1
|
|
|
|
#define LFS_THREADSAFE 1
|
|
|
|
#define LFS_NO_DEBUG 1
|
|
|
|
#define LFS_NO_WARN 1
|
|
|
|
#include "lfs/lfs.c"
|
|
|
|
#include "lfs/lfs_util.c"
|
|
|
|
|
|
|
|
#define LFS_NAME "littlefs"
|
|
|
|
|
|
|
|
typedef struct __lfs_drv_ctrl lfsDrvCtrl;
|
|
|
|
typedef struct lfs_ios_drv lfsIosDrv;
|
|
|
|
|
|
|
|
struct __lfs_file_descr {
|
|
|
|
union {
|
|
|
|
lfs_file_t file;
|
|
|
|
lfs_dir_t dir;
|
|
|
|
} u;
|
|
|
|
BOOL isDir;
|
|
|
|
lfsDrvCtrl *ctrl;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct __lfs_file_descr LFS_FILE_DESC;
|
|
|
|
|
|
|
|
struct lfs_ios_drv {
|
|
|
|
DEV_HDR devHdr;
|
|
|
|
lfsDrvCtrl *pDrvCtrl;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct __lfs_drv_ctrl {
|
|
|
|
VXB_DEVICE_ID pDev;
|
|
|
|
/* per-driver info */
|
|
|
|
void *pDrvCtrl;
|
|
|
|
char name[16];
|
|
|
|
const char *mountPoint;
|
|
|
|
|
|
|
|
BOOL autoFormat;
|
|
|
|
|
|
|
|
const char *flashDrvName;
|
|
|
|
int flashUnit;
|
|
|
|
|
|
|
|
UINT32 flashOffset;
|
|
|
|
UINT32 flashSize;
|
|
|
|
UINT32 pageSize;
|
|
|
|
|
|
|
|
UINT32 blkNum;
|
|
|
|
|
|
|
|
lfsIosDrv lfsDrv;
|
|
|
|
FLASH_CHIP_ID mtd;
|
|
|
|
|
|
|
|
struct lfs_config lfsConfig;
|
|
|
|
|
|
|
|
SEM_ID lock;
|
|
|
|
lfs_t fsh;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* {{{ vxBus methods */
|
|
|
|
LOCAL void lfsDevInstInit(VXB_DEVICE_ID pDev);
|
|
|
|
LOCAL void lfsDevInstInit2(VXB_DEVICE_ID pDev);
|
|
|
|
LOCAL void lfsDevInstConnect(VXB_DEVICE_ID pDev);
|
|
|
|
LOCAL void lfsDevShow(VXB_DEVICE_ID pDev, int verbose);
|
|
|
|
LOCAL STATUS lfsDevInstUnlink(VXB_DEVICE_ID pDev, void *unused);
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* Publish the methods for the resources controlled with this file */
|
|
|
|
/* clang-format off */
|
|
|
|
LOCAL struct drvBusFuncs lfsDevFuncs = {
|
|
|
|
lfsDevInstInit, /* devInstanceInit */
|
|
|
|
lfsDevInstInit2, /* devInstanceInit2 */
|
|
|
|
lfsDevInstConnect /* devConnect */
|
|
|
|
};
|
|
|
|
LOCAL struct vxbDeviceMethod lfsDevMethods[] = {
|
|
|
|
DEVMETHOD(busDevShow , lfsDevShow),
|
|
|
|
DEVMETHOD(vxbDrvUnlink, lfsDevInstUnlink),
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
LOCAL struct vxbSpiRegister lfsDevDriver = {
|
|
|
|
{
|
|
|
|
NULL, /* pNext */
|
|
|
|
VXB_DEVID_DEVICE, /* devID */
|
|
|
|
VXB_BUSID_PLB, /* busID */
|
|
|
|
VXBUS_VERSION_5, /* vxbVersion */
|
|
|
|
LFS_NAME, /* drvName */
|
|
|
|
&lfsDevFuncs, /* pDrvBusFuncs */
|
|
|
|
lfsDevMethods, /* pMethods */
|
|
|
|
NULL, /* devProbe */
|
|
|
|
NULL, /* pParamDefaults */
|
|
|
|
},
|
|
|
|
};
|
|
|
|
/* clang-format on */
|
|
|
|
|
|
|
|
LOCAL int __lfs_driver_node = -1;
|
|
|
|
|
|
|
|
|
|
|
|
void lfsDevRegister(void)
|
|
|
|
{
|
|
|
|
(void)vxbDevRegister((struct vxbDevRegInfo *)&lfsDevDriver);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ lfsDevFuncs */
|
|
|
|
LOCAL void lfsDevInstInit(VXB_DEVICE_ID pDev)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *drv;
|
|
|
|
struct hcfDevice *pHcf;
|
|
|
|
|
|
|
|
drv = (lfsDrvCtrl *)hwMemAlloc(sizeof(*drv));
|
|
|
|
if (drv == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
drv->pDrvCtrl = pDev;
|
|
|
|
pDev->pDrvCtrl = drv;
|
|
|
|
|
|
|
|
drv->mtd = NULL;
|
|
|
|
|
|
|
|
pHcf = (struct hcfDevice *)hcfDeviceGet(pDev);
|
|
|
|
if (pHcf == NULL) {
|
|
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
|
|
hwMemFree((char *)drv);
|
|
|
|
#endif /* _VXBUS_BASIC_HWMEMLIB */
|
|
|
|
pDev->pDrvCtrl = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "flashName", HCF_RES_STRING, (void *)&drv->flashDrvName) != OK) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "flashUnit", HCF_RES_INT, (void *)&drv->flashUnit) != OK) {
|
|
|
|
drv->flashUnit = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "flashOffset", HCF_RES_INT, (void *)&drv->flashOffset) != OK) {
|
|
|
|
drv->flashOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "flashSize", HCF_RES_INT, (void *)&drv->flashSize) != OK) {
|
|
|
|
drv->flashSize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "pageSize", HCF_RES_INT, (void *)&drv->pageSize) != OK) {
|
|
|
|
drv->pageSize = 256;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "autoFormat", HCF_RES_INT, (void *)&drv->autoFormat) != OK) {
|
|
|
|
drv->autoFormat = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devResourceGet(pHcf, "mountPoint", HCF_RES_STRING, (void *)&drv->mountPoint) != OK) {
|
|
|
|
snprintf(drv->name, sizeof drv->name, "/lfs%d", pDev->unitNumber);
|
|
|
|
drv->mountPoint = drv->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
vxbNextUnitGet(pDev);
|
|
|
|
return;
|
|
|
|
err:
|
|
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
|
|
hwMemFree((char *)drv);
|
|
|
|
#endif /* _VXBUS_BASIC_HWMEMLIB */
|
|
|
|
pDev->pDrvCtrl = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ lfs handler */
|
|
|
|
LOCAL LFS_FILE_DESC *lfsFuncOpen(lfsIosDrv *dev, const char *name, int flags, int mode)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int is_dir = 0;
|
|
|
|
LFS_FILE_DESC *ptr = NULL;
|
|
|
|
char namep[_PARM_NAME_MAX + 1] = { 0 };
|
|
|
|
int oflags = 0, openFlag;
|
|
|
|
|
|
|
|
if (!name) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S_ISDIR(mode)) {
|
|
|
|
is_dir = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name[0] == '\0') {
|
|
|
|
namep[0] = '/';
|
|
|
|
namep[1] = '.';
|
|
|
|
namep[2] = '\0';
|
|
|
|
is_dir = 1;
|
|
|
|
} else {
|
|
|
|
strncpy(namep, name, _PARM_NAME_MAX + 1);
|
|
|
|
namep[_PARM_NAME_MAX - 1] = EOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (namep[strlen(namep) - 1] == '/') {
|
|
|
|
namep[strlen(namep) - 1] = '\0';
|
|
|
|
is_dir = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = calloc(1, sizeof *ptr);
|
|
|
|
if (!ptr) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr->ctrl = dev->pDrvCtrl;
|
|
|
|
|
|
|
|
if (is_dir) {
|
|
|
|
if ((flags & O_CREAT) == O_CREAT) {
|
|
|
|
lfs_mkdir(&ptr->ctrl->fsh, namep);
|
|
|
|
}
|
|
|
|
err = lfs_dir_open(&ptr->ctrl->fsh, &ptr->u.dir, namep);
|
|
|
|
if (err != LFS_ERR_OK) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ptr->isDir = 1;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
openFlag = flags & (O_RDONLY | O_WRONLY | O_RDWR);
|
|
|
|
|
|
|
|
switch (openFlag) {
|
|
|
|
case O_RDONLY:
|
|
|
|
oflags = LFS_O_RDONLY;
|
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
|
|
|
oflags = LFS_O_WRONLY;
|
|
|
|
break;
|
|
|
|
case O_RDWR:
|
|
|
|
oflags = LFS_O_RDWR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errnoSet(EINVAL);
|
|
|
|
goto end;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & O_CREAT) {
|
|
|
|
oflags |= LFS_O_CREAT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lfs_file_open(&ptr->ctrl->fsh, &ptr->u.file, namep, oflags) == LFS_ERR_OK) {
|
|
|
|
ptr->isDir = 0;
|
|
|
|
return ptr;
|
|
|
|
} else {
|
|
|
|
/* try dir */
|
|
|
|
if (lfs_dir_open(&ptr->ctrl->fsh, &ptr->u.dir, namep) == LFS_ERR_OK) {
|
|
|
|
ptr->isDir = 1;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
if (ptr) {
|
|
|
|
free(ptr);
|
|
|
|
}
|
|
|
|
return (LFS_FILE_DESC *)(ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL int lfsFuncClose(LFS_FILE_DESC *pfd)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = pfd->ctrl;
|
|
|
|
|
|
|
|
if (pfd->isDir) {
|
|
|
|
lfs_dir_close(&pDrvCtrl->fsh, &pfd->u.dir);
|
|
|
|
} else {
|
|
|
|
lfs_file_close(&pDrvCtrl->fsh, &pfd->u.file);
|
|
|
|
}
|
|
|
|
free(pfd);
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL int lfsFuncIoctl(LFS_FILE_DESC *pfd, int cmd, _Vx_ioctl_arg_t arg)
|
|
|
|
{
|
|
|
|
struct stat *stbuf;
|
|
|
|
int ret = OK;
|
|
|
|
const char *name;
|
|
|
|
DIR *dirp;
|
|
|
|
size_t offset;
|
|
|
|
struct lfs_info info;
|
|
|
|
lfsDrvCtrl *pDrvCtrl = pfd->ctrl;
|
|
|
|
|
|
|
|
errnoSet(OK);
|
|
|
|
switch (cmd) {
|
|
|
|
case FIOFSTATGET:
|
|
|
|
stbuf = (struct stat *)(arg);
|
|
|
|
stbuf->st_dev = (u_long)&pDrvCtrl->lfsDrv.devHdr;
|
|
|
|
stbuf->st_nlink = 1;
|
|
|
|
stbuf->st_attrib = 0;
|
|
|
|
stbuf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
|
|
|
if (pfd->isDir) {
|
|
|
|
stbuf->st_size = pDrvCtrl->pageSize;
|
|
|
|
stbuf->st_blocks = 1;
|
|
|
|
stbuf->st_mode |= S_IFDIR;
|
|
|
|
} else {
|
|
|
|
stbuf->st_mode |= S_IFREG;
|
|
|
|
stbuf->st_size = lfs_file_size(&pDrvCtrl->fsh, &pfd->u.file);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FIOREADDIR:
|
|
|
|
if (!pfd->isDir) {
|
|
|
|
errnoSet(EIO);
|
|
|
|
ret = ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dirp = (DIR *)(arg);
|
|
|
|
if (!lfs_dir_read(&pDrvCtrl->fsh, &pfd->u.dir, &info)) { /* return is not TRUE */
|
|
|
|
dirp->dd_eof = TRUE;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dirp->dd_eof = FALSE;
|
|
|
|
dirp->dd_dirent.d_ino = __lfs_driver_node;
|
|
|
|
strncpy(dirp->dd_dirent.d_name, info.name, _PARM_NAME_MAX + 1);
|
|
|
|
dirp->dd_dirent.d_name[_PARM_NAME_MAX - 1] = EOS;
|
|
|
|
break;
|
|
|
|
case FIOSEEK:
|
|
|
|
if (pfd->isDir) {
|
|
|
|
errnoSet(EINVAL);
|
|
|
|
ret = ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
offset = (size_t)arg;
|
|
|
|
lfs_file_seek(&pDrvCtrl->fsh, &pfd->u.file, offset, LFS_SEEK_SET);
|
|
|
|
break;
|
|
|
|
case FIOUNLINK:
|
|
|
|
name = (const char *)arg;
|
|
|
|
ret = lfs_remove(&pDrvCtrl->fsh, name);
|
|
|
|
if (ret != LFS_ERR_OK) {
|
|
|
|
}
|
|
|
|
ret = OK;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("lfs unsupport ioctl: %d\n", cmd);
|
|
|
|
errnoSet(ENOTSUP);
|
|
|
|
ret = ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL ssize_t lfsFuncRead(LFS_FILE_DESC *pfd, char *buffer, size_t maxbytes)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = pfd->ctrl;
|
|
|
|
|
|
|
|
if (pfd->isDir) {
|
|
|
|
printf("read dir\r\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return lfs_file_read(&pDrvCtrl->fsh, &pfd->u.file, buffer, maxbytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL ssize_t lfsFuncWrite(LFS_FILE_DESC *pfd, char *buffer, size_t nbytes)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = pfd->ctrl;
|
|
|
|
|
|
|
|
if (pfd->isDir) {
|
|
|
|
printf("write dir\r\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return lfs_file_write(&pDrvCtrl->fsh, &pfd->u.file, buffer, nbytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL STATUS lfsFuncRemove(lfsIosDrv *dev, char *pPath)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = dev->pDrvCtrl;
|
|
|
|
|
|
|
|
lfs_remove(&pDrvCtrl->fsh, pPath);
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ lfs flash operations */
|
|
|
|
LOCAL int lfsFlashRead(const struct lfs_config *cfg, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
|
|
|
|
{
|
|
|
|
UINT32 pos;
|
|
|
|
lfsDrvCtrl *pDrvCtrl = cfg->context;
|
|
|
|
UINT8 *buffers[2];
|
|
|
|
|
|
|
|
buffers[0] = buffer;
|
|
|
|
buffers[1] = NULL;
|
|
|
|
pos = pDrvCtrl->flashOffset + block * cfg->block_size + off;
|
|
|
|
|
|
|
|
if (pDrvCtrl->mtd->flashOPs.read(pDrvCtrl->mtd, pos, 1, size, buffers, NULL) == OK) {
|
|
|
|
return LFS_ERR_OK;
|
|
|
|
}
|
|
|
|
return LFS_ERR_IO;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL int lfsFlashProg(const struct lfs_config *cfg, lfs_block_t block, lfs_off_t off, const void *buffer,
|
|
|
|
lfs_size_t size)
|
|
|
|
{
|
|
|
|
STATUS r;
|
|
|
|
UINT32 pos;
|
|
|
|
lfsDrvCtrl *pDrvCtrl = cfg->context;
|
|
|
|
UINT8 *buffers[2];
|
|
|
|
|
|
|
|
buffers[0] = (void *)buffer;
|
|
|
|
buffers[1] = NULL;
|
|
|
|
pos = pDrvCtrl->flashOffset + block * cfg->block_size + off;
|
|
|
|
|
|
|
|
r = pDrvCtrl->mtd->flashOPs.write(pDrvCtrl->mtd, pos, 1, size, buffers, NULL);
|
|
|
|
|
|
|
|
return r == OK ? LFS_ERR_OK : LFS_ERR_IO;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL int lfsFlashErase(const struct lfs_config *cfg, lfs_block_t block)
|
|
|
|
{
|
|
|
|
UINT32 pos;
|
|
|
|
lfsDrvCtrl *pDrvCtrl = cfg->context;
|
|
|
|
|
|
|
|
pos = pDrvCtrl->flashOffset + block * cfg->block_size;
|
|
|
|
if (pDrvCtrl->mtd->flashOPs.blkErase(pDrvCtrl->mtd, pos, 1) == OK) {
|
|
|
|
return LFS_ERR_OK;
|
|
|
|
}
|
|
|
|
return LFS_ERR_IO;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL int lfsFlashSync(const struct lfs_config *c)
|
|
|
|
{
|
|
|
|
return LFS_ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LFS_THREADSAFE
|
|
|
|
|
|
|
|
LOCAL int lfsFlashLock(const struct lfs_config *cfg)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = cfg->context;
|
|
|
|
|
|
|
|
semTake(pDrvCtrl->lock, WAIT_FOREVER);
|
|
|
|
|
|
|
|
return LFS_ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL int lfsFlashUnlock(const struct lfs_config *cfg)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = cfg->context;
|
|
|
|
|
|
|
|
semGive(pDrvCtrl->lock);
|
|
|
|
|
|
|
|
return LFS_ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
LOCAL void lfsCfgInit(lfsDrvCtrl *drv, FLASH_CHIP_ID flash)
|
|
|
|
{
|
|
|
|
int buffer_size = flash->uPageSize > 0 ? flash->uPageSize : drv->pageSize;
|
|
|
|
|
|
|
|
memset(&drv->lfsConfig, 0, sizeof drv->lfsConfig);
|
|
|
|
|
|
|
|
drv->lfsConfig.context = drv;
|
|
|
|
drv->lfsConfig.read = lfsFlashRead;
|
|
|
|
drv->lfsConfig.prog = lfsFlashProg;
|
|
|
|
drv->lfsConfig.erase = lfsFlashErase;
|
|
|
|
drv->lfsConfig.sync = lfsFlashSync;
|
|
|
|
|
|
|
|
drv->lfsConfig.read_size = buffer_size;
|
|
|
|
drv->lfsConfig.prog_size = buffer_size;
|
|
|
|
|
|
|
|
drv->lfsConfig.block_size = flash->uEraseSize;
|
|
|
|
drv->lfsConfig.block_count = drv->blkNum;
|
|
|
|
|
|
|
|
drv->lfsConfig.cache_size = buffer_size;
|
|
|
|
drv->lfsConfig.lookahead_size = flash->uEraseSize / 8;
|
|
|
|
|
|
|
|
drv->lfsConfig.block_cycles = 100;
|
|
|
|
#ifdef LFS_THREADSAFE
|
|
|
|
drv->lfsConfig.lock = lfsFlashLock;
|
|
|
|
drv->lfsConfig.unlock = lfsFlashUnlock;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
LOCAL void lfsDevInstInit2(VXB_DEVICE_ID pDev)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = (lfsDrvCtrl *)pDev->pDrvCtrl;
|
|
|
|
|
|
|
|
pDrvCtrl->lock = semBCreate(SEM_Q_FIFO, SEM_FULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL void lfsDevInstConnect(VXB_DEVICE_ID pDev)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl;
|
|
|
|
VXB_DEVICE_ID pFlashDev;
|
|
|
|
FLASH_CHIP_ID (*flashChipInfoGet)(VXB_DEVICE_ID pDev, UINT32 chipId);
|
|
|
|
|
|
|
|
pDrvCtrl = (lfsDrvCtrl *)pDev->pDrvCtrl;
|
|
|
|
|
|
|
|
if (__lfs_driver_node < 0) {
|
|
|
|
/* clang-format off */
|
|
|
|
__lfs_driver_node = iosDrvInstall(
|
|
|
|
(DRV_CREATE_PTR) lfsFuncOpen,
|
|
|
|
(DRV_REMOVE_PTR) lfsFuncRemove,
|
|
|
|
(DRV_OPEN_PTR) lfsFuncOpen,
|
|
|
|
(DRV_CLOSE_PTR) lfsFuncClose,
|
|
|
|
(DRV_READ_PTR) lfsFuncRead,
|
|
|
|
(DRV_WRITE_PTR) lfsFuncWrite,
|
|
|
|
(DRV_IOCTL_PTR) lfsFuncIoctl
|
|
|
|
);
|
|
|
|
/* clang-format on */
|
|
|
|
}
|
|
|
|
|
|
|
|
pFlashDev = vxbInstByNameFind((char *)pDrvCtrl->flashDrvName, pDrvCtrl->flashUnit);
|
|
|
|
if (!pFlashDev) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
semTake(pDrvCtrl->lock, WAIT_FOREVER);
|
|
|
|
flashChipInfoGet = (void *)vxbDevMethodGet(pFlashDev, DEVMETHOD_CALL(vxbFlashChipInfoGet));
|
|
|
|
pDrvCtrl->mtd = flashChipInfoGet(pFlashDev, 0);
|
|
|
|
if (pDrvCtrl->mtd) {
|
|
|
|
if (pDrvCtrl->flashSize <= 0) {
|
|
|
|
pDrvCtrl->flashSize = pDrvCtrl->mtd->uChipSize - pDrvCtrl->flashOffset;
|
|
|
|
}
|
|
|
|
pDrvCtrl->blkNum = pDrvCtrl->flashSize / pDrvCtrl->mtd->uEraseSize;
|
|
|
|
if (__lfs_driver_node > 0) {
|
|
|
|
if (iosDevAdd(&pDrvCtrl->lfsDrv.devHdr, pDrvCtrl->mountPoint, __lfs_driver_node) == OK) {
|
|
|
|
pDrvCtrl->lfsDrv.pDrvCtrl = pDrvCtrl;
|
|
|
|
lfsCfgInit(pDrvCtrl, pDrvCtrl->mtd);
|
|
|
|
} else {
|
|
|
|
pDrvCtrl->mtd = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pDrvCtrl->mtd = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
semGive(pDrvCtrl->lock);
|
|
|
|
if (pDrvCtrl->mtd) {
|
|
|
|
int ret;
|
|
|
|
ret = lfs_mount(&pDrvCtrl->fsh, &pDrvCtrl->lfsConfig);
|
|
|
|
if ((ret != LFS_ERR_OK) && pDrvCtrl->autoFormat) {
|
|
|
|
lfs_format(&pDrvCtrl->fsh, &pDrvCtrl->lfsConfig);
|
|
|
|
lfs_mount(&pDrvCtrl->fsh, &pDrvCtrl->lfsConfig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ lfsMethods */
|
|
|
|
LOCAL void lfsDevShow(VXB_DEVICE_ID pDev, int verbose)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = (lfsDrvCtrl *)pDev->pDrvCtrl;
|
|
|
|
printf(" %s unit %d on %s @ 0x%08x", pDev->pName, pDev->unitNumber, vxbBusTypeString(pDev->busID), pDev);
|
|
|
|
printf(" with busInfo %p\n", pDev->u.pSubordinateBus);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
printf(" mountPoint: %s\n", pDrvCtrl->mountPoint);
|
|
|
|
printf(" flashName: %s\n", pDrvCtrl->flashDrvName);
|
|
|
|
printf(" mtd: %p\n", pDrvCtrl->mtd);
|
|
|
|
printf(" read_size: %d\n", pDrvCtrl->lfsConfig.read_size);
|
|
|
|
printf(" prog_size: %d\n", pDrvCtrl->lfsConfig.prog_size);
|
|
|
|
printf(" block_size: %d\n", pDrvCtrl->lfsConfig.block_size);
|
|
|
|
printf(" flashOffset: 0x%x\n", pDrvCtrl->flashOffset);
|
|
|
|
printf(" partSize: 0x%x\n", pDrvCtrl->flashSize);
|
|
|
|
printf(" blkNum: 0x%x\n", pDrvCtrl->blkNum);
|
|
|
|
if (pDrvCtrl->mtd) {
|
|
|
|
printf(" flashChip: %s\n", pDrvCtrl->mtd->chipName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL STATUS lfsDevInstUnlink(VXB_DEVICE_ID pDev, void *unused)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = (lfsDrvCtrl *)pDev->pDrvCtrl;
|
|
|
|
|
|
|
|
/* Check for vaild parameter */
|
|
|
|
VXB_ASSERT_NONNULL_V(pDev);
|
|
|
|
|
|
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
|
|
hwMemFree((char *)pDrvCtrl);
|
|
|
|
#endif /* _VXBUS_BASIC_HWMEMLIB */
|
|
|
|
pDev->pDrvCtrl = NULL;
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
LOCAL lfsDrvCtrl * getLfsLowHandle(int unit)
|
|
|
|
{
|
|
|
|
VXB_DEVICE_ID pDev;
|
|
|
|
lfsDrvCtrl *pDrvCtrl = NULL;
|
|
|
|
|
|
|
|
pDev = vxbInstByNameFind(LFS_NAME, unit);
|
|
|
|
if (pDev == NULL) {
|
|
|
|
printf("Can't find lfs%d\n", unit);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pDrvCtrl = (lfsDrvCtrl *)pDev->pDrvCtrl;
|
|
|
|
if (!pDrvCtrl->mtd) {
|
|
|
|
printf("can't find spiFlash\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pDrvCtrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATUS lfsFormat(int unit)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = getLfsLowHandle(unit);
|
|
|
|
|
|
|
|
if (pDrvCtrl == NULL) {
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lfs_format(&pDrvCtrl->fsh, &pDrvCtrl->lfsConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATUS lfsMount(int unit)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = getLfsLowHandle(unit);
|
|
|
|
|
|
|
|
if (pDrvCtrl == NULL) {
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lfs_mount(&pDrvCtrl->fsh, &pDrvCtrl->lfsConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
int lfsLowRawWrite(unsigned long offset, const char *buffer, int size)
|
|
|
|
{
|
|
|
|
lfsDrvCtrl *pDrvCtrl = getLfsLowHandle(0);
|
|
|
|
int nblocks, block_size;
|
|
|
|
STATUS ok = OK;
|
|
|
|
if (pDrvCtrl == NULL) {
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
semTake(pDrvCtrl->lock, WAIT_FOREVER);
|
|
|
|
|
|
|
|
block_size = pDrvCtrl->mtd->uEraseSize;
|
|
|
|
if (block_size <= 0) {
|
|
|
|
block_size = 0x10000;
|
|
|
|
}
|
|
|
|
nblocks = (size + block_size - 1) / block_size;
|
|
|
|
if (pDrvCtrl->mtd->flashOPs.blkErase) {
|
|
|
|
pDrvCtrl->mtd->flashOPs.blkErase(pDrvCtrl->mtd, offset, nblocks);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pDrvCtrl->mtd->flashOPs.write) {
|
|
|
|
ok = pDrvCtrl->mtd->flashOPs.write(pDrvCtrl->mtd, offset, 1, size, (UINT8 **)&buffer, NULL);
|
|
|
|
}
|
|
|
|
semGive(pDrvCtrl->lock);
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|