nuttx/tools/rp2040/make_flash_fs.c
Huang Qi 8b3862d19b style: Fix case statement formatting in power management callbacks.
Remove unnecessary parentheses around case labels in switch statements
for power management callback functions. This fixes checkpatch style
violations for case statement formatting.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
2026-01-10 12:59:14 -03:00

495 lines
13 KiB
C

/****************************************************************************
* tools/rp2040/make_flash_fs.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <stdio.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/dir.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define MAX_NAME_LEN 16
#define MAX_SECTOR_DATA (1024 - 10)
#define MAX_DIR_COUNT (MAX_SECTOR_DATA / 24)
/****************************************************************************
* Private Types
****************************************************************************/
typedef struct dir_item_s
{
struct dir_item_s *prior;
bool is_directory;
int init_sector;
int permissions;
char name[0];
} dir_item_t;
/****************************************************************************
* Private Data
****************************************************************************/
int max_name_len = MAX_NAME_LEN;
int root_sector = 3;
char path[4096];
uint8_t *buffer;
const char *preamble =
"\n .macro sector num, type, used=0xffff, next=0xffff"
"\n .balign 1024, 0xff"
"\n .hword \\num, 0"
"\n .byte 0b01101001, \\type"
"\n 1:"
"\n .hword \\next, \\used"
"\n .endm"
"\n"
"\n .macro dir_entry perm, addr, time, name"
"\n .hword \\perm | 0x7e00, \\addr"
"\n .word \\time"
"\n 0:"
"\n .ascii \"\\name\""
"\n .= 0b + name_length"
"\n .endm"
"\n"
"\n .macro file_entry perm, addr, time, name"
"\n .hword \\perm | 0x5e00, \\addr"
"\n .word \\time"
"\n 0:"
"\n .ascii \"\\name\""
"\n .= 0b + name_length"
"\n .endm"
"\n"
"\n .cpu cortex-m0plus"
"\n .thumb"
"\n"
"\n .section .flash.init, \"ax\""
"\n .balign 4096"
"\n .global rp2040_smart_flash_start"
"\n rp2040_smart_flash_start:"
"\n .ascii \"2040\""
"\n .byte 0b01101001"
"\n .ascii \"SMRT\""
"\n .byte 0x01, 0x10, 0"
"\n"
"\n .balign 4096, 0xff";
const char *postamble =
"\n"
"\n .balign 4096, 0xff"
"\n .global rp2040_smart_flash_end"
"\n rp2040_smart_flash_end:"
"\n"
"\n .end";
/****************************************************************************
* Private Functions
****************************************************************************/
void put_name(const char * cp)
{
putchar('"');
for (; *cp != 0; ++cp)
{
switch (*cp)
{
case '\"':
printf("\\\"");
break;
case '\'':
printf("\\\'");
break;
case '\\':
printf("\\\\");
break;
case '\a':
printf("\\a");
break;
case '\b':
printf("\\b");
break;
case '\n':
printf("\\n");
break;
case '\t':
printf("\\t");
break;
default:
if (iscntrl(*cp))
{
printf("\\%03o", *cp);
}
else
{
putchar(*cp);
}
}
}
putchar('"');
}
/****************************************************************************
* Name: copy_file
****************************************************************************/
int copy_file(int in_sector, const char * in_name)
{
FILE *data_file = fopen(path, "r");
struct stat file_stat;
int sector_len;
uint8_t *bp;
if (data_file == NULL) return in_sector;
lstat(path, &file_stat);
while (file_stat.st_size > 0)
{
bp = buffer;
sector_len = fread(buffer, 1, MAX_SECTOR_DATA, data_file);
file_stat.st_size -= sector_len;
if (file_stat.st_size > 0)
{
printf("\n sector %4d, dir, used=%d, next=%d",
in_sector,
sector_len,
in_sector + 1);
}
else
{
printf("\n sector %4d, file, used=%d",
in_sector,
sector_len);
}
in_sector += 1;
for (; sector_len > 0; sector_len -= 8)
{
printf("\n .byte ");
for (int i = 0; i < 8 && i < sector_len; ++i)
{
if (i != 0) printf(", ");
printf("0x%02x", *bp++);
}
}
printf("\n");
}
return in_sector;
}
/****************************************************************************
* Name: dir_entry
*
* On entry:
* The global "path" will be path to the prototype directory.
****************************************************************************/
int scan_dir(int in_sector)
{
dir_item_t *an_item = NULL;
dir_item_t *prior_item = NULL;
int path_len = strlen(path);
int item_count = 0;
int sector = in_sector + 1;
DIR *input_dir;
struct dirent *a_dirent;
struct stat stat;
int name_len;
if (name_len > max_name_len)
{
fprintf(stderr, "directory name to big. skipped. (%s)\n", path);
return -1;
}
input_dir = opendir(path);
if (input_dir == NULL)
{
fprintf(stderr,
"could not open directory %s %s\n",
path,
strerror(errno));
return -1;
}
/* scan directory to create directory entries */
while ((a_dirent = readdir(input_dir)) != NULL)
{
if (strcmp(a_dirent->d_name, ".") == 0) continue;
if (strcmp(a_dirent->d_name, "..") == 0) continue;
path[path_len] = '/';
strncpy(&path[path_len + 1], a_dirent->d_name, 4094 - path_len);
if (a_dirent->d_type == DT_DIR || a_dirent->d_type == DT_REG)
{
name_len = strlen(a_dirent->d_name);
if (name_len > max_name_len)
{
fprintf(stderr, "Skipped item. Name too long: %s\n", path);
continue;
}
item_count += 1;
an_item = malloc(sizeof(dir_item_t) + name_len + 1);
an_item->prior = prior_item;
prior_item = an_item;
strncpy(an_item->name, a_dirent->d_name, name_len);
an_item->init_sector = sector;
if (a_dirent->d_type == DT_DIR)
{
an_item->is_directory = true;
an_item->permissions = 0777;
sector = scan_dir(sector);
}
else
{
an_item->is_directory = false;
an_item->permissions = 0666;
sector = copy_file(sector, an_item->name);
}
}
else
{
fprintf(stderr, "Skipped unusable item: %s\n", path);
}
}
path[path_len] = 0;
closedir(input_dir);
/* Generate the directory sector for this directory. */
if (item_count > MAX_DIR_COUNT)
{
printf("\n sector %4d, dir, next=%d", in_sector, sector);
}
else
{
printf("\n sector %4d, dir", in_sector);
}
while (an_item != NULL)
{
for (int i = 0; i < MAX_DIR_COUNT && an_item != NULL; ++i)
{
if (an_item->is_directory)
{
printf("\n dir_entry 0%03o, 0x%04x, 0, ",
an_item->permissions,
an_item->init_sector);
put_name(an_item->name);
}
else
{
printf("\n file_entry 0%03o, 0x%04x, 0, ",
an_item->permissions,
an_item->init_sector);
put_name(an_item->name);
}
prior_item = an_item->prior;
free(an_item);
an_item = prior_item;
item_count -= 1;
}
if (an_item != NULL)
{
printf("\n sector %4d, dir, used=%d",
sector,
(item_count > MAX_DIR_COUNT) ? (sector + 1) : 0xffff);
sector += 1;
}
}
printf("\n");
return sector;
}
/****************************************************************************
* Name: print_help
****************************************************************************/
void print_help(const char * name)
{
fprintf(stderr, "\nusage: %s [-h][-n name-len] source-path\n\n", name);
fprintf(stderr, "-h : print this help and exit.\n\n");
fprintf(stderr, "-n : name length is the length of file names in\n");
fprintf(stderr, " the smart filesystem. It must match the\n");
fprintf(stderr, " CONFIG_SMARTFS_MAXNAMLEN with which NuttX was\n");
fprintf(stderr, " built. The default is %d.\n\n", max_name_len);
fprintf(stderr, "source-path is the path to a prototype directory tree\n");
fprintf(stderr, " that will be used to build the initial smart\n");
fprintf(stderr, " filesystem. Any items that are not normal\n");
fprintf(stderr, " files or directories will be ignored.\n\n");
fprintf(stderr, "Output is to stdout.\n\n");
}
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, char *argv[])
{
FILE *output_file;
const char *input_path = NULL;
/* parse arguments */
for (int i = 1; i < argc; ++i)
{
if (argv[i][0] == '-')
{
if (argv[i][1] == 'h')
{
print_help(argv[0]);
return 0;
}
if (argv[i][1] == 'n')
{
if (argv[i][2] == 0 && argc > i + 1)
{
i += 1;
if (!isdigit(argv[i][0]))
{
fprintf(stderr, "invalid name length.\n");
print_help(argv[0]);
return 1;
}
max_name_len = atoi(argv[i]);
}
else if (isdigit(argv[i][2]))
{
max_name_len = atoi(&(argv[i][2]));
}
else
{
fprintf(stderr, "invalid name length.\n");
print_help(argv[0]);
return 1;
}
}
else
{
fprintf(stderr, "unknown argument: %c\n", argv[i][1]);
print_help(argv[0]);
return 1;
}
}
else if (input_path == NULL)
{
input_path = argv[i];
}
}
if (input_path == NULL)
{
print_help(argv[0]);
return 1;
}
buffer = malloc(MAX_SECTOR_DATA);
if (buffer == NULL)
{
fprintf(stderr, "could not allocate file buffer.\n");
return 1;
}
strncpy(path, input_path, 4096);
/* remove any stray trailing slash characters. */
for (int c = strlen(path) - 1; c >= 0; --c)
{
if (path[c] != '/') break;
path[c] = 0;
}
/* Output the defined constants */
printf("dir= 1\n"
"file= 2\n"
"name_length= %d\n",
max_name_len);
/* Output the macro definitions and block zero. */
puts(preamble);
/* Scan the prototype directory tree. */
scan_dir(root_sector);
/* Wrap things up. */
puts(postamble);
return 0;
}