/**************************************************************************** * apps/fsutils/flashtool/flashtool_main.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include /**************************************************************************** * Private Types ****************************************************************************/ enum opr_list { HELP, DEVICE_INFO, READ_PAGE, WRITE_PAGE, ERASE_BLOCK, ERASE_ALL, CHECK_BAD_BLOCK }; /**************************************************************************** * Private Functions ****************************************************************************/ static void display_help(void) { printf("Usage : flashtool [OPTION [ARG]] device_name ...\n"); printf("-h show this help statement\n"); printf("-i display device geometry information\n"); printf("-r read the specified pages\n"); printf("-w write the specified pages\n"); printf("-e erase the specified blocks\n"); printf("-n number of pages or blocks\n"); printf("-f file name for read or write\n"); printf("-b check whether is bad\n"); printf("-c erase all of the flash\n"); printf("-d device name\n"); } static void display_device_info(FAR const struct mtd_geometry_s *geo) { printf("Size of one read/write page: %lu\n", geo->blocksize); printf("Size of one erase block: %lu\n", geo->erasesize); printf("Number of erase blocks: %lu\n", geo->neraseblocks); } static int read_page(int fd, FAR const struct mtd_geometry_s *geo, off_t start_page, size_t npages) { FAR unsigned char *buf; ssize_t ret = OK; off_t seek; size_t i; buf = malloc(geo->blocksize); if (!buf) { printf("ERROR: read_page cannot allocate memory %d\n", geo->blocksize); return ERROR; } seek = geo->blocksize * start_page; if (lseek(fd, seek, SEEK_SET) != seek) { printf("ERROR: Cannot seek mtd to offset %lld: %d", seek, errno); goto oops; } printf("Flash pages contents:\n"); for (i = 0; i < npages; i++) { ret = read(fd, buf, geo->blocksize); if (ret < 0) { printf("ERROR: Read error: %d!\n", errno); goto oops; } printf("Flash page %lld:\n", start_page + i); lib_dumpbuffer(NULL, buf, ret); } oops: free(buf); return ret; } /* Write npages data from img to flash * If size of img is less than npags, only write img size */ static int write_page(int fd, FAR const struct mtd_geometry_s *geo, off_t start_page, size_t npages, FAR const char *img) { FAR unsigned char *buf; off_t imglen; off_t seek; off_t i; int fd_src; int ret = OK; if (img == NULL) { printf("ERROR: Need source file path!\n"); return ERROR; } printf("Write data from %s...\n", img); seek = geo->blocksize * start_page; if (lseek(fd, seek, SEEK_SET) != seek) { printf("ERROR: cannot seek mtd to offset %lld: %d", seek, errno); return ERROR; } fd_src = open(img, O_RDONLY); if (fd_src < 0) { printf("ERROR: Open file %s failed: %d\n", img, errno); return ERROR; } imglen = lseek(fd_src, 0, SEEK_END); if (lseek(fd_src, 0, SEEK_SET) != 0) { close(fd_src); return ERROR; } /* Malloc a size of page for buf */ buf = malloc(geo->blocksize); if (!buf) { printf("ERROR: write_page cannot allocate memory %d\n", geo->blocksize); close(fd_src); return ERROR; } for (i = start_page; i < start_page + npages; i++) { ret = read(fd_src, buf, (imglen < geo->blocksize) ? imglen : geo->blocksize); if (ret < 0) { printf("ERROR: read source file error: %d!\n", errno); goto oops; } ret = write(fd, buf, geo->blocksize); if (ret < 0) { printf("ERROR: write error: %d!\n", errno); goto oops; } imglen -= geo->blocksize; if (imglen <= 0) { break; } } oops: close(fd_src); free(buf); return ret; } static int erase_block(int fd, off_t start_block, size_t nblocks) { struct mtd_erase_s erase; int ret; printf("Erase block from %lld to %lld!\n", start_block, start_block + nblocks -1); erase.startblock = start_block; erase.nblocks = nblocks; ret = ioctl(fd, MTDIOC_ERASESECTORS, &erase); if (ret < 0) { printf("ERROR: Erase failed: %d!\n", errno); } return ret; } static int erase_all(int fd) { if (ioctl(fd, MTDIOC_BULKERASE, 0) < 0) { printf("ERROR: MTD ioctl(MTDIOC_BULKERASE) failed: %d\n", errno); return ERROR; } return OK; } static int check_bad_block(int fd, FAR const struct mtd_geometry_s *geo) { struct mtd_bad_block_s bad_block; int flag = 0; int ret; int i; printf("Check bad blocks in flash......\n"); for (i = 0; i < geo->neraseblocks; i++) { bad_block.block_num = i; ret = ioctl(fd, MTDIOC_ISBAD, &bad_block); if (ret != OK) { printf("ERROR: MTDIOC_ISBAD failed: %d!\n", errno); return ERROR; } else { if (bad_block.bad_flag) { printf("Block %d is bad!\n", i); flag = 1; } } } if (flag == 0) { printf("No bad blocks!\n"); } return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ int main(int argc, FAR char *argv[]) { FAR char *mtddev = NULL; FAR char *img = NULL; struct mtd_geometry_s geo; enum opr_list opr = HELP; off_t npages = 1; off_t start; int option; int mode = O_RDONLY; int fd; int ret; while ((option = getopt(argc, argv, ":hir:w:e:n:f:bcd:")) != -1) { switch (option) { case 'h': display_help(); exit(0); case 'i': opr = DEVICE_INFO; break; case 'r': opr = READ_PAGE; start = strtoul(optarg, NULL, 0); break; case 'w': opr = WRITE_PAGE; mode = O_RDWR; start = strtoul(optarg, NULL, 0); break; case 'e': opr = ERASE_BLOCK; start = strtoul(optarg, NULL, 0); break; case 'n': npages = strtoul(optarg, NULL, 0); break; case 'f': img = optarg; break; case 'b': opr = CHECK_BAD_BLOCK; break; case 'c': opr = ERASE_ALL; break; case 'd': mtddev = optarg; break; case ':': printf("Error: Missing required argument\n"); exit(1); case '?': printf("Error: Unrecognized option\n"); exit(1); } } if (mtddev == NULL) { printf("Error: Device name is required!\n"); return -1; } fd = open(mtddev, mode, 0777); if (fd < 0) { printf("ERROR: Failed to open '%s': %d\n", mtddev, errno); return -1; } ret = ioctl(fd, MTDIOC_GEOMETRY, &geo); if (ret < 0) { printf("ERROR: Ioctl MTDIOC_GEOMETRY failed: %d\n", errno); goto oops; } switch (opr) { case DEVICE_INFO: display_device_info(&geo); break; case READ_PAGE: ret = read_page(fd, &geo, start, npages); break; case WRITE_PAGE: ret = write_page(fd, &geo, start, npages, img); break; case ERASE_BLOCK: ret = erase_block(fd, start, npages); break; case ERASE_ALL: ret = erase_all(fd); break; case CHECK_BAD_BLOCK: ret = check_bad_block(fd, &geo); break; default: } oops: close(fd); return ret; }