[Feature][ZXW-88]merge P50 version
Only Configure: No
Affected branch: master
Affected module: unknown
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No
Change-Id: I34667719d9e0e7e29e8e4368848601cde0a48408
diff --git a/ap/lib/libmtd/Makefile b/ap/lib/libmtd/Makefile
new file mode 100755
index 0000000..f4fa4c6
--- /dev/null
+++ b/ap/lib/libmtd/Makefile
@@ -0,0 +1,37 @@
+#*******************************************************************************
+# include ZTE library makefile
+#*******************************************************************************
+#include $(COMMON_MK)
+
+##############USER COMIZE BEGIN################
+LIB_STATIC = libmtd.a
+LIB_SHARED = libmtd.so
+
+OBJS = mtd.o
+
+CFLAGS += -g -I.
+# off_t:32 bits -> 64 bits
+CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+#LDFLAGS += -lpthread
+##############USER COMIZE END##################
+
+CFLAGS += -fPIC
+
+CFLAGS += -I$(zte_app_path)/include
+
+LDFLAGS += -shared
+
+all: $(LIB_STATIC) $(LIB_SHARED)
+
+$(LIB_STATIC) : $(OBJS)
+ $(AR) rcs $(LIB_STATIC) $(OBJS)
+
+$(LIB_SHARED): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $^
+
+romfs:
+ $(ROMFSINST) $(LIB_SHARED) /lib/$(LIB_SHARED)
+
+clean:
+ -$(RM) *.a *.o *.so $(LIB_SHARED) $(LIB_STATIC) $(OBJS)
+
diff --git a/ap/lib/libmtd/mtd.c b/ap/lib/libmtd/mtd.c
new file mode 100755
index 0000000..5754368
--- /dev/null
+++ b/ap/lib/libmtd/mtd.c
@@ -0,0 +1,819 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <mtd/mtd-abi.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include "mtd_api.h"
+
+#define MTD_PATH_LENGTH_MAX (256)
+
+static ssize_t readn(int fd, void *vptr, size_t n);
+static ssize_t writen(int fd, const void *vptr, size_t n);
+
+/*******************************************************************************
+ * 内部函数/mtd_private.h *
+ *******************************************************************************/
+/**
+ * @brief 从文件描述符读取数据
+ * @param fd 入参,文件描述符
+ * @param vptr 出参,数据缓冲区
+ * @param n 入参,内容字节数
+ * @return 成功返回成功读取的字节数,失败返回-1
+ * @retval
+ * @note 封装read接口,读取被打断时会重试直到全部读取成功
+ * @warning
+ */
+static ssize_t readn(int fd, void *vptr, size_t n)
+{
+ size_t nleft;
+ ssize_t nread;
+ char *ptr;
+
+ ptr = vptr;
+ nleft = n;
+ while (nleft > 0)
+ {
+ if ((nread = read(fd, ptr, nleft)) < 0)
+ {
+ if (errno == EINTR)
+ {
+ nread = 0; /* and call read() again */
+ }
+ else
+ {
+ return (-1);
+ }
+ }
+ else if (nread == 0)
+ {
+ break; /* EOF */
+ }
+
+ nleft -= nread;
+ ptr += nread;
+ }
+ return (n - nleft); /* return >= 0 */
+}
+
+/**
+ * @brief 向文件描述符写入数据
+ * @param fd 入参,文件描述符
+ * @param vptr 入参,数据缓冲区
+ * @param n 入参,内容字节数
+ * @return 成功返回成功写入的字节数,失败返回-1
+ * @retval
+ * @note 封装write接口,写入被打断时会重试直到全部写入成功
+ * @warning
+ */
+static ssize_t writen(int fd, const void *vptr, size_t n)
+{
+ size_t nleft;
+ ssize_t nwritten;
+ const char *ptr;
+
+ ptr = vptr;
+ nleft = n;
+ while (nleft > 0)
+ {
+ nwritten = write(fd, ptr, nleft);
+ if (nwritten < 0)
+ {
+ if (errno == EINTR)
+ {
+ nwritten = 0; /* call write() again */
+ }
+ else
+ {
+ return (-1); /* error */
+ }
+ }
+ else if (nwritten == 0)
+ {
+ break;
+ }
+
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ return (n - nleft); /* return >= 0 */
+}
+
+/*******************************************************************************
+ * 外部函数定义 *
+ *******************************************************************************/
+int mtd_find(const char *i_parti_name, device_type_t device_type, char *o_mtd_path, unsigned int o_mtd_path_len)
+{
+ FILE *fp_mtd = 0;
+ char buf[128];
+ char *line_str;
+
+ if (!o_mtd_path_len)
+ {
+ return -1;
+ }
+
+ fp_mtd = fopen("/proc/mtd", "r+");
+ if (NULL == fp_mtd)
+ {
+ printf("[libmtd]: mtd_find, open file error:%s", strerror(errno));
+ return -1;
+ }
+ // printf("[libmtd]: partition name:%s\n", i_parti_name);
+
+ while (1)
+ {
+ int matches = 0;
+ char mtdname[64] = {0};
+ int mtdnum = 0;
+ unsigned int mtdsize, mtderasesize;
+ memset(buf, 0, sizeof(buf));
+ line_str = fgets(buf, sizeof(buf) - 1, fp_mtd);
+
+ if (NULL == line_str)
+ {
+ printf("[libmtd]: mtd_find, get info from mtd error:%s\n", strerror(errno));
+ fclose(fp_mtd);
+ return -1;
+ }
+ // mtd5: 00100000 00020000 "fotaflag"
+ matches = sscanf(buf, "mtd%d: %x %x \"%63[^\"]",
+ &mtdnum, &mtdsize, &mtderasesize, mtdname);
+ mtdname[63] = '\0';
+
+ if ((matches == 4) && (strcmp(mtdname, i_parti_name) == 0))
+ {
+ memset(o_mtd_path, 0, o_mtd_path_len);
+ if (device_type == DEVICE_MTD_BLOCK)
+ {
+ snprintf(o_mtd_path, o_mtd_path_len, "/dev/mtdblock%d", mtdnum);
+ }
+ else if (device_type == DEVICE_MTD)
+ {
+ snprintf(o_mtd_path, o_mtd_path_len, "/dev/mtd%d", mtdnum);
+ }
+ else if (device_type == DEVICE_ZFTL)
+ {
+ snprintf(o_mtd_path, o_mtd_path_len, "/dev/zftl%d", mtdnum);
+ }
+ else
+ {
+ printf("[libmtd]: mtd_find, unknown device type %d\n", device_type);
+ fclose(fp_mtd);
+ return -1;
+ }
+ // printf("[libmtd]: o_mtd_path=[%s]\n", o_mtd_path);
+ break;
+ }
+ }
+ fclose(fp_mtd);
+ return 0;
+}
+
+int mtd_get_info(int fd, struct mtd_info_user *info)
+{
+ if (0 != ioctl(fd, MEMGETINFO, info))
+ {
+ printf("[libmtd]: mtd_get_info, get fd(%d) info error, %s\n", fd, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+int mtd_block_isbad(int fd, off_t offset)
+{
+ int ret = 0;
+ ret = ioctl(fd, MEMGETBADBLOCK, &offset);
+ if (ret > 0)
+ {
+ printf("[libmtd]: mtd_block_isbad, bad block at 0x%lx, ret = %d\n", offset, ret);
+ ret = 1;
+ }
+ else if (ret < 0)
+ {
+ printf("[libmtd]: mtd_block_isbad, ioctl(MEMGETBADBLOCK) error at 0x%lx, %s, ret = %d\n", offset, strerror(errno), ret);
+ ret = -1;
+ }
+ return ret;
+}
+
+int mtd_erase_partition(const char *partition_name)
+{
+ int ret = 0;
+ char mtd_path[MTD_PATH_LENGTH_MAX] = {0};
+ int fd_mtd = -1;
+
+ struct mtd_info_user meminfo = {0};
+ struct erase_info_user64 erase_info = {0};
+
+ if (NULL == partition_name)
+ {
+ return -1;
+ }
+
+ ret = mtd_find(partition_name, DEVICE_MTD, mtd_path, MTD_PATH_LENGTH_MAX);
+ if (ret < 0)
+ {
+ printf("[libmtd]: mtd_erase_partition, mtd_find %s failed\n", partition_name);
+ ret = -1;
+ goto out;
+ }
+ fd_mtd = open(mtd_path, O_RDWR);
+ if (fd_mtd < 0)
+ {
+ printf("[libmtd]: mtd_erase_partition, open %s error, %s\n", partition_name, strerror(errno));
+ return -1;
+ }
+ ret = mtd_get_info(fd_mtd, &meminfo);
+ if (ret < 0)
+ {
+ printf("[libmtd]: mtd_erase_partition, get %s info error, %s\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ erase_info.length = meminfo.erasesize;
+ for (erase_info.start = 0; erase_info.start < meminfo.size; erase_info.start += meminfo.erasesize)
+ {
+ ret = mtd_block_isbad(fd_mtd, erase_info.start);
+ if (1 == ret)
+ {
+ continue;
+ }
+ else if (-1 == ret)
+ {
+ printf("[libmtd]: mtd_erase_partition, mtd_block_isbad %s error\n", partition_name);
+ goto out;
+ }
+
+ if (0 != ioctl(fd_mtd, MEMERASE64, &erase_info))
+ {
+ printf("[libmtd]: mtd_erase_partition, erasing %s failure at 0x%llx\n", partition_name, erase_info.start);
+ if (ioctl(fd_mtd, MEMSETBADBLOCK, &(erase_info.start)) < 0)
+ {
+ printf("[libmtd]: mtd_erase_partition, mark %s bad block error, %s\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ continue;
+ }
+ }
+ ret = 0;
+out:
+ if (fd_mtd >= 0)
+ {
+ close(fd_mtd);
+ }
+ return ret;
+}
+
+int mtd_write_partition(const char *partition_name, const char *image_file)
+{
+ int ret = 0;
+ ssize_t wr_len;
+ char mtd_path[MTD_PATH_LENGTH_MAX] = {0};
+ int fd_mtd = -1;
+ struct mtd_info_user meminfo = {0};
+
+ off_t data_size = 0;
+ off_t index = 0;
+ off_t fd_img_index = 0;
+ int fd_img = -1;
+ char *buf = NULL;
+ struct stat statbuff = {0};
+
+ if (NULL == partition_name || NULL == image_file)
+ {
+ return -1;
+ }
+
+ ret = mtd_find(partition_name, DEVICE_MTD, mtd_path, MTD_PATH_LENGTH_MAX);
+ if (ret < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, mtd_find %s failed\n", partition_name);
+ ret = -1;
+ goto out;
+ }
+ fd_mtd = open(mtd_path, O_RDWR);
+ if (fd_mtd < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, open %s error, %s\n", partition_name, strerror(errno));
+ return -1;
+ }
+ ret = mtd_get_info(fd_mtd, &meminfo);
+ if (ret < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, get %s info error, %s\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ if (stat(image_file, &statbuff) < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, stat %s failed, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ fd_img = open(image_file, O_RDONLY);
+ if (fd_img < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, open %s failed, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ buf = (char *)malloc(meminfo.erasesize);
+ if (!buf)
+ {
+ printf("[libmtd]: mtd_write_partition, malloc failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ for (index = 0; index < meminfo.size && fd_img_index < statbuff.st_size; index += meminfo.erasesize)
+ {
+ ret = mtd_block_isbad(fd_mtd, index);
+ if (1 == ret)
+ {
+ continue;
+ }
+ else if (-1 == ret)
+ {
+ printf("[libmtd]: mtd_write_partition, mtd_block_isbad %s error,at 0x%llx\n", partition_name, index);
+ goto out;
+ }
+
+ if (lseek(fd_img, fd_img_index, SEEK_SET) < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, lseek %s error = %s!\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ if (fd_img_index + meminfo.erasesize > statbuff.st_size)
+ {
+ data_size = statbuff.st_size - fd_img_index;
+ }
+ else
+ {
+ data_size = meminfo.erasesize;
+ }
+ wr_len = readn(fd_img, buf, (size_t)data_size);
+ if (wr_len < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, read %s error, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ fd_img_index += data_size;
+
+ if (lseek(fd_mtd, index, SEEK_SET) < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, lseek %s error = %s!\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ wr_len = writen(fd_mtd, buf, (size_t)data_size);
+ if (wr_len < 0)
+ {
+ printf("[libmtd]: mtd_write_partition, write %s error, %s\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ memset(buf, 0xFF, meminfo.erasesize);
+ }
+ if (fd_img_index < statbuff.st_size)
+ {
+ printf("[libmtd]: mtd_write_partition, No space left, writelen=0x%lx, filesize=0x%lx\n", fd_img_index, statbuff.st_size);
+ ret = -1;
+ goto out;
+ }
+ ret = 0;
+out:
+ if (fd_mtd >= 0)
+ {
+ close(fd_mtd);
+ }
+
+ if (buf != NULL)
+ {
+ // memset(buf, 0xFF, meminfo.erasesize);
+ free(buf);
+ }
+
+ if (fd_img >= 0)
+ {
+ close(fd_img);
+ }
+
+ return ret;
+}
+
+int mtd_erase_offset(int fd, off_t offset)
+{
+ struct mtd_info_user meminfo = {0};
+ struct erase_info_user64 erase_info = {0};
+
+ if (fd < 0)
+ {
+ printf("[libmtd]: mtd_erase_offset, fd(%d) error\n", fd);
+ return -1;
+ }
+
+ if (0 != mtd_get_info(fd, &meminfo))
+ {
+ printf("[libmtd]: mtd_erase_offset, get fd(%d) info error, %s\n", fd, strerror(errno));
+ return -1;
+ }
+
+ if (0 != (offset % meminfo.erasesize))
+ {
+ printf("[libmtd]: mtd_erase_offset, not at the beginning of a block, erasesize is %d\n", meminfo.erasesize);
+ return -1;
+ }
+
+ erase_info.length = meminfo.erasesize;
+ erase_info.start = offset;
+
+ if (mtd_block_isbad(fd, erase_info.start))
+ {
+ return -1;
+ }
+ if (0 != ioctl(fd, MEMERASE64, &erase_info))
+ {
+ printf("[libmtd]: mtd_erase_offset, erasing failure at 0x%llx\n", erase_info.start);
+ if (ioctl(fd, MEMSETBADBLOCK, &(erase_info.start)) < 0)
+ {
+ printf("[libmtd]: mtd_erase_offset, mark bad block error, %s\n", strerror(errno));
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t mtd_write_offset(int fd, off_t offset, const void *buf, size_t count)
+{
+ ssize_t writen_len;
+ struct mtd_info_user meminfo = {0};
+
+ if (fd < 0)
+ {
+ return -1;
+ }
+
+ if (0 != mtd_get_info(fd, &meminfo))
+ {
+ printf("[libmtd]: mtd_write_offset, get fd(%d) info error, %s\n", fd, strerror(errno));
+ return -1;
+ }
+ if (count <= 0 || count > meminfo.erasesize)
+ {
+ printf("[libmtd]: mtd_write_offset, count(0x%lx), less than 0, or larger than erasesize(0x%x)\n", count, meminfo.erasesize);
+ return -1;
+ }
+ if (0 != (offset % meminfo.erasesize))
+ {
+ printf("[libmtd]: mtd_write_offset, not at the beginning of a block, erasesize is 0x%x\n", meminfo.erasesize);
+ return -1;
+ }
+
+ if (mtd_block_isbad(fd, offset))
+ {
+ return -1;
+ }
+
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ {
+ printf("[libmtd]: mtd_write_offset, lseek error = %s!\n", strerror(errno));
+ return -1;
+ }
+ writen_len = writen(fd, buf, count);
+ if (writen_len != count)
+ {
+ if (-1 == writen_len)
+ {
+ printf("[libmtd]: mtd_write_offset, write error, %s\n", strerror(errno));
+ }
+ return -1;
+ }
+
+ return writen_len;
+}
+
+ssize_t mtd_read_offset(int fd, off_t offset, void *buf, size_t count)
+{
+ ssize_t readn_len;
+ struct mtd_info_user meminfo = {0};
+
+ if (fd < 0)
+ {
+ return -1;
+ }
+
+ if (0 != mtd_get_info(fd, &meminfo))
+ {
+ printf("[libmtd]: mtd_read_offset, get fd(%d) info error, %s\n", fd, strerror(errno));
+ return -1;
+ }
+ if (count <= 0 || count > meminfo.erasesize)
+ {
+ printf("[libmtd]: mtd_read_offset, count(0x%lx), less than 0, or larger than erasesize(0x%x)\n", count, meminfo.erasesize);
+ return -1;
+ }
+ if (0 != (offset % meminfo.erasesize))
+ {
+ printf("[libmtd]: mtd_read_offset, not at the beginning of a block, erasesize is %x\n", meminfo.erasesize);
+ return -1;
+ }
+
+ if (mtd_block_isbad(fd, offset))
+ {
+ return -1;
+ }
+
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ {
+ printf("[libmtd]: mtd_read_offset, lseek error = %s!\n", strerror(errno));
+ return -1;
+ }
+ readn_len = readn(fd, buf, count);
+ if (readn_len != count)
+ {
+ if (-1 == readn_len)
+ {
+ printf("[libmtd]: mtd_read_offset, read error, %s\n", strerror(errno));
+ }
+ return -1;
+ }
+
+ return readn_len;
+}
+
+static int zftl_verify_partition(const char *partition_name, const char *image_file)
+{
+ int ret = 0;
+ ssize_t rd_len;
+ size_t read_size = 4096;
+ char zftl_path[MTD_PATH_LENGTH_MAX] = {0};
+ int fd_zftl = -1;
+ struct mtd_info_user meminfo = {0};
+
+ off_t data_size = 0;
+ off_t index = 0;
+ off_t fd_img_index = 0;
+ int fd_img = -1;
+ char *buf = NULL;
+ char *buf2 = NULL;
+ struct stat statbuff = {0};
+
+ if (NULL == partition_name || NULL == image_file)
+ {
+ return -1;
+ }
+
+ ret = mtd_find(partition_name, DEVICE_ZFTL, zftl_path, MTD_PATH_LENGTH_MAX);
+ if (ret < 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, mtd_find %s failed\n", partition_name);
+ return -1;
+ }
+ fd_zftl = open(zftl_path, O_RDONLY);
+ if (fd_zftl < 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, open %s error, %s\n", partition_name, strerror(errno));
+ return -1;
+ }
+
+ if (stat(image_file, &statbuff) < 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, stat %s failed, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ fd_img = open(image_file, O_RDONLY);
+ if (fd_img < 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, open %s failed, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ buf = (char *)malloc(read_size);
+ if (!buf)
+ {
+ printf("[libmtd]: zftl_verify_partition, malloc failed\n");
+ ret = -1;
+ goto out;
+ }
+ buf2 = (char *)malloc(read_size);
+ if (!buf2)
+ {
+ printf("[libmtd]: zftl_verify_partition, malloc2 failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ for (index = 0; fd_img_index < statbuff.st_size; index += read_size)
+ {
+ //memset(buf, 0xFF, read_size);
+
+ if (fd_img_index + read_size > statbuff.st_size)
+ {
+ data_size = statbuff.st_size - fd_img_index;
+ }
+ else
+ {
+ data_size = read_size;
+ }
+ // data_size = (fd_img_index + read_size > statbuff.st_size) ? (statbuff.st_size - fd_img_index) : (read_size);
+
+ rd_len = readn(fd_img, buf, (size_t)data_size);
+ if (rd_len < 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, read image file %s error, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ fd_img_index += data_size;
+
+ rd_len = readn(fd_zftl, buf2, (size_t)data_size);
+ if (rd_len < 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, read zftl %s error, %s\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ if (memcmp(buf, buf2, (size_t)data_size) != 0)
+ {
+ printf("[libmtd]: zftl_verify_partition, data memcmp %s error\n", partition_name);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ if (fd_zftl >= 0)
+ {
+ //fsync(fd_zftl);
+ close(fd_zftl);
+ }
+
+ if (buf != NULL)
+ {
+ // memset(buf, 0xFF, meminfo.erasesize);
+ free(buf);
+ }
+ if (buf2 != NULL)
+ {
+ // memset(buf, 0xFF, meminfo.erasesize);
+ free(buf2);
+ }
+
+ if (fd_img >= 0)
+ {
+ close(fd_img);
+ }
+ if (ret == 0)
+ {
+ printf("[libmtd]: zftl %s verify sucess\n", partition_name);
+ }
+ else
+ {
+ printf("[libmtd]: zftl %s verify fail\n", partition_name);
+ }
+
+ return ret;
+}
+
+int zftl_write_partition(const char *partition_name, const char *image_file)
+{
+ int ret = 0;
+ ssize_t wr_len;
+ size_t write_size = 4096;
+ char zftl_path[MTD_PATH_LENGTH_MAX] = {0};
+ int fd_zftl = -1;
+ struct mtd_info_user meminfo = {0};
+
+ off_t data_size = 0;
+ off_t index = 0;
+ off_t fd_img_index = 0;
+ int fd_img = -1;
+ char *buf = NULL;
+ struct stat statbuff = {0};
+
+ if (NULL == partition_name || NULL == image_file)
+ {
+ return -1;
+ }
+
+ ret = mtd_find(partition_name, DEVICE_ZFTL, zftl_path, MTD_PATH_LENGTH_MAX);
+ if (ret < 0)
+ {
+ printf("[libmtd]: zftl_write_partition, mtd_find %s failed\n", partition_name);
+ return -1;
+ }
+ fd_zftl = open(zftl_path, O_RDWR);
+ if (fd_zftl < 0)
+ {
+ printf("[libmtd]: zftl_write_partition, open %s error, %s\n", partition_name, strerror(errno));
+ return -1;
+ }
+
+ if (stat(image_file, &statbuff) < 0)
+ {
+ printf("[libmtd]: zftl_write_partition, stat %s failed, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ fd_img = open(image_file, O_RDONLY);
+ if (fd_img < 0)
+ {
+ printf("[libmtd]: zftl_write_partition, open %s failed, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ buf = (char *)malloc(write_size);
+ if (!buf)
+ {
+ printf("[libmtd]: zftl_write_partition, malloc failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ for (index = 0; fd_img_index < statbuff.st_size; index += write_size)
+ {
+ memset(buf, 0xFF, write_size);
+
+ if (fd_img_index + write_size > statbuff.st_size)
+ {
+ data_size = statbuff.st_size - fd_img_index;
+ }
+ else
+ {
+ data_size = write_size;
+ }
+ // data_size = (fd_img_index + write_size > statbuff.st_size) ? (statbuff.st_size - fd_img_index) : (write_size);
+
+ wr_len = readn(fd_img, buf, (size_t)data_size);
+ if (wr_len < 0)
+ {
+ printf("[libmtd]: zftl_write_partition, read %s error, %s\n", image_file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ fd_img_index += data_size;
+
+ wr_len = writen(fd_zftl, buf, (size_t)data_size);
+ if (wr_len < 0)
+ {
+ printf("[libmtd]: zftl_write_partition, write %s error, %s\n", partition_name, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ }
+ if (fd_img_index < statbuff.st_size)
+ {
+ printf("[libmtd]: zftl_write_partition, No space left, writelen=0x%lx, filesize=0x%lx\n", fd_img_index, statbuff.st_size);
+ ret = -1;
+ goto out;
+ }
+ ret = 0;
+out:
+ if (fd_zftl >= 0)
+ {
+ fsync(fd_zftl);
+ close(fd_zftl);
+ }
+
+ if (buf != NULL)
+ {
+ // memset(buf, 0xFF, meminfo.erasesize);
+ free(buf);
+ }
+
+ if (fd_img >= 0)
+ {
+ close(fd_img);
+ }
+
+ if (ret == 0)
+ {
+ //write sucess then do verify
+ ret = zftl_verify_partition(partition_name, image_file);
+ }
+
+ return ret;
+}
\ No newline at end of file
diff --git a/ap/lib/libmtd/mtd_api.h b/ap/lib/libmtd/mtd_api.h
new file mode 100755
index 0000000..bd95421
--- /dev/null
+++ b/ap/lib/libmtd/mtd_api.h
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 版权所有 (C)2022, 中兴通讯股份有限公司。
+ *
+ * 文件名称: pub_flags.h
+ * 文件标识: pub_flags
+ * 内容摘要: zx298501芯片平台flags分区规划头文件
+ * 使用方法:
+ *
+ * 修改日期 版本号 修改标记 修改人 修改内容
+ * ------------------------------------------------------------------------------
+ * 2022/09/15 V1.0 Create 周国坡 创建
+ *
+ *******************************************************************************/
+
+#ifndef _MTD_API_H
+#define _MTD_API_H
+
+typedef enum
+{
+ DEVICE_MTD = 0,
+ DEVICE_ZFTL = 1,
+ DEVICE_MTD_BLOCK,
+} device_type_t;
+
+/**
+ * @brief 根据分区名查找分区设备文件路径
+ * @param partition_name 入参,分区名
+ * @param type 入参,设备类型
+ * @param out_mtd_path 出参,设备文件路径缓冲区
+ * @param out_mtd_path_len 入参,out_mtd_path数据缓冲区长度
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note
+ * @warning
+ */
+extern int mtd_find(const char *i_parti_name, device_type_t type, char *out_mtd_path, unsigned int out_mtd_path_len);
+
+/**
+ * @brief 根据分区名获取mtd分区信息
+ * @param fd 入参,mtd分区文件fd
+ * @param info 出参,包括分区大小和擦除块大小
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern int mtd_get_info(int fd, struct mtd_info_user *info);
+
+/**
+ * @brief 判断block是否是坏块
+ * @param fd 入参,mtd分区文件fd
+ * @param offset 入参,mtd分区偏移位置,包含坏块
+ * @return 0表示非坏块,1表示坏块,-1表示失败
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern int mtd_block_isbad(int fd, off_t offset);
+
+/**
+ * @brief 擦除指定分区
+ * @param partition_name 入参,分区名
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note
+ * @warning
+ */
+extern int mtd_erase_partition(const char *partition_name);
+
+/**
+ * @brief 将指定镜像文件写到指定分区
+ * @param partition_name 入参,分区名
+ * @param image_file 入参,指定的镜像文件
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note
+ * @warning 先要mtd_erase_partition函数擦除分区
+ */
+extern int mtd_write_partition(const char *partition_name, const char *image_file);
+
+/**
+ * @brief 擦除mtd分区指定位置数据
+ * @param fd 入参,mtd分区文件fd
+ * @param offset 入参,mtd分区偏移位置,包含坏块
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern int mtd_erase_offset(int fd, off_t offset);
+
+/**
+ * @brief 将数据写到mtd分区指定偏移位置
+ * @param fd 入参,mtd分区文件fd
+ * @param offset 入参,mtd分区偏移位置
+ * @param buf 入参,数据缓冲区
+ * @param count 入参,buf数据长度,不超过一个擦除块
+ * @return 成功返回写入数据长度,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning 先要mtd_erase_partition函数擦除分区
+ */
+extern ssize_t mtd_write_offset(int fd, off_t offset, const void *buf, size_t count);
+
+/**
+ * @brief 读取mtd分区指定偏移位置的数据
+ * @param fd 入参,mtd分区文件fd
+ * @param offset 入参,mtd分区偏移位置
+ * @param buf 出参,数据缓冲区
+ * @param count 入参,buf数据长度,不超过一个擦除块
+ * @return 成功返回读取数据长度,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern ssize_t mtd_read_offset(int fd, off_t offset, void *buf, size_t count);
+
+#endif /* _MTD_API_H */