/** * @file fee.c * * Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. * * Description: * * Revision History: * ----------------- */ #include #include #include #include #include #include #include #include /* FEE BUFF */ #define FEE_BUFF_SIZE ((FEE_RECORD_BUFF_SIZE) * (FEE_BUFF_MAX)) static uint8_t record_buff[FEE_BUFF_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE) = {0}; //#define FEE_WRITE_CHECK 1 #ifdef FEE_WRITE_CHECK #define FEE_WRITE_CHECK_SIZE 0x200 static uint8_t fee_write_check_buff[FEE_WRITE_CHECK_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE) = {0}; #endif static int fee_disk_read(struct fee_dev *fee_dev, disk_addr_t addr, uint8_t *dst, disk_size_t size) { struct disk_dev_info *disk_dev = fee_dev->disk_dev; if (!IS_ALIGNED(dst, disk_dev->mem_align_size)) { ssdk_printf(SSDK_CRIT, "fee_disk_read dst not aligned to disk_mem_align_size\n"); return -1; } if ((!IS_ALIGNED(addr, disk_dev->access_size)) || (!IS_ALIGNED(size, disk_dev->access_size))) { ssdk_printf(SSDK_CRIT, "fee_disk_read addr or size not aligned to disk_access_size\n"); return -1; } return disk_dev->disk_read(disk_dev->disk_dev, dst, addr, size); } static int fee_disk_write(struct fee_dev *fee_dev, disk_addr_t addr, const uint8_t *src, disk_size_t size) { struct disk_dev_info *disk_dev = fee_dev->disk_dev; if (!IS_ALIGNED(src, disk_dev->mem_align_size)) { ssdk_printf(SSDK_CRIT, "fee_disk_write src not aligned to disk_mem_align_size\n"); return -1; } if ((!IS_ALIGNED(addr, disk_dev->access_size)) || (!IS_ALIGNED(size, disk_dev->access_size))) { ssdk_printf(SSDK_CRIT, "fee_disk_write addr or size not aligned to disk_access_size\n"); return -1; } #ifdef FEE_WRITE_CHECK disk_size_t offset = 0; disk_size_t rlen = 0; uint8_t *check_buff = fee_write_check_buff; int ret = 0; ret = disk_dev->disk_write(disk_dev->disk_dev, src, addr, size); if(ret) { ssdk_printf(SSDK_CRIT, "fee_disk_write write error, addr:%llx, size:%llx\n", addr, size); return ret; } while(offset < size) { rlen = MIN(FEE_WRITE_CHECK_SIZE, size - offset); memset(check_buff, 0x0, rlen); ret = disk_dev->disk_read(disk_dev->disk_dev, check_buff, addr + offset, rlen); if(ret) { ssdk_printf(SSDK_CRIT, "fee_disk_write read error, addr:%llx, size:%llx\n", addr + offset, rlen); return ret; } if(memcmp(check_buff, src + offset, rlen)) { ssdk_printf(SSDK_CRIT, "*****************write data addr:%llx, size:%llx********************\n", addr + offset, rlen); hexdump8_ex(src + offset, rlen, (uint64_t)((addr_t)src + offset)); ssdk_printf(SSDK_CRIT, "*****************read data addr:%llx, size:%llx********************\n", addr + offset, rlen); hexdump8_ex(check_buff, rlen, (uint64_t)((addr_t)check_buff)); } offset += rlen; } return 0; #else return disk_dev->disk_write(disk_dev->disk_dev, src, addr, size); #endif } static int fee_disk_erase(struct fee_dev *fee_dev, disk_addr_t addr, disk_size_t size) { struct disk_dev_info *disk_dev = fee_dev->disk_dev; if ((!IS_ALIGNED(addr, disk_dev->sector_size)) || (!IS_ALIGNED(size, disk_dev->sector_size))) { ssdk_printf(SSDK_CRIT, "fee_disk_erase addr or size not aligned to disk_sector_size\n"); return -1; } return disk_dev->disk_erase(disk_dev->disk_dev, addr, size); } /* get sector_size record info based on sector_index */ static int fee_get_sector(struct fee_dev *fee_dev, uint16_t page_number, uint16_t sector_index, uint8_t *sector) { return fee_disk_read(fee_dev, fee_dev->page_info[page_number].page_addr + (sector_index * fee_dev->record_buff_size), sector, fee_dev->record_buff_size); } /* configure page_status based on page_number */ static int fee_set_page_status(struct fee_dev *fee_dev, uint16_t page_number, fee_page_status_t page_status) { fee_dev->page_info[page_number].page_status = page_status; return fee_disk_write(fee_dev, fee_dev->page_info[page_number].page_addr, (uint8_t *)&fee_dev->page_info[page_number].page_status, sizeof(fee_page_status_t)); } /* get page_status based on page_number */ static int fee_get_page_status(struct fee_dev *fee_dev, uint16_t page_number, fee_page_status_t *page_status) { if (fee_disk_read(fee_dev, fee_dev->page_info[page_number].page_addr, (uint8_t *)&fee_dev->page_info[page_number].page_status, sizeof(fee_page_status_t))) return -1; *page_status = fee_dev->page_info[page_number].page_status; return 0; } /* erases page based on page_number */ static int fee_erase_page(struct fee_dev *fee_dev, uint16_t page_number) { return fee_disk_erase(fee_dev, fee_dev->page_info[page_number].page_addr, fee_dev->page_info[page_number].page_size); } /* displays complete page information based on page_number */ __UNUSED static int fee_page_dump(struct fee_dev *fee_dev, uint16_t page_number) { int ret = 0; for (int i = 0; i < fee_dev->page_info[page_number].page_buff_num; i++) { if (fee_get_sector(fee_dev, page_number, i, (uint8_t *)fee_dev->record_data_buff)) return -1; ssdk_printf(SSDK_INFO, "***************Page:%d sector:%d dump*******************\n", page_number, i); hexdump8_ex(fee_dev->record_data_buff, fee_dev->record_buff_size, (uint64_t)((addr_t)fee_dev->record_data_buff)); } return ret; } /* TODO:set/get block addr mask */ __UNUSED static int fee_block_addr_set(struct fee_dev *fee_dev, uint16_t page_number, uint16_t block_number, uint16_t block_length) { int ret = 0; return ret; } __UNUSED static int fee_block_addr_get(struct fee_dev *fee_dev, uint16_t page_number, uint16_t block_number, uint32_t *block_addr) { int ret = 0; return ret; } /* set record_status based on page_number and record_index */ static int fee_set_record_status(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_index_offset, fee_record_status_t record_status) { disk_addr_t addr = fee_dev->page_info[page_number].page_addr + fee_dev->page_info[page_number].page_size; addr -= (record_index_offset + 1) * sizeof(struct fee_record_info); fee_dev->record_info.record_status = record_status; return fee_disk_write(fee_dev, addr, (uint8_t *)&fee_dev->record_info.record_status, sizeof(fee_record_status_t)); } /* set record_info based on page_number and record_index */ static int fee_set_record_info(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_index_offset, struct fee_record_info *record_info) { disk_addr_t addr = fee_dev->page_info[page_number].page_addr + fee_dev->page_info[page_number].page_size; addr -= (record_index_offset + 1) * sizeof(struct fee_record_info); return fee_disk_write(fee_dev, addr, (uint8_t *)record_info, sizeof(struct fee_record_info)); } /* get record_data_offset based on page_number and record_index_offset */ static int fee_get_record_data_offset(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_index_offset, disk_size_t *record_data_offset) { int ret = 0; uint32_t record_data_tmp = 0; struct disk_dev_info *disk_dev = fee_dev->disk_dev; struct fee_record_info *record_info = (struct fee_record_info *) fee_dev->record_data_offset_buff; uint32_t sector_num = DIV_ROUND_UP(record_index_offset, fee_dev->record_info_num); uint32_t sector_index = fee_dev->page_info[page_number].page_buff_num - sector_num; uint32_t record_num = 0, record_index = 0; for (int i = sector_index; i < sector_index + sector_num; i++) { ret = fee_get_sector(fee_dev, page_number, i, (uint8_t *)record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i); return -1; } if ((!IS_ALIGNED(record_index_offset, fee_dev->record_info_num)) && (i == sector_index)) record_num = record_index_offset % fee_dev->record_info_num; else record_num = fee_dev->record_info_num; record_index = fee_dev->record_info_num - record_num; for (int j = record_index; j < record_index + record_num; j++) { ssdk_printf(SSDK_INFO, "sector_index:%d record_index:%d \n", i, j); record_data_tmp += ROUNDUP(record_info[j].record_len, disk_dev->access_size); } } *record_data_offset = record_data_tmp; return ret; } /* write record data based on page_number and record_data_offset */ static int fee_write_record_data(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_data_offset, const uint8_t *data_buffer, uint16_t length) { /* Address offset, start address + page information + block addr + used data offset */ disk_addr_t addr = fee_dev->page_info[page_number].page_addr + FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset; uint16_t rlen = 0; uint8_t *buff = NULL; struct disk_dev_info *disk_dev = fee_dev->disk_dev; while (length) { /* length smaller than disk_access_size,added to disk_access_size */ if (length < disk_dev->access_size) { buff = fee_dev->record_data_buff; rlen = ROUNDUP(length, disk_dev->access_size); memset(buff, 0xff, rlen); memcpy(buff, data_buffer, MIN(rlen, length)); } else { /* mem address misaligned, data copy */ if (IS_ALIGNED(data_buffer, disk_dev->mem_align_size)) { buff = (uint8_t *)data_buffer; rlen = ROUNDDOWN(length, disk_dev->access_size); } else { buff = fee_dev->record_data_buff; rlen = MIN(ROUNDDOWN(length, disk_dev->access_size), fee_dev->record_buff_size); memcpy(buff, data_buffer, rlen); } } if (fee_disk_write(fee_dev, addr, buff, rlen)) { ssdk_printf(SSDK_CRIT, "fee_write_record_data page_number %d record_data_offset %lld failure\n", page_number, record_data_offset); return -1; } data_buffer += MIN(rlen, length); addr += MIN(rlen, length); length -= MIN(rlen, length); } return 0; } /* read record data based on page_number and record_data_offset */ static int fee_read_record_data(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_data_offset, const uint8_t *data_buffer, uint16_t length) { /* Address offset, start address + page information + used data offset */ disk_addr_t addr = fee_dev->page_info[page_number].page_addr + FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset; uint16_t rlen = 0; uint8_t *buff = NULL; struct disk_dev_info *disk_dev = fee_dev->disk_dev; while (length) { if (length < disk_dev->access_size) { buff = fee_dev->record_data_buff; rlen = ROUNDUP(length, disk_dev->access_size); } else { if (IS_ALIGNED(data_buffer, disk_dev->mem_align_size)) { buff = (uint8_t *)data_buffer; rlen = ROUNDDOWN(length, disk_dev->access_size); } else { buff = fee_dev->record_data_buff; rlen = MIN(ROUNDDOWN(length, disk_dev->access_size), fee_dev->record_buff_size); } } if (fee_disk_read(fee_dev, addr, buff, rlen)) { ssdk_printf(SSDK_CRIT, "fee_read_record_data page_number %d record_data_offset %lld failure\n", page_number, record_data_offset); return -1; } if (buff != data_buffer) { memcpy((void *)data_buffer, buff, MIN(rlen, length)); } data_buffer += MIN(rlen, length); addr += MIN(rlen, length); length -= MIN(rlen, length); } return 0; } /* Based on page_number, write record */ static int fee_write_record(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_index_offset, uint16_t block_number, disk_size_t record_data_offset, const uint8_t *data_buffer, uint16_t length) { int ret = 0; ssdk_printf(SSDK_INFO, "fee_write_record page_number:%d block_number:%x record_index_offset:%lld record_data_offset:%llx length:%x data_buffer:%x~%x\n", page_number, block_number, record_index_offset, record_data_offset, length, *data_buffer, *(data_buffer + length - 1)); /* Configuring record Information */ struct fee_record_info *record_info = (struct fee_record_info *)&fee_dev->record_info; record_info->record_status = FEE_RECORD_INVALID; record_info->record_num = block_number; record_info->record_len = length; ret = fee_set_record_info(fee_dev, page_number, record_index_offset, record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee_block_write set_record_info block_number %d failure\n", block_number); return -1; } /* Write record data */ ret = fee_write_record_data(fee_dev, page_number, record_data_offset, data_buffer, length); if (ret) { ssdk_printf(SSDK_CRIT, "fee_block_write set_record_data block_number %d failure\n", block_number); return -1; } /* Configure record valid */ ret = fee_set_record_status(fee_dev, page_number, record_index_offset, FEE_RECORD_VALID); if (ret) { ssdk_printf(SSDK_CRIT, "fee_block_write set_record_info FEE_RECORD_VALID status block_number %d failure\n", block_number); return -1; } return ret; } /* set the block address mask block_number:The starting blocks block_length:Block number */ static int fee_addr_mask_set(uint8_t *addr, uint16_t block_number, uint16_t block_length) { int ret = 0; uint32_t addr_mask = 0; uint32_t addr_index = 0; uint32_t left_offset = 0; uint32_t rlen = 0; ssdk_printf(SSDK_INFO, "fee_addr_mask_set block_number %d block_length %d\n", block_number, block_length); while (block_length) { if (!IS_ALIGNED(block_number, FEE_CHAR_BIT)) { left_offset = block_number - ROUNDDOWN(block_number, FEE_CHAR_BIT); rlen = MIN(block_length, FEE_CHAR_BIT - left_offset); addr_mask = ((0x1 << rlen) - 1) << left_offset; addr_index = ROUNDDOWN(block_number, FEE_CHAR_BIT) / FEE_CHAR_BIT; addr[addr_index] |= addr_mask; ssdk_printf(SSDK_INFO, "fee_addr_mask_set block_number not aligned part addr_index %d addr_mask %x\n", addr_index, addr_mask); block_number += rlen; block_length -= rlen; } else if (block_length >= FEE_CHAR_BIT) { rlen = ROUNDDOWN(block_length, FEE_CHAR_BIT); addr_index = block_number / FEE_CHAR_BIT; memset(addr + addr_index, 0xff, rlen / FEE_CHAR_BIT); ssdk_printf(SSDK_INFO, "fee_addr_mask_set addr_index %d\n", addr_index); block_number += rlen; block_length -= rlen; } else { rlen = block_length; addr_index = block_number / FEE_CHAR_BIT; addr_mask = (0x1 << rlen) - 1; addr[addr_index] |= addr_mask; ssdk_printf(SSDK_INFO, "fee_addr_mask_set block_length not aligned part addr_index %d addr_mask %x\n", addr_index, addr_mask); block_number += rlen; block_length -= rlen; } } return ret; } /* clear the block address mask block_number:The starting blocks block_length:Block number */ static int fee_addr_mask_clear(uint8_t *addr, uint16_t block_number, uint16_t block_length) { int ret = 0; uint32_t addr_mask = 0; uint32_t addr_index = 0; uint32_t left_offset = 0; uint32_t rlen = 0; ssdk_printf(SSDK_INFO, "fee_addr_mask_clear block_number %d block_length %d\n", block_number, block_length); while (block_length) { if (!IS_ALIGNED(block_number, FEE_CHAR_BIT)) { left_offset = block_number - ROUNDDOWN(block_number, FEE_CHAR_BIT); rlen = MIN(block_length, FEE_CHAR_BIT - left_offset); addr_mask = ~(((0x1 << rlen) - 1) << left_offset); addr_index = ROUNDDOWN(block_number, FEE_CHAR_BIT) / FEE_CHAR_BIT; addr[addr_index] &= addr_mask; ssdk_printf(SSDK_INFO, "fee_addr_mask_clear block_number not aligned part addr_index %d addr_mask %x\n", addr_index, addr_mask); block_number += rlen; block_length -= rlen; } else if (block_length >= FEE_CHAR_BIT) { rlen = ROUNDDOWN(block_length, FEE_CHAR_BIT); addr_index = block_number / FEE_CHAR_BIT; memset(addr + addr_index, 0x0, rlen / FEE_CHAR_BIT); ssdk_printf(SSDK_INFO, "fee_addr_mask_clear addr_index %d\n", addr_index); block_number += rlen; block_length -= rlen; } else { rlen = block_length; addr_index = block_number / FEE_CHAR_BIT; addr_mask = ~((0x1 << rlen) - 1); addr[addr_index] &= addr_mask; ssdk_printf(SSDK_INFO, "fee_addr_mask_clear block_length not aligned part addr_index %d addr_mask %x\n", addr_index, addr_mask); block_number += rlen; block_length -= rlen; } } return ret; } static int fee_addr_mask_and(uint8_t *addr_mask1, uint8_t *addr_mask2, uint8_t *addr_mask3, uint16_t block_length) { for (int i = 0; i < block_length; i++) { addr_mask3[i] = addr_mask1[i] & addr_mask2[i]; } return 0; } __UNUSED static int fee_addr_mask_or(uint8_t *addr_mask1, uint8_t *addr_mask2, uint8_t *addr_mask3, uint16_t block_length) { for (int i = 0; i < block_length; i++) { addr_mask3[i] = addr_mask1[i] | addr_mask2[i]; } return 0; } static int fee_addr_mask_empty(uint8_t *addr_mask, uint16_t block_length) { for (int i = 0; i < block_length; i++) { if (addr_mask[i]) return 0; } return 1; } /* get the start block address and size based on the block address mask */ static int fee_addr_mask_block(uint8_t *addr_mask, uint32_t addr_size, uint16_t *block_number, uint16_t *block_length) { int ret = 0; uint32_t addr_block_index = 0; uint32_t addr_index = 0; uint32_t rlen = 0; /* The first bit that is 1 is block_number */ for (int i = 0; i < addr_size; i++) { if (addr_mask[i]) { addr_block_index = i; ssdk_printf(SSDK_INFO, "addr_block_index:%d \n", addr_block_index); for (int j = 0; j < FEE_CHAR_BIT; j++) { if ((addr_mask[addr_block_index] >> j) & 0x1) { addr_index = j; ssdk_printf(SSDK_INFO, "addr_index:%d \n", addr_index); *block_number = DIVD_NUM(i, j, FEE_CHAR_BIT); ssdk_printf(SSDK_INFO, "block_number:%d \n", *block_number); goto match_num; } } } } return -1; match_num: /* Offset back from block_number and calculate the length from the first 0 bit to block_length */ for (int i = addr_block_index; i < addr_size; i++) { if (i != addr_block_index) addr_index = 0; for (int j = addr_index; j < FEE_CHAR_BIT; j++) { if ((addr_mask[i] >> j) & 0x1) { rlen++; ssdk_printf(SSDK_INFO, "rlen:%d \n", rlen); } else goto match_len; } } match_len: *block_length = rlen; return ret; } /* fee initial power-on initialization */ static int fee_format(struct fee_dev *fee_dev) { /* Erase all pages */ int ret = 0; for (int i = 0; i < fee_dev->page_number; i++) { ret = fee_erase_page(fee_dev, i); if (ret) { ssdk_printf(SSDK_CRIT, "fee_format erase page %d failure\n", i); return ret; } } /* configure Page 0 to FEE_PAGE_RECEIVE */ ret = fee_set_page_status(fee_dev, 0, FEE_PAGE_ACTIVE); if (ret) { ssdk_printf(SSDK_CRIT, "fee_format set page 0 FEE_PAGE_RECEIVE failure\n"); return ret; } return ret; } /* get the current record_index based on page_number */ static int fee_get_page_record_index(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t *record_index_offset) { int ret = 0; disk_size_t record_offset = 0; uint8_t record_match = 0; /* Get the latest record_info_offset(fee_record_info aligned) */ struct fee_record_info *record_info = (struct fee_record_info *) fee_dev->record_info_buff; uint32_t sector_index = fee_dev->page_info[page_number].page_buff_num - 1; uint32_t record_index = 0; /* Traversal from the last sector */ for (int i = sector_index; i >= 0 ; i--) { ret = fee_get_sector(fee_dev, page_number, i, (uint8_t *)record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i); return -1; } /* Traversal from the last record */ record_index = fee_dev->record_info_num - 1; for (int j = record_index; j >= 0; j--) { if (record_info[j].record_status == FEE_RECORD_ERASED) { ssdk_printf(SSDK_INFO, "sector_num:%d record_num:%d\n", sector_index - i, record_index - j); record_match = 1; record_offset = DIVD_NUM(sector_index - i, record_index - j, fee_dev->record_info_num); break; } } if (record_match) break; } *record_index_offset = record_offset; return ret; } /* Get the current page ADDR mask based on page_number and record_index */ static int fee_set_record_addr_mask(struct fee_dev *fee_dev, uint16_t page_number, disk_size_t record_index_offset, uint8_t *addr_mask) { int ret = 0; /* Traversal begins with the last sector */ uint32_t sector_num = DIV_ROUND_UP(record_index_offset, fee_dev->record_info_num); uint32_t sector_index = fee_dev->page_info[page_number].page_buff_num - sector_num; uint32_t record_num = 0, record_index = 0; struct fee_record_info *record_info = (struct fee_record_info *) fee_dev->record_info_buff; uint16_t block_length = 0; for (int i = sector_index; i < sector_index + sector_num; i++) { ret = fee_get_sector(fee_dev, page_number, i, (uint8_t *)record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i); return -1; } if ((!IS_ALIGNED(record_index_offset, fee_dev->record_info_num)) && (i == sector_index)) record_num = record_index_offset % fee_dev->record_info_num; else record_num = fee_dev->record_info_num; record_index = fee_dev->record_info_num - record_num; for (int j = record_index; j < record_index + record_num; j++) { block_length = DIV_ROUND_UP(record_info[j].record_len, fee_dev->block_length); ssdk_printf(SSDK_INFO, "block_number:%d block_length %d\n", record_info[j].record_num, block_length); fee_addr_mask_set(addr_mask, record_info[j].record_num, block_length); } } return ret; } static int fee_swap_data(struct fee_dev *fee_dev, uint16_t src_page, uint16_t dst_page, disk_size_t record_info_offset_dst, struct fee_record_info *record_info, disk_size_t record_data_offset_src, disk_size_t record_data_offset_dst) { int ret = 0; struct disk_dev_info *disk_dev = fee_dev->disk_dev; ret = fee_set_record_info(fee_dev, dst_page, record_info_offset_dst, record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee_block_write set_record_info block_number %d failure\n", record_info->record_num); return -1; } fee_record_length_t record_len = 0, rlen = 0, addr_offset = 0;; record_len = record_info->record_len; disk_addr_t addr_src = fee_dev->page_info[src_page].page_addr + FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset_src; disk_addr_t addr_dst = fee_dev->page_info[dst_page].page_addr + FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset_dst; while (record_len) { rlen = MIN(record_len, fee_dev->record_buff_size); memset((void *)fee_dev->record_data_buff, 0xff, ROUNDUP(rlen, disk_dev->access_size)); /* Read the data */ ret = fee_disk_read(fee_dev, addr_src + addr_offset, fee_dev->record_data_buff, ROUNDUP(rlen, disk_dev->access_size)); if (ret) { ssdk_printf(SSDK_CRIT, "fee fee_read_record_data failure\n"); return -1; } /* Write data */ ret = fee_disk_write(fee_dev, addr_dst + addr_offset, fee_dev->record_data_buff, ROUNDUP(rlen, disk_dev->access_size)); if (ret) { ssdk_printf(SSDK_CRIT, "fee fee_write_record failure\n"); return -1; } addr_offset += rlen; record_len -= rlen; } /* Configure record valid */ ret = fee_set_record_status(fee_dev, dst_page, record_info_offset_dst, FEE_RECORD_VALID); if (ret) { ssdk_printf(SSDK_CRIT, "fee_block_write set_record_info FEE_RECORD_VALID status block_number %d failure\n", record_info->record_num); return -1; } return ret; } /* Two page swaps */ static int fee_page_swap_multiple(struct fee_dev *fee_dev, uint16_t active_page, uint16_t erase_page) { int ret = 0; struct disk_dev_info *disk_dev = fee_dev->disk_dev; /* Setting page Status */ if (fee_set_page_status(fee_dev, active_page, FEE_PAGE_VALID)) return -1; if (fee_set_page_status(fee_dev, erase_page, FEE_PAGE_RECEIVE)) return -1; /* Record information */ disk_size_t record_info_offset_active = fee_dev->record_info_offset; disk_size_t record_info_offset_erase = 0; disk_size_t record_data_offset_erase = 0; disk_size_t record_info_offset_record = 0; disk_size_t record_data_offset_record = 0; uint16_t match_block = 0; uint16_t match_len = 0; disk_size_t record_addr_offset = 0; disk_size_t record_addr_len = 0; /* block address space */ uint8_t *block_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_BLOCK, fee_dev->block_addr_size); uint8_t *record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_RECORD, fee_dev->block_addr_size); uint8_t *current_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_RECORD_CURRENT, fee_dev->block_addr_size); uint8_t *tmp_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_RECORD_TMP, fee_dev->block_addr_size); /* copy data information */ memset(record_mask, 0x0, fee_dev->block_addr_size); memcpy(record_mask, block_mask, fee_dev->block_addr_size); /* Traversal begins with the last sector */ struct fee_record_info *record_info = (struct fee_record_info *) fee_dev->record_info_buff; uint32_t sector_num = DIV_ROUND_UP(record_info_offset_active, fee_dev->record_info_num); uint32_t sector_index = fee_dev->page_info[active_page].page_buff_num - sector_num; uint32_t record_num = 0, record_index = 0; for (int i = sector_index; i < sector_index + sector_num; i++) { ret = fee_get_sector(fee_dev, active_page, i, (uint8_t *)record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i); return -1; } if ((!IS_ALIGNED(record_info_offset_active, fee_dev->record_info_num)) && (i == sector_index)) record_num = record_info_offset_active % fee_dev->record_info_num; else record_num = fee_dev->record_info_num; record_index = fee_dev->record_info_num - record_num; for (int j = record_index; j < record_index + record_num; j++) { /* Record the effective */ if (record_info[j].record_status == FEE_RECORD_VALID) { /* Judge the matching of record and block_mask, and swap the consistent parts */ memset(current_record_mask, 0x0, fee_dev->block_addr_size); fee_addr_mask_set(current_record_mask, record_info[j].record_num, DIV_ROUND_UP(record_info[j].record_len, fee_dev->block_length)); memset(tmp_record_mask, 0x0, fee_dev->block_addr_size); fee_addr_mask_and(current_record_mask, record_mask, tmp_record_mask, fee_dev->block_addr_size); /* When the matching part is not empty */ while (!fee_addr_mask_empty(tmp_record_mask, fee_dev->block_addr_size)) { /* Matches block & length */ fee_addr_mask_block(tmp_record_mask, fee_dev->block_addr_size, &match_block, &match_len); /* Clears matching blocks */ fee_addr_mask_clear(tmp_record_mask, match_block, match_len); fee_addr_mask_clear(record_mask, match_block, match_len); /* Get record data */ record_info_offset_record = DIVD_NUM( fee_dev->page_info[active_page].page_buff_num - 1 - i, fee_dev->record_info_num - 1 - j, fee_dev->record_info_num); if (fee_get_record_data_offset(fee_dev, active_page, record_info_offset_record, &record_data_offset_record)) return -1; /* Calculate the data offset and matching address length of the matching part and record */ record_addr_offset = (match_block - record_info[j].record_num) * fee_dev->block_length; record_addr_len = match_len * fee_dev->block_length; /* Configuring record Information */ struct fee_record_info *record_info_erase = (struct fee_record_info *)&fee_dev->record_info; record_info_erase->record_status = FEE_RECORD_INVALID; record_info_erase->record_num = match_block; record_info_erase->record_len = record_addr_len; ret = fee_swap_data(fee_dev, active_page, erase_page, record_info_offset_erase, record_info_erase, record_data_offset_record + record_addr_offset, record_data_offset_erase); if (ret) { ssdk_printf(SSDK_CRIT, "fee_swap_data block_num %d failure\n", record_info[j].record_num); return -1; } record_info_offset_erase++; record_data_offset_erase += ROUNDUP(record_addr_len, disk_dev->access_size); } } if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size)) break; } if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size)) break; } /* Updated fee_dev information */ fee_dev->current_page = erase_page; fee_dev->record_info_offset = record_info_offset_erase; fee_dev->record_data_offset = record_data_offset_erase; memset(block_mask, 0x0, fee_dev->block_addr_size); ret = fee_set_record_addr_mask(fee_dev, erase_page, fee_dev->record_info_offset, block_mask); if (ret) { ssdk_printf(SSDK_CRIT, "fee set_record_addr_mask error\n"); return ret; } /* TODO:configure block mask info */ /* Setting page Status */ if (fee_set_page_status(fee_dev, erase_page, FEE_PAGE_ACTIVE)) return -1; if (fee_set_page_status(fee_dev, active_page, FEE_PAGE_ERASING)) return -1; if (fee_erase_page(fee_dev, active_page)) return -1; return ret; } /* TODO:Two page swaps singel block */ static int fee_page_swap_single(struct fee_dev *fee_dev, uint16_t active_page, uint16_t erase_page) { int ret = 0; return ret; } /* Two page swaps */ static int fee_page_swap(struct fee_dev *fee_dev, uint16_t active_page, uint16_t erase_page) { switch (fee_dev->page_mode) { case FEE_PAGE_BLOCK: return fee_page_swap_single(fee_dev, active_page, erase_page); case FEE_PAGE_EEPROM: return fee_page_swap_multiple(fee_dev, active_page, erase_page); default: ssdk_printf(SSDK_CRIT, "fee_page_swap page mode error\n"); return -1; } } /* get the current page based on page information */ static int fee_page_set_two(struct fee_dev *fee_dev) { int ret = 0; fee_page_status_t page0_status = 0; fee_page_status_t page1_status = 0; /* Getting page state */ ret = fee_get_page_status(fee_dev, 0, &page0_status); if (ret) { ssdk_printf(SSDK_CRIT, "fee get page0 status error\n"); return ret; } ret = fee_get_page_status(fee_dev, 1, &page1_status); if (ret) { ssdk_printf(SSDK_CRIT, "fee get page1 status error\n"); return ret; } ssdk_printf(SSDK_INFO, "get current page: page0_status %x page1_status %x\n", page0_status, page1_status); switch (page0_status) { case FEE_PAGE_ERASED: switch (page1_status) { case FEE_PAGE_ERASED: fee_dev->current_page = 0; break; case FEE_PAGE_ACTIVE: case FEE_PAGE_VALID: fee_dev->current_page = 1; break; default: goto error; } break; case FEE_PAGE_RECEIVE: switch (page1_status) { case FEE_PAGE_VALID: fee_dev->current_page = 1; break; default: goto error; } break; case FEE_PAGE_ACTIVE: switch (page1_status) { case FEE_PAGE_ERASED: case FEE_PAGE_VALID: case FEE_PAGE_ERASING: fee_dev->current_page = 0; break; default: goto error; } break; case FEE_PAGE_VALID: switch (page1_status) { case FEE_PAGE_ERASED: case FEE_PAGE_RECEIVE: fee_dev->current_page = 0; break; case FEE_PAGE_ACTIVE: fee_dev->current_page = 1; break; default: goto error; } break; case FEE_PAGE_ERASING: switch (page1_status) { case FEE_PAGE_ACTIVE: fee_dev->current_page = 1; break; default: goto error; } break; default: goto error; } return ret; error: ssdk_printf(SSDK_CRIT, "fee_page_set_two page0_status %x page1_status %x failure\n", page0_status, page1_status); return -1; } /* Page state information detection */ static int fee_page_check_two(struct fee_dev *fee_dev) { int ret = 0; fee_page_status_t page0_status = 0; fee_page_status_t page1_status = 0; /* Getting page state */ ret = fee_get_page_status(fee_dev, 0, &page0_status); if (ret) { ssdk_printf(SSDK_CRIT, "fee get page0 status error\n"); return ret; } ret = fee_get_page_status(fee_dev, 1, &page1_status); if (ret) { ssdk_printf(SSDK_CRIT, "fee get page1 status error\n"); return ret; } ssdk_printf(SSDK_CRIT, "two page: page0_status %x page1_status %x\n", page0_status, page1_status); switch (page0_status) { case FEE_PAGE_ERASED: switch (page1_status) { case FEE_PAGE_ERASED: ssdk_printf(SSDK_INFO, "fee dev is initialized for the first time,fee_format\n"); /* Power on for the first time */ return fee_format(fee_dev); case FEE_PAGE_ACTIVE: ssdk_printf(SSDK_INFO, "fee page information is normal\n"); /* Normal boot */ break; case FEE_PAGE_VALID: /* Page1 data is exchanged to Page0 */ ssdk_printf(SSDK_INFO, "fee page1 data is full, exchange data to page0\n"); return fee_page_swap(fee_dev, 1, 0); default: goto error; } break; case FEE_PAGE_RECEIVE: switch (page1_status) { case FEE_PAGE_VALID: /* Page1 data is exchanged to Page0 */ ssdk_printf(SSDK_INFO, "fee page1 data is full, erase page0 & exchange data to page0\n"); if (fee_erase_page(fee_dev, 0)) goto error; return fee_page_swap(fee_dev, 1, 0); default: goto error; } break; case FEE_PAGE_ACTIVE: switch (page1_status) { case FEE_PAGE_ERASED: ssdk_printf(SSDK_INFO, "fee page information is normal\n"); /* Normal boot */ break; case FEE_PAGE_VALID: fee_set_page_status(fee_dev, 1, FEE_PAGE_ERASING); case FEE_PAGE_ERASING: ssdk_printf(SSDK_INFO, "fee erase page1\n"); /* Erase the page1 */ return fee_erase_page(fee_dev, 1); default: goto error; } break; case FEE_PAGE_VALID: switch (page1_status) { case FEE_PAGE_ERASED: ssdk_printf(SSDK_INFO, "fee page0 data is full, exchange data to page1\n"); /* Page0 Data is exchanged to page1 */ return fee_page_swap(fee_dev, 0, 1); case FEE_PAGE_RECEIVE: /* Page0 Data is exchanged to page1 */ ssdk_printf(SSDK_INFO, "fee page0 data is full, erase page1 & exchange data to page1\n"); if (fee_erase_page(fee_dev, 1)) goto error; return fee_page_swap(fee_dev, 0, 1); case FEE_PAGE_ACTIVE: ssdk_printf(SSDK_INFO, "fee erase page0\n"); fee_set_page_status(fee_dev, 0, FEE_PAGE_ERASING); /* Erase the page1 */ return fee_erase_page(fee_dev, 0); default: goto error; } break; case FEE_PAGE_ERASING: switch (page1_status) { case FEE_PAGE_ACTIVE: ssdk_printf(SSDK_INFO, "fee erase page0\n"); /* Erase the page0 */ return fee_erase_page(fee_dev, 0); default: goto error; } break; default: goto error; } return ret; error: ssdk_printf(SSDK_CRIT, "page0_status %x page1_status %x failure\n", page0_status, page1_status); return -1; } int fee_init(struct fee_dev *fee_dev) { int ret = 0; disk_size_t page_size = 0; /* Configure basic page information */ fee_dev->page_number = FEE_PAGE_NUMBER; struct disk_dev_info *disk_dev = fee_dev->disk_dev; if (!IS_ALIGNED(disk_dev->addr, disk_dev->sector_size)) { ssdk_printf(SSDK_CRIT, "fee disk addr:%lld not aligned to sector_size %d\n", disk_dev->addr, disk_dev->sector_size); goto error; } if (!IS_ALIGNED(disk_dev->size, disk_dev->sector_size * fee_dev->page_number)) { ssdk_printf(SSDK_CRIT, "fee size:%lld not aligned to (sector_size * %d):%d\n", disk_dev->size, fee_dev->page_number, disk_dev->sector_size * fee_dev->page_number); goto error; } page_size = disk_dev->size / fee_dev->page_number; ssdk_printf(SSDK_INFO, "nor flash Flash EEPROM Emulation addr:%llx size:%llx\n", disk_dev->addr, disk_dev->size); for (int i = 0; i < fee_dev->page_number; i++) { fee_dev->page_info[i].page_addr = disk_dev->addr + (page_size * i); fee_dev->page_info[i].page_size = page_size; fee_dev->page_info[i].page_sector_num = fee_dev->page_info[i].page_size / disk_dev->sector_size; ssdk_printf(SSDK_CRIT, "page %d addr:%llx size:%llx page_sector_num:%d\n", i, fee_dev->page_info[i].page_addr, fee_dev->page_info[i].page_size, fee_dev->page_info[i].page_sector_num); } /* set current page */ switch (fee_dev->page_number) { case FEE_PAGE_NUMBER_TWO: ret = fee_page_set_two(fee_dev); if (ret < 0) { ssdk_printf(SSDK_CRIT, "two page mode set current page error \n"); goto error; } break; default: ssdk_printf(SSDK_CRIT, "page mode not support \n"); ret = -1; goto error; } ssdk_printf(SSDK_CRIT, "set current page %d\n", fee_dev->current_page); fee_dev->record_buff_size = FEE_RECORD_BUFF_SIZE; for (int i = 0; i < fee_dev->page_number; i++) { fee_dev->page_info[i].page_buff_num = fee_dev->page_info[i].page_size / fee_dev->record_buff_size; ssdk_printf(SSDK_CRIT, "page %d record_buff_size:%x page_buff_num:%d\n", i, fee_dev->record_buff_size, fee_dev->page_info[i].page_buff_num); } fee_dev->record_info_buff = FEE_ADDR_MASK_PRT(record_buff, FEE_INFO_BUFF, fee_dev->record_buff_size); fee_dev->record_data_buff = FEE_ADDR_MASK_PRT(record_buff, FEE_DATA_BUFF, fee_dev->record_buff_size); fee_dev->record_data_offset_buff = FEE_ADDR_MASK_PRT(record_buff, FEE_DATA_OFFSET_BUFF, fee_dev->record_buff_size); /* Verify that the Record INFO is aligned to the sector */ if (!IS_ALIGNED(fee_dev->record_buff_size, sizeof(struct fee_record_info))) { ssdk_printf(SSDK_CRIT, "fee record_buff_size %x not aligned to fee_record_info size %d\n", fee_dev->record_buff_size, sizeof(struct fee_record_info)); goto error; } fee_dev->record_info_num = fee_dev->record_buff_size / sizeof( struct fee_record_info); ret = fee_get_page_record_index(fee_dev, fee_dev->current_page, &fee_dev->record_info_offset); if (ret) { ssdk_printf(SSDK_CRIT, "fee get_page_record_index error\n"); goto error; } ret = fee_get_record_data_offset(fee_dev, fee_dev->current_page, fee_dev->record_info_offset, &fee_dev->record_data_offset); if (ret) { ssdk_printf(SSDK_CRIT, "fee get_record_data_offset error\n"); goto error; } ssdk_printf(SSDK_INFO, "record_info_offset %lld record_data_offset:%lld\n", fee_dev->record_info_offset, fee_dev->record_data_offset); memset(fee_dev->block_addr_mask, 0x0, fee_dev->block_addr_size * FEE_ADDR_MASK_MAX); ret = fee_set_record_addr_mask(fee_dev, fee_dev->current_page, fee_dev->record_info_offset, fee_dev->block_addr_mask); if (ret) { ssdk_printf(SSDK_CRIT, "fee set_record_addr_mask error\n"); goto error; } /* Check status information based on page mode */ switch (fee_dev->page_number) { case FEE_PAGE_NUMBER_TWO: ret = fee_page_check_two(fee_dev); if (ret < 0) { ssdk_printf(SSDK_CRIT, "two page mode check error \n"); goto error; } break; default: ssdk_printf(SSDK_CRIT, "page mode not support \n"); ret = -1; goto error; } /* One final page was FEE_PAGE_ACTIVE and the rest were FEE_PAGE_ERASE */ fee_page_status_t page_status; for (int i = 0; i < fee_dev->page_number; i++) { if (fee_get_page_status(fee_dev, i, &page_status)) goto error; if (page_status == FEE_PAGE_ACTIVE) { fee_dev->current_page = i; break; } } if (fee_get_page_status(fee_dev, fee_dev->current_page, &page_status)) goto error; if (page_status != FEE_PAGE_ACTIVE) { ssdk_printf(SSDK_CRIT, "page mode check FEE_PAGE_ACTIVE failure\n"); goto error; } for (int i = 0; i < fee_dev->page_number; i++) { if (fee_get_page_status(fee_dev, i, &page_status)) goto error; if ((i != fee_dev->current_page) && page_status != FEE_PAGE_ERASED) { ssdk_printf(SSDK_CRIT, "page mode check FEE_PAGE_ERASED failure\n"); goto error; } } return ret; error: return -1; } int fee_exit(struct fee_dev *fee_dev) { int ret = 0; return ret; } static int fee_page_check_size(struct fee_dev *fee_dev, uint16_t page_number, uint16_t length) { /* Fee Residual space detection */ /* One more record info space must be reserved for initial use of the record index offset */ disk_size_t used_size = sizeof(struct fee_page_info) + FEE_BLOCK_ADDR_BIT_SIZE + fee_dev->record_data_offset + (fee_dev->record_info_offset * sizeof( struct fee_record_info) + sizeof(struct fee_record_info)); if ((fee_dev->page_info[page_number].page_size - used_size) < length) return 0; else return 1; } /* Based on page_number, write record */ static int fee_write_record_block(struct fee_dev *fee_dev, uint16_t block_number, uint8_t *data_buffer, uint16_t length) { int ret = 0; struct disk_dev_info *disk_dev = fee_dev->disk_dev; if (!fee_page_check_size(fee_dev, fee_dev->current_page, length + sizeof(struct fee_record_info))) { ssdk_printf(SSDK_INFO, "******************%d full page size %lld target size %d,swap page****************\n", block_number, fee_dev->page_info[fee_dev->current_page].page_size, length + sizeof(struct fee_record_info)); uint16_t swap_page = 0; if (fee_dev->current_page == fee_dev->page_number - 1) swap_page = 0; else swap_page = fee_dev->current_page + 1; ret = fee_page_swap(fee_dev, fee_dev->current_page, swap_page); if (ret) { ssdk_printf(SSDK_CRIT, "fee fee_page_swap error\n"); return -1; } if (!fee_page_check_size(fee_dev, fee_dev->current_page, length + sizeof(struct fee_record_info))) { ssdk_printf(SSDK_EMERG, "swap page end, still not enough space\n"); return -1; } } /* Actually writing record */ ret = fee_write_record(fee_dev, fee_dev->current_page, fee_dev->record_info_offset, block_number, fee_dev->record_data_offset, data_buffer, length); if (ret) { ssdk_printf(SSDK_CRIT, "fee fee_write_record error\n"); return -1; } /* Update Status Information */ fee_dev->record_info_offset++; fee_dev->record_data_offset += ROUNDUP(length, disk_dev->access_size); fee_addr_mask_set(fee_dev->block_addr_mask, block_number, ROUNDUP(length, fee_dev->block_length)); /* TODO:set block addr mask */ return ret; } /* Based on page_number, write record */ int fee_write_record_multiple(struct fee_dev *fee_dev, uint16_t block_number, uint8_t *data_buffer, uint16_t length) { return fee_write_record_block(fee_dev, block_number, data_buffer, length); } /* Read the record based on page_number */ int fee_read_record_multiple(struct fee_dev *fee_dev, uint16_t block_number, uint8_t *data_buffer, uint16_t length) { int ret = 0; /* block address space */ uint8_t *block_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_BLOCK, fee_dev->block_addr_size); uint8_t *record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_RECORD, fee_dev->block_addr_size); uint8_t *current_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_RECORD_CURRENT, fee_dev->block_addr_size); uint8_t *tmp_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask, FEE_ADDR_MASK_RECORD_TMP, fee_dev->block_addr_size); /* record info offset */ disk_size_t record_info_offset_record = 0; disk_size_t record_data_offset_record = 0; /* match block */ uint16_t match_block = 0; uint16_t match_len = 0; /* data information */ disk_size_t record_addr_offset = 0; disk_size_t record_addr_len = 0; uint32_t data_addr_offset = 0; /* Matches the record part and the block part */ memset(record_mask, 0x0, fee_dev->block_addr_size); fee_addr_mask_set(record_mask, block_number, length / fee_dev->block_length); fee_addr_mask_and(block_mask, record_mask, record_mask, fee_dev->block_addr_size); /* Traversal begins with the last sector */ struct fee_record_info *record_info = (struct fee_record_info *) fee_dev->record_info_buff; uint32_t sector_num = DIV_ROUND_UP(fee_dev->record_info_offset, fee_dev->record_info_num); uint32_t sector_index = fee_dev->page_info[fee_dev->current_page].page_buff_num - sector_num; uint32_t record_num = 0, record_index = 0; for (int i = sector_index; i < sector_index + sector_num; i++) { ret = fee_get_sector(fee_dev, fee_dev->current_page, i, (uint8_t *)record_info); if (ret) { ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i); return -1; } if ((!IS_ALIGNED(fee_dev->record_info_offset, fee_dev->record_info_num)) && (i == sector_index)) record_num = fee_dev->record_info_offset % fee_dev->record_info_num; else record_num = fee_dev->record_info_num; record_index = fee_dev->record_info_num - record_num; for (int j = record_index; j < record_index + record_num; j++) { if (record_info[j].record_status == FEE_RECORD_VALID) { /* block_number and block_length of the current record */ memset(current_record_mask, 0x0, fee_dev->block_addr_size); fee_addr_mask_set(current_record_mask, record_info[j].record_num, record_info[j].record_len / fee_dev->block_length); /* matches the matching parts of current_record_mask and record_mask */ memset(tmp_record_mask, 0x0, fee_dev->block_addr_size); fee_addr_mask_and(current_record_mask, record_mask, tmp_record_mask, fee_dev->block_addr_size); while (!fee_addr_mask_empty(tmp_record_mask, fee_dev->block_addr_size)) { /* Matches block & length */ fee_addr_mask_block(tmp_record_mask, fee_dev->block_addr_size, &match_block, &match_len); /* Clears matching blocks */ fee_addr_mask_clear(tmp_record_mask, match_block, match_len); fee_addr_mask_clear(record_mask, match_block, match_len); /* Get record data information */ record_info_offset_record = DIVD_NUM( fee_dev->page_info[fee_dev->current_page].page_buff_num - 1 - i, fee_dev->record_info_num - 1 - j, fee_dev->record_info_num); if (fee_get_record_data_offset(fee_dev, fee_dev->current_page, record_info_offset_record, &record_data_offset_record)) return -1; /* Calculate the data offset and matching address length of the matching part and record */ record_addr_offset = (match_block - record_info[j].record_num) * fee_dev->block_length; record_addr_len = match_len * fee_dev->block_length; data_addr_offset = (match_block - block_number) * fee_dev->block_length; /* Read the data */ ret = fee_read_record_data(fee_dev, fee_dev->current_page, record_data_offset_record + record_addr_offset, data_buffer + data_addr_offset, record_addr_len); if (ret) { ssdk_printf(SSDK_CRIT, "fee fee_read_record_data failure\n"); return -1; } } if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size)) break; } if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size)) break; } } return 0; } /* TODO:write/read singel block */ int fee_write_record_single(struct fee_dev *fee_dev, uint16_t block_number, uint8_t *data_buffer, uint16_t length) { int ret = 0; return ret; } int fee_read_record_single(struct fee_dev *fee_dev, uint16_t block_number, uint16_t block_offset, uint8_t *data_buffer, uint16_t length) { int ret = 0; return ret; }