📄 fconfig.c
字号:
//==========================================================================
//
// fconfig.c
//
// RedBoot - persistent data storage support (FLASH or EEPROM)
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas, tkoeller
// Date: 2000-07-28
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <redboot.h>
#ifdef CYGOPT_REDBOOT_FIS
#include <fis.h>
#endif
#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
// Note horrid intertwining of functions, to save precious FLASH
externC void fis_update_directory(void);
#endif
#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_EEPROM
externC void write_eeprom(void *buf, int len);
externC void read_eeprom(void *buf, int len);
#endif
#ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
externC bool cyg_plf_redboot_esa_validate(unsigned char *val);
#endif
#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
externC bool do_flash_init(void);
externC int flash_read(void *flash_base, void *ram_base, int len, void **err_address);
#endif
// Round a quantity up
#define _rup(n,s) ((((n)+(s-1))/s)*s)
#include <flash_config.h>
// Configuration data, saved in FLASH, used to set/update RedBoot
// normal "configuration" data items.
struct _config *config, *backup_config;
// Local data used by these routines
#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
extern void *flash_start, *flash_end;
extern int flash_block_size, flash_num_blocks;
extern int __flash_init;
#ifdef CYGOPT_REDBOOT_FIS
extern void *fis_work_block;
extern void *fis_addr;
extern int fisdir_size; // Size of FIS directory.
#endif
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
static struct _config *readonly_config;
#endif
void *cfg_base; // Location in Flash of config data
int cfg_size; // Length of config data - rounded to Flash block size
#endif // FLASH MEDIA
// Prototypes for local functions
static unsigned char *flash_lookup_config(char *key);
static bool config_ok;
#define CONFIG_KEY1 0x0BADFACE
#define CONFIG_KEY2 0xDEADDEAD
#define CONFIG_DONE 0
#define CONFIG_ABORT -1
#define CONFIG_CHANGED 1
#define CONFIG_OK 2
#define CONFIG_BACK 3
#define CONFIG_BAD 4
// Note: the following options are related. If 'boot_script' is false, then
// the other values are used in the configuration. Because of the way
// that configuration tables are generated, they should have names which
// are related. The configuration options will show up lexicographically
// ordered, thus the peculiar naming.
RedBoot_config_option("Run script at boot",
boot_script,
ALWAYS_ENABLED, true,
CONFIG_BOOL,
false
);
RedBoot_config_option("Boot script",
boot_script_data,
"boot_script", true,
CONFIG_SCRIPT,
""
);
// Some preprocessor magic for building the [constant] prompt string
#define __cat(s1,c2,s3) s1 #c2 s3
#define _cat(s1,c2,s3) __cat(s1,c2,s3)
RedBoot_config_option(_cat("Boot script timeout (",
CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION,
"ms resolution)"),
boot_script_timeout,
"boot_script", true,
CONFIG_INT,
0
);
#undef __cat
#undef _cat
#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
RedBoot_config_option("Console baud rate",
console_baud_rate,
ALWAYS_ENABLED, true,
CONFIG_INT,
CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
);
#endif
CYG_HAL_TABLE_BEGIN( __CONFIG_options_TAB__, RedBoot_config_options);
CYG_HAL_TABLE_END( __CONFIG_options_TAB_END__, RedBoot_config_options);
extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[];
//
// Layout of config data
// Each data item is variable length, with the name, type and dependencies
// encoded into the object.
// offset contents
// 0 data type
// 1 length of name (N)
// 2 enable sense
// 3 length of enable key (M)
// 4 key name
// N+4 enable key
// M+N+4 data value
//
#define CONFIG_OBJECT_TYPE(dp) (dp)[0]
#define CONFIG_OBJECT_KEYLEN(dp) (dp)[1]
#define CONFIG_OBJECT_ENABLE_SENSE(dp) (dp)[2]
#define CONFIG_OBJECT_ENABLE_KEYLEN(dp) (dp)[3]
#define CONFIG_OBJECT_KEY(dp) ((dp)+4)
#define CONFIG_OBJECT_ENABLE_KEY(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp))
#define CONFIG_OBJECT_VALUE(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)+CONFIG_OBJECT_ENABLE_KEYLEN(dp))
#define LIST_OPT_LIST_ONLY (1)
#define LIST_OPT_NICKNAMES (2)
#define LIST_OPT_FULLNAMES (4)
#define LIST_OPT_DUMBTERM (8)
static void config_init(void);
static int
get_config(unsigned char *dp, char *title, int list_opt, char *newvalue )
{
char line[256], hold_line[256], *sp, *lp;
int ret;
bool hold_bool_val, new_bool_val, enable;
unsigned long hold_int_val, new_int_val;
#ifdef CYGPKG_REDBOOT_NETWORKING
in_addr_t hold_ip_val, new_ip_val;
enet_addr_t hold_esa_val;
int esa_ptr;
char *esp;
#endif
void *val_ptr;
int type;
if (CONFIG_OBJECT_ENABLE_KEYLEN(dp)) {
flash_get_config(CONFIG_OBJECT_ENABLE_KEY(dp), &enable, CONFIG_BOOL);
if (((bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && !enable) ||
(!(bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && enable)) {
return CONFIG_OK; // Disabled field
}
}
lp = line; *lp = '\0';
val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
if (LIST_OPT_NICKNAMES & list_opt)
diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
if (LIST_OPT_FULLNAMES & list_opt) {
if (title != (char *)NULL) {
diag_printf("%s: ", title);
} else {
diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
}
}
switch (type = CONFIG_OBJECT_TYPE(dp)) {
case CONFIG_BOOL:
memcpy(&hold_bool_val, val_ptr, sizeof(bool));
lp += diag_sprintf(lp, "%s", hold_bool_val ? "true" : "false");
break;
case CONFIG_INT:
memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
lp += diag_sprintf(lp, "%ld", hold_int_val);
break;
#ifdef CYGPKG_REDBOOT_NETWORKING
case CONFIG_IP:
lp += diag_sprintf(lp, "%s", inet_ntoa((in_addr_t *)val_ptr));
if (0 == strcmp("0.0.0.0", line) && !(LIST_OPT_LIST_ONLY & list_opt)) {
// then we have a deeply unhelpful starting text - kill it off
// (unless we are just listing all values)
lp = line; *lp = '\0';
}
break;
case CONFIG_ESA:
for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
lp += diag_sprintf(lp, "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
if (esa_ptr < (sizeof(enet_addr_t)-1)) lp += diag_sprintf(lp, ":");
}
break;
#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
case CONFIG_NETPORT:
lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
break;
#endif
#endif
case CONFIG_STRING:
lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
break;
case CONFIG_SCRIPT:
diag_printf("\n");
sp = lp = (unsigned char *)val_ptr;
while (*sp) {
while (*lp != '\n') lp++;
*lp = '\0';
diag_printf(".. %s\n", sp);
*lp++ = '\n';
sp = lp;
}
break;
}
if (LIST_OPT_LIST_ONLY & list_opt) {
diag_printf("%s\n", line);
return CONFIG_OK;
}
if (type != CONFIG_SCRIPT) {
if (NULL != newvalue) {
ret = strlen(newvalue);
if (ret > sizeof(line))
return CONFIG_BAD;
strcpy(hold_line, line); // Hold the old value for comparison
strcpy(line, newvalue);
diag_printf("Setting to %s\n", newvalue);
} else {
// read from terminal
strcpy(hold_line, line);
if (LIST_OPT_DUMBTERM & list_opt) {
diag_printf( (CONFIG_STRING == type ?
"%s > " :
"%s ? " ), line);
*line = '\0';
}
ret = _rb_gets_preloaded(line, sizeof(line), 0);
}
if (ret < 0) return CONFIG_ABORT;
// empty input - leave value untouched (else DNS goes away for a
// minute to try to look it up) but we must accept empty value for strings.
if (0 == line[0] && CONFIG_STRING != type) return CONFIG_OK;
if (strcmp(line, hold_line) == 0) return CONFIG_OK; // Just a CR - leave value untouched
lp = &line[strlen(line)-1];
if (*lp == '.') return CONFIG_DONE;
if (*lp == '^') return CONFIG_BACK;
}
switch (type) {
case CONFIG_BOOL:
memcpy(&hold_bool_val, val_ptr, sizeof(bool));
if (!parse_bool(line, &new_bool_val)) {
return CONFIG_BAD;
}
if (hold_bool_val != new_bool_val) {
memcpy(val_ptr, &new_bool_val, sizeof(bool));
return CONFIG_CHANGED;
} else {
return CONFIG_OK;
}
break;
case CONFIG_INT:
memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
if (!parse_num(line, &new_int_val, 0, 0)) {
return CONFIG_BAD;
}
if (hold_int_val != new_int_val) {
memcpy(val_ptr, &new_int_val, sizeof(unsigned long));
return CONFIG_CHANGED;
} else {
return CONFIG_OK;
}
break;
#ifdef CYGPKG_REDBOOT_NETWORKING
case CONFIG_IP:
memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t));
if (!_gethostbyname(line, &new_ip_val)) {
return CONFIG_BAD;
}
if (hold_ip_val.s_addr != new_ip_val.s_addr) {
memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t));
return CONFIG_CHANGED;
} else {
return CONFIG_OK;
}
break;
case CONFIG_ESA:
memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t));
esp = line;
for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
unsigned long esa_byte;
if (!parse_num(esp, &esa_byte, &esp, ":")) {
memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
return CONFIG_BAD;
}
((unsigned char *)val_ptr)[esa_ptr] = esa_byte;
}
#ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
if (!cyg_plf_redboot_esa_validate(val_ptr)) {
memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
return CONFIG_BAD;
}
#endif
return CONFIG_CHANGED;
break;
#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
case CONFIG_NETPORT:
if (strlen(line) >= MAX_STRING_LENGTH || net_devindex(line) < 0) {
int index;
const char *name;
diag_printf("Sorry, Port name must be one of:\n");
for (index = 0; (name = net_devname(index)) != NULL; index++)
diag_printf(" %s\n", name);
return CONFIG_BAD;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -