static URET femu_hw_auto_ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc, uffs_TagStore *ts, u8 *ecc_store) { uffs_FileEmu *emu; int abs_page; struct uffs_StorageAttrSt *attr = dev->attr; unsigned char status; int spare_len; u8 spare[PAGE_SPARE_SIZE]; u8 ecc_buf[RS_ECC_SIZE]; int ret = UFFS_FLASH_IO_ERR; emu = (uffs_FileEmu *)(dev->attr->_private); if (!emu || !(emu->fp)) { goto ext; } abs_page = attr->pages_per_block * block + page; // now load full page to serial data buffer ret = load_sdata(dev, block, page); if (ret != UFFS_FLASH_NO_ERR) goto ext; start_sdata_access(); dev->st.io_read += PAGE_FULL_SIZE; dev->st.page_read_count++; dev->st.spare_read_count++; if (data || ts) { if (data && data_len > 0) { if (data_len > attr->page_data_size) goto ext; drain_sdata(data, data_len); } if (ts) { if (g_sdata_buf_pointer < attr->page_data_size) drain_sdata(NULL, attr->page_data_size - g_sdata_buf_pointer); drain_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE); // unload ts from spare uffs_FlashUnloadSpare(dev, spare, ts, NULL); } } else { // read bad block mark drain_sdata(NULL, attr->page_data_size + attr->block_status_offs - 1); drain_sdata(&status, 1); ret = (status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK); } ext: return ret; }
static int femu_hw_auto_WritePageWithLayout(uffs_Device *dev, u32 block, u32 page, const u8 *data, int data_len, const u8 *ecc, const uffs_TagStore *ts) { int abs_page; uffs_FileEmu *emu; struct uffs_StorageAttrSt *attr = dev->attr; u8 spare[PAGE_SPARE_SIZE]; int ret = UFFS_FLASH_IO_ERR; emu = (uffs_FileEmu *)(dev->attr->_private); if (!emu || !(emu->fp)) { goto err; } abs_page = attr->pages_per_block * block + page; start_sdata_access(); dev->st.page_write_count++; dev->st.spare_write_count++; dev->st.io_write += PAGE_FULL_SIZE; if (data || ts) { // normal page write if (data && data_len > 0) { if (data_len > attr->page_data_size) goto err; emu->em_monitor_page[abs_page]++; if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) { MSGLN("Warrning: block %d page %d exceed it's maximum write time!", block, page); goto err; } // Copy data to serial data buffer feed_sdata(data, data_len); // Pad the rest data as 0xFF feed_sdata_constant(0xFF, attr->page_data_size - data_len); } else { // We still need to feed data to serial data buffer to make MLC controller happy // The current UFFS won't write ts only, so we'll never run to here. feed_sdata_constant(0xFF, attr->page_data_size); } if (ts) { emu->em_monitor_spare[abs_page]++; if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) { MSGLN("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page); goto err; } memset(spare, 0xFF, sizeof(spare)); uffs_FlashMakeSpare(dev, ts, NULL, spare); // do not pack ECC, as MLC controller will // automatically write RS-ECC to the latest 10 bytes. // feed spare data to serial data buffer feed_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE); } } else { // mark bad block // feed data to serial data buffer to make MLC controller happy feed_sdata_constant(0xFF, attr->page_data_size); memset(spare, 0xFF, sizeof(spare)); spare[attr->block_status_offs] = 0; // feed spare data to serial data buffer feed_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE); dev->st.io_write++; } // now, program serial data buffer to NAND flash ret = program_sdata(dev, block, page); fflush(emu->fp); return ret; err: fflush(emu->fp); return ret; }