📄 uffs_buf.c~
字号:
block = node->u.file.block;
break;
case UFFS_TYPE_DATA:
block = node->u.data.block;
break;
default:
uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown type.\n");
return U_FAIL;
}
bc = uffs_GetBlockInfo(dev, block);
if(bc == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"get block info fail.\n");
return U_FAIL;
}
uffs_LoadBlockInfo(dev, bc, UFFS_ALL_PAGES);
n = uffs_GetFreePagesCount(dev, bc);
if(n >= dev->buf.dirtyCount && !force_block_recover) {
//The free pages are enough for the dirty pages
ret = _BufFlush_Exist_With_Enough_FreePage(dev, bc, n);
}
else {
ret = _BufFlush_Exist_With_BlockCover(dev, node, bc);
}
uffs_PutBlockInfo(dev, bc);
}
return ret;
}
/**
* flush buffers to flash
* \param[in] dev uffs device
*/
URET uffs_BufFlush(struct uffs_DeviceSt *dev)
{
return _BufFlush(dev, U_FALSE);
}
/**
* flush buffers to flash
* \param[in] dev uffs device
* \param[in] force_block_recover #U_TRUE: force a block recover even there are enough free pages
*/
URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover)
{
return _BufFlush(dev, force_block_recover);
}
/**
* \brief get a page buffer
* \param[in] dev uffs device
* \param[in] father father serial num
* \param[in] serial serial num
* \param[in] pageID pageID
* \return return the buffer found in buffer list, if not found, return NULL.
*/
uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 father, u16 serial, u16 pageID)
{
uffs_Buf *p;
//first, check whether the buffer exist in buf list ?
p = uffs_BufFind(dev, father, serial, pageID);
if(p) {
p->refCount++;
_MoveNodeToHead(dev, p);
}
return p;
}
/**
* New generate a buffer
*/
uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 father, u16 serial, u16 pageID)
{
uffs_Buf *buf;
buf = uffs_BufGet(dev, father, serial, pageID);
if (buf) {
if (buf->refCount > 1) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"When create new buf, an exist buffer has ref count %d, possibly bug!\n", buf->refCount);
}
else {
buf->dataLen = 0;
}
_MoveNodeToHead(dev, buf);
return buf;
}
buf = _FindFreeBuf(dev);
if(buf == NULL) {
uffs_BufFlush(dev);
buf = _FindFreeBuf(dev);
if (buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"no free page buf!\n");
return NULL;
}
}
buf->mark = UFFS_BUF_EMPTY;
buf->type = type;
buf->father = father;
buf->serial = serial;
buf->pageID = pageID;
buf->dataLen = 0;
buf->refCount++;
memset(buf->data, 0xff, dev->com.pgSize);
_MoveNodeToHead(dev, buf);
return buf;
}
/**
* get a page buffer
* \param[in] dev uffs device
* \param[in] type dir, file or data ?
* \param[in] node node on the tree
* \param[in] pageID pageID
* \return return the bufer if found in buffer list, if not found in
* buffer list, it will get a free buffer, and load data from flash.
* return NULL if not free buffer.
*/
uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 pageID)
{
uffs_Buf *buf;
u16 father, serial, block, page;
uffs_blockInfo *bc;
switch(type) {
case UFFS_TYPE_DIR:
father = node->u.dir.father;
serial = node->u.dir.serial;
block = node->u.dir.block;
break;
case UFFS_TYPE_FILE:
father = node->u.file.father;
serial = node->u.file.serial;
block = node->u.file.block;
break;
case UFFS_TYPE_DATA:
father = node->u.data.father;
serial = node->u.data.serial;
block = node->u.data.block;
break;
default:
uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown type");
return NULL;
}
buf = uffs_BufFind(dev, father, serial, pageID);
if(buf) {
buf->refCount++;
return buf;
}
buf = _FindFreeBuf(dev);
if(buf == NULL) {
uffs_BufFlush(dev);
buf = _FindFreeBuf(dev);
if (buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"no free page buf!\n");
return NULL;
}
}
bc = uffs_GetBlockInfo(dev, block);
if (bc == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't get block info!\n");
return NULL;
}
page = uffs_FindPageInBlockWithPageId(dev, bc, pageID);
if(page == UFFS_INVALID_PAGE) {
uffs_PutBlockInfo(dev, bc);
uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find right page ?\n");
return NULL;
}
page = uffs_FindBestPageInBlock(dev, bc, page);
uffs_PutBlockInfo(dev, bc);
buf->mark = UFFS_BUF_EMPTY;
buf->type = type;
buf->father = father;
buf->serial = serial;
buf->pageID = pageID;
if (uffs_LoadPhiDataToBuf(dev, buf, block, page) == U_FAIL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't load page from flash !\n");
return NULL;
}
buf->dataLen = bc->spares[page].tag.dataLength;
buf->mark = UFFS_BUF_VALID;
buf->refCount++;
_MoveNodeToHead(dev, buf);
return buf;
}
/**
* \brief Put back a page buffer, make reference count decrease by one
* \param[in] dev uffs device
* \param[in] buf buffer to be put back
*/
URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf)
{
dev = dev;
if(buf == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, PFX "Can't put an NULL buffer!\n");
return U_FAIL;
}
if(buf->refCount == 0) {
uffs_Perror(UFFS_ERR_NORMAL, PFX "Putting an unused page buffer ? \n");
return U_FAIL;
}
buf->refCount--;
return U_SUCC;
}
/**
* \brief clone from an exist buffer.
allocate memory for new buffer, and copy data from original buffer if
original buffer is not NULL.
* \param[in] dev uffs device
* \param[in] buf page buffer to be clone from. if NULL presented here, data copy will not be processed
* \return return the cloned page buffer, all data copied from source
* \note the cloned buffer is not linked in page buffer list in uffs device,
* so you should use #uffs_BufFreeClone instead of #uffs_BufPut when you put back or release buffer
*/
uffs_Buf * uffs_BufClone(uffs_Device *dev, uffs_Buf *buf)
{
uffs_Buf *p;
p = _FindFreeBuf(dev);
if(p == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"no enough free pages for clone!\n");
return NULL;
}
_BreakFromBufList(dev, p);
if(buf) {
p->father = buf->father;
p->type = buf->type;
p->serial = buf->serial;
p->pageID = buf->pageID;
p->dataLen = buf->dataLen;
//athough the valid data length is .dataLen,
//but we still need copy the whole buffer, include ecc
memcpy(p->data, buf->data, dev->com.pgSize);
}
p->next = p->prev = NULL; //because the cloned one is not linked to device buffer
p->nextDirty = p->prevDirty = NULL;
p->refCount = CLONE_BUF_MARK; //CLONE_BUF_MARK indicates that this is an cloned buffer
return p;
}
/**
* \brief release cloned buffer
* \param[in] dev uffs device
* \param[in] buf cloned buffer
*/
void uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf)
{
dev = dev; //make compiler happy
if(!buf) return;
if(buf->refCount != CLONE_BUF_MARK) {
/* a cloned buffer must have a refCount of CLONE_BUF_MARK */
uffs_Perror(UFFS_ERR_SERIOUS, PFX "Try to release a non-cloned page buffer ?\n");
return;
}
buf->refCount = 0;
buf->mark = UFFS_BUF_EMPTY;
_LinkToBufListTail(dev, buf);
}
UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev)
{
uffs_Buf *buf = dev->buf.bufHead;
while(buf) {
if(buf->refCount != 0) return U_FALSE;
buf = buf->next;
}
return U_TRUE;
}
UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev)
{
uffs_Buf *buf = dev->buf.bufHead;
while(buf) {
if(buf->mark != UFFS_BUF_EMPTY) return U_FALSE;
buf = buf->next;
}
return U_TRUE;
}
URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev)
{
uffs_Buf *buf = dev->buf.bufHead;
while(buf) {
buf->mark = UFFS_BUF_EMPTY;
buf = buf->next;
}
return U_SUCC;
}
void uffs_BufIncRef(uffs_Buf *buf)
{
buf->refCount++;
}
void uffs_BufDecRef(uffs_Buf *buf)
{
if(buf->refCount > 0) buf->refCount--;
}
void uffs_BufSetMark(uffs_Buf *buf, int mark)
{
buf->mark = mark;
}
static UBOOL _IsBufInDirtyList(struct uffs_DeviceSt *dev, uffs_Buf *buf)
{
uffs_Buf *p = dev->buf.dirty;
while(p) {
if(p == buf) return U_TRUE;
p = p->nextDirty;
}
return U_FALSE;
}
URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
{
uffs_Buf *dirty;
UBOOL inDirtyList = U_FALSE;
if(ofs + len > dev->com.pgDataSize) {
uffs_Perror(UFFS_ERR_SERIOUS, PFX"data length out of range! %d+%d\n", ofs, len);
return U_FAIL;
}
if(dev->buf.dirtyCount > 0) {
dirty = dev->buf.dirty;
inDirtyList = _IsBufInDirtyList(dev, buf);
if(inDirtyList == U_FALSE) {
//new dirty buffer...
if(dirty->father != buf->father ||
dirty->serial != buf->serial ||
dirty->type != buf->type) {
//new buf is in different block, flush buffer right now
if(uffs_BufFlush(dev) != U_SUCC) return U_FAIL;
}
}
}
memcpy(buf->data + ofs, data, len);
if(ofs + len > buf->dataLen) buf->dataLen = ofs + len;
if(inDirtyList == U_FALSE) {
_LinkToDirtyList(dev, buf);
}
if(dev->buf.dirtyCount >= dev->buf.maxDirtyBuf) {
if(uffs_BufFlush(dev) != U_SUCC) {
return U_FAIL;
}
}
return U_SUCC;
}
URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
{
u32 readSize;
u32 pgDataSize = dev->com.pgDataSize;
readSize = (ofs >= pgDataSize ? 0 : (ofs + len >= pgDataSize ? pgDataSize - ofs : len));
if(readSize > 0) memcpy(data, buf->data + ofs, readSize);
return U_SUCC;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -