/** * find first free page from 'pageFrom' * \param[in] dev uffs device * \param[in] bc block info * \param[in] pageFrom search from this page * \return return first free page number from 'pageFrom' * \retval UFFS_INVALID_PAGE no free page found * \retval >=0 the first free page number */ u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom) { u16 i; for (i = pageFrom; i < dev->attr->pages_per_block; i++) { uffs_BlockInfoLoad(dev, bc, i); if (uffs_IsPageErased(dev, bc, i) == U_TRUE) return i; } return UFFS_INVALID_PAGE; //free page not found }
/** * get free pages number * \param[in] dev uffs device * \param[in] bc block info */ int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc) { int count = 0; int i; for (i = dev->attr->pages_per_block - 1; i >= 0; i--) { uffs_BlockInfoLoad(dev, bc, i); if (uffs_IsPageErased(dev, bc, (u16)i) == U_TRUE) { count++; } else break; } return count; }
/** * get free pages number * \param[in] dev uffs device * \param[in] bc block info */ int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc) { int count = 0; int i; // search from the last page ... to first page for (i = dev->attr->pages_per_block - 1; i >= 0; i--) { uffs_BlockInfoLoad(dev, bc, i); if (uffs_IsPageErased(dev, bc, (u16)i) == U_TRUE) { count++; } else { if (TAG_IS_GOOD(GET_TAG(bc, i))) // it won't be any free page if we see a good tag. break; } } return count; }
static URET _BuildTreeStepOne(uffs_Device *dev) { int block_lt; uffs_BlockInfo *bc = NULL; TreeNode *node; struct uffs_TreeSt *tree; uffs_Pool *pool; struct uffs_MiniHeaderSt header; URET ret = U_SUCC; struct BlockTypeStatSt st = {0, 0, 0}; tree = &(dev->tree); pool = TPOOL(dev); tree->bad = NULL; tree->bad_count = 0; tree->erased = NULL; tree->erased_tail = NULL; tree->erased_count = 0; uffs_Perror(UFFS_MSG_NOISY, "build tree step one"); // printf("s:%d e:%d\n", dev->par.start, dev->par.end); for (block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) { bc = uffs_BlockInfoGet(dev, block_lt); if (bc == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "step one:fail to get block info"); ret = U_FAIL; break; } node = (TreeNode *)uffs_PoolGet(pool); if (node == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "insufficient tree node!"); ret = U_FAIL; break; } // Need to check bad block at first ! if (uffs_FlashIsBadBlock(dev, block_lt) == U_TRUE) { node->u.list.block = block_lt; uffs_TreeInsertToBadBlockList(dev, node); uffs_Perror(UFFS_MSG_NORMAL, "found bad block %d", block_lt); } else if (uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0 // page 0 tag shows it's an erased block, we need to check the mini header status to make sure it is clean. if (uffs_LoadMiniHeader(dev, block_lt, 0, &header) == U_FAIL) { uffs_Perror(UFFS_MSG_SERIOUS, "I/O error when reading mini header !" "block %d page %d", block_lt, 0); ret = U_FAIL; break; } if (header.status != 0xFF) { // page 0 tag is clean but page data is dirty ??? // this block should be erased immediately ! uffs_FlashEraseBlock(dev, block_lt); } node->u.list.block = block_lt; if (HAVE_BADBLOCK(dev)) { uffs_Perror(UFFS_MSG_NORMAL, "New bad block (%d) discovered.", block_lt); uffs_BadBlockProcess(dev, node); } else { // page 0 is clean does not means all pages in this block are clean, // need to check this block later before use it. uffs_TreeInsertToErasedListTailEx(dev, node, 1); } } else { // this block have valid data page(s). ret = _ScanAndFixUnCleanPage(dev, bc); if (ret == U_FAIL) break; ret = _BuildValidTreeNode(dev, node, bc, &st); if (ret == U_FAIL) break; } uffs_BlockInfoPut(dev, bc); } //end of for if(ret == U_FAIL) uffs_BlockInfoPut(dev, bc); uffs_Perror(UFFS_MSG_NORMAL, "DIR %d, FILE %d, DATA %d", st.dir, st.file, st.data); return ret; }