mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
In flashtool_main.c, the 'default:' label in a switch statement was followed directly by '}', which is invalid in C. This commit adds a 'break;' statement after the default label to resolve the error. Signed-off-by: tuansuper <tunainnet@tutanota.com>
374 lines
9.1 KiB
C
374 lines
9.1 KiB
C
/****************************************************************************
|
|
* 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 <nuttx/config.h>
|
|
#include <nuttx/mtd/mtd.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <fcntl.h>
|
|
#include <nuttx/debug.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
/****************************************************************************
|
|
* 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 <page> read the specified pages\n");
|
|
printf("-w <page> write the specified pages\n");
|
|
printf("-e <block> erase the specified blocks\n");
|
|
printf("-n <num> number of pages or blocks\n");
|
|
printf("-f <file> file name for read or write\n");
|
|
printf("-b <block> check whether <block> is bad\n");
|
|
printf("-c erase all of the flash\n");
|
|
printf("-d <device> 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:
|
|
break;
|
|
}
|
|
|
|
oops:
|
|
close(fd);
|
|
return ret;
|
|
}
|