vivi源代码最为详细分析(三)
来源:互联网 发布:编程实现arp协议c语言 编辑:程序博客网 时间:2024/06/05 21:51
在我们即将看到的代码中,使用mtd_info数据结构表示一个MTD设备,使用nand_chip数据结构表示一个nand flash芯片。在mtd_info结构中,对nand_flash结构作了封装,向上层提供统一的接口。比如,它根据nand_flash提供的read_data(读一个字节)、read_addr(发送要读的扇区的地址)等函数,构造了一个通用的读函数read,将此函数的指针作为自己的一个成员。而上层要读写flash
时,执行mtd_info中的read、write函数即可。
ret = mtd_dev_init();
/*
* VIVI Interfaces
*/
#ifdef CONFIG_MTD
int write_to_flash(loff_t ofs, size_t len, const u_char *buf, int flag);
int mtd_dev_init(void);
#else
#define write_to_flash(a, b, c, d) (int)(1)
#define mtd_dev_init() (int)(1)
#endif
int mtd_init(void)
{
int ret;
#ifdef CONFIG_MTD_CFI
ret = cfi_init();
#endif
#ifdef CONFIG_MTD_SMC
ret = smc_init();
#endif
#ifdef CONFIG_S3C2410_AMD_BOOT
ret = amd_init();
#endif
u_char type;
u_int32_t flags;
u_int32_t size; // Total size of the MTD
* to be the only erase size available, or may use the more detailed
* information below if they desire
*/
u_int32_t erasesize;
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
u_int32_t ecctype;
u_int32_t eccsize;
char *name;
int index;
* it means that the whole device has erasesize as given above.
*/
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
u_int32_t bank_size;
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
void (*unpoint) (struct mtd_info *mtd, u_char * addr);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
* Methods to access the protection register area, present in some
* flash devices. The user data is one time programmable but the
* factory data is read only.
*/
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
/* Chip-supported device locking */
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
};
#ifdef CONFIG_MTD_NANDY
void (*hwcontrol)(int cmd);
void (*write_cmd)(u_char val);
void (*write_addr)(u_char val);
u_char (*read_data)(void);
void (*write_data)(u_char val);
void (*wait_for_ready)(void);
/*spinlock_t chip_lock;*/
/*wait_queue_head_t wq;*/
/*nand_state_t state;*/
int page_shift;
u_char *data_buf;
u_char *data_cache;
int cache_page;
struct nand_smc_dev *dev;
u_char spare[SMC_OOB_SIZE];
#else /* CONFIG_MTD_NANDY */
unsigned long IO_ADDR_R;
unsigned long IO_ADDR_W;
void (*hwcontrol)(int cmd);
int (*dev_ready)(void);
int chip_delay;
/*spinlock_t chip_lock;*/
/*wait_queue_head_t wq;*/
/*nand_state_t state;*/
int page_shift;
u_char *data_buf;
u_char *data_cache;
int cache_page;
#ifdef CONFIG_MTD_NAND_ECC
u_char ecc_code_buf[6];
u_char reserved[2];
#endif
#endif /* CONFIG_MTD_NANDY */
};
mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
this = (struct nand_chip *)(&mymtd[1]);
memset((char *)mymtd, 0, sizeof(struct mtd_info));
memset((char *)this, 0, sizeof(struct nand_chip));
mymtd->priv = this;
/* set NAND Flash controller */
nfconf = NFCONF;
/* NAND Flash controller enable */
nfconf |= NFCONF_FCTRL_EN;
/* Set flash memory timing */
nfconf &= ~NFCONF_TWRPH1; /* 0x0 */
nfconf |= NFCONF_TWRPH0_3; /* 0x3 */
nfconf &= ~NFCONF_TACLS; /* 0x0 */
NFCONF = nfconf;
/* Set address of NAND IO lines */
this->hwcontrol = smc_hwcontrol;
this->write_cmd = write_cmd;
this->write_addr = write_addr;
this->read_data = read_data;
this->write_data = write_data;
this->wait_for_ready = wait_for_ready;
/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */
this->hwcontrol(NAND_CTL_SETNCE);
this->write_cmd(NAND_CMD_RESET);
this->wait_for_ready();
this->hwcontrol(NAND_CTL_CLRNCE);
smc_insert(this);
inline int
smc_insert(struct nand_chip *this) {
/* Scan to find existance of the device */
if (smc_scan(mymtd)) {
return -ENXIO;
}
/* Allocate memory for internal data buffer */
this->data_buf = mmalloc(sizeof(u_char) *
(mymtd->oobblock + mymtd->oobsize));
if (!this->data_buf) {
printk("Unable to allocate NAND data buffer for S3C2410./n");
this->data_buf = NULL;
return -ENOMEM;
}
return 0;
}
{
int i, nand_maf_id, nand_dev_id; //定义flash的厂家ID和设备ID
struct nand_chip *this = mtd->priv; //获得与mtd设备相联系的真正的flash设备结构
nand_select(); //#define nand_select() this->hwcontrol(NAND_CTL_SETNCE); nand_command(mtd, NAND_CMD_RESET, -1, -1); udelay(10);这三句代码和我们之前在nand章节中讲解的片选flash是一个意思,先将使能nand的那位置1也就是片选nand,然后想nand发送reset命令,然后等待一段时间。
nand_command(mtd, NAND_CMD_READID, 0x00, -1);//向nand发送读ID的命令
nand_maf_id = this->read_data();//nand数据准备好后,通过read_data可以相继的读出厂家ID和设备ID
nand_dev_id = this->read_data();
for (i = 0; nand_flash_ids[i].name != NULL; i++) { //在数组nand_flash_ids中查找与ID相符合的项,可以看到下面对数组说明
if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
nand_dev_id == nand_flash_ids[i].model_id) {
#ifdef USE_256BYTE_NAND_FLASH
if (!mtd->size) { //下面都是根据在nand_flash_ids数组中找到相符的项,然后从对应的nand_flash_dev结构体中取出对应的属性值来填充mtd_info结构
mtd->name = nand_flash_ids[i].name;
mtd->erasesize = nand_flash_ids[i].erasesize;
mtd->size = (1 << nand_flash_ids[i].chipshift); //
mtd->eccsize = 256;
if (nand_flash_ids[i].page256) {
mtd->oobblock = 256;
mtd->oobsize = 8;
this->page_shift = 8;
} else {
mtd->oobblock = 512;
mtd->oobsize = 16;
this->page_shift = 9;
}
this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
}
#else
if (!(mtd->size) && !(nand_flash_ids[i].page256)) {
mtd->name = nand_flash_ids[i].name;
mtd->erasesize = nand_flash_ids[i].erasesize;
mtd->size = (1 << nand_flash_ids[i].chipshift);
mtd->eccsize = 256;
mtd->oobblock = 512;
mtd->oobsize = 16;
this->page_shift = 9;
this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
}
#endif
printk("NAND device: Manufacture ID:" /
" 0x%02x, Chip ID: 0x%02x (%s)/n",
nand_maf_id, nand_dev_id, mtd->name);
break;
}
}
nand_deselect(); //在对nand flash操作完后,需要禁止nand flash#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);也就是将对应的位置0
if (!mtd->size) {
printk("No NAND device found!!!/n");
return 1;
}
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; //填充mtd_info结构体中的函数指针,这些函数大多都是在smc_core.c定义
mtd->module = NULL;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_ecc = nand_read_ecc;
mtd->write_ecc = nand_write_ecc;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->lock = NULL;
mtd->unlock = NULL;
return 0;
}
struct nand_flash_dev {
char * name; //设备名
int manufacture_id; //flash的厂家ID
int model_id; //flash的设备ID
int chipshift; //片选移位数,用来构建flash的大小
char page256; //
char pageadrlen;
unsigned long erasesize;
};
static struct nand_flash_dev nand_flash_ids[] = {
{"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000}, // 2Mb 5V
... ....
{"Samsung K9D1G08V0M", NAND_MFR_SAMSUNG, 0x79, 27, 0, 3, 0x4000}, // 128Mb
{NULL,}
};
init_priv_data();
int
init_priv_data(void)
{
int ret_def;
#ifdef CONFIG_PARSE_PRIV_DATA
int ret_saved;
#endif
ret_def = get_default_priv_data();
#ifdef CONFIG_PARSE_PRIV_DATA
ret_saved = load_saved_priv_data();
if (ret_def && ret_saved) {
printk("Could not found vivi parameters./n");
return -1;
} else if (ret_saved && !ret_def) {
printk("Could not found stored vivi parameters.");
printk(" Use default vivi parameters./n");
} else {
printk("Found saved vivi parameters./n");
}
#else
if (ret_def) {
printk("Could not found vivi parameters/n");
return -1;
} else {
printk("Found default vivi parameters/n");
}
#endif
return 0;
a.vivi自身使用的一些参数,比如传输文件时的使用的协议等
b.linux启动命令
c.nand flash的分区参数
static inline int get_default_priv_data(void)
{
if (get_default_param_tlb()) //获取默认的参数表
return NO_DEFAULT_PARAM;
if (get_default_linux_cmd()) //获取到在vivi设置的linux启动命令
return NO_DEFAULT_LINUXCMD;
if (get_default_mtd_partition()) //这步很重要,主要用来获取到nand flash分区表
return NO_DEFAULT_MTDPART;
return 0;
}
int get_default_param_tlb(void)
{
char *src = (char *)&default_vivi_parameters;//这个默认的参数表也就是在程序中自定义的vivi_parameter_t数组,每个参数都用这样一个vivi_parameter_t来表示,default_vivi_parameters则为默认参数数组名,可以参考下面
char *dst = (char *)(VIVI_PRIV_RAM_BASE + PARAMETER_TLB_OFFSET); //48KB的参数区域从下到上依次是16KB的mtd参数信息,16KB的参数表,16KB的linux启动命令,所以这里PARAMETER_TLB_OFFSET=16KB
int num = default_nb_params;
if (src == NULL) return -1;
/*printk("number of vivi parameters = %d/n", num); */
*(nb_params) = num;
//参数表的长度不可以超过预设内存的大小,可以看到这里每个参数都是由vivi_parameter_t结构体来定义的,这里总共有num个参数,也就对应有num个结构体
if ((sizeof(vivi_parameter_t)*num) > PARAMETER_TLB_SIZE) {
printk("Error: too large partition table/n");
return -1;
}
//首先复制magic number
memcpy(dst, vivi_param_magic, 8);
//预留下8个字节作为扩展
dst += 16;
//复制真正的parameter
memcpy(dst, src, (sizeof(vivi_parameter_t)*num));
return 0;
}
typedef struct parameter {
char name[MAX_PARAM_NAME];
param_value_t value;
void (*update_func)(param_value_t value);
} vivi_parameter_t;
vivi_parameter_t default_vivi_parameters[] = {
{ "mach_type", MACH_TYPE, NULL },
{ "media_type", MT_S3C2410, NULL },
{ "boot_mem_base", 0x30000000, NULL },
{ "baudrate", UART_BAUD_RATE, NULL },
{ "xmodem_one_nak", 0, NULL },
{ "xmodem_initial_timeout", 300000, NULL },
{ "xmodem_timeout", 1000000, NULL },
{ "ymodem_initial_timeout", 1500000, NULL },
{ "boot_delay", 0x1000000, NULL }
};
int default_nb_params = ARRAY_SIZE(default_vivi_parameters);
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
{
char *src = linux_cmd;
char *dst = (char *)(VIVI_PRIV_RAM_BASE + LINUX_CMD_OFFSET);
dst += 8;
memcpy(dst, src, (strlen(src) + 1));
}
mtd_partition_t default_mtd_partitions[] = {
{
name: "vivi",
offset: 0,
size: 0x00020000,
flag: 0
}, {
name: "param",
offset: 0x00020000,
size: 0x00010000,
flag: 0
}, {
name: "kernel",
offset: 0x00030000,
size: 0x001d0000, // 2M sector
flag: 0
}, {
name: "root",
offset: 0x00200000,
size: 0x03000000,
flag: MF_BONFS
}
};在这里在flash分为vivi区,参数区,内核区,文件系统区,我们在vivi期间会将对应的内核,文件系统都会放到指定的区域,然后将信息传递给内核,这样内核在启动时会知道从哪地方加载内核,和文件系统。
{
char *buf = (char *)(DRAM_BASE);
char *dst = (char *)(VIVI_PRIV_RAM_BASE);
printk("invalid (saved) parameter block/n");
return -1;
}
if (strncmp((buf + PARAMETER_TLB_OFFSET), vivi_param_magic, 8) != 0)
return WRONG_MAGIC_PARAM;
memcpy(dst + PARAMETER_TLB_OFFSET, buf + PARAMETER_TLB_OFFSET,
PARAMETER_TLB_SIZE);
/* load linux command line */
if (strncmp((buf + LINUX_CMD_OFFSET), linux_cmd_magic, 8) != 0)
return WRONG_MAGIC_LINUXCMD;
memcpy((dst + LINUX_CMD_OFFSET), buf + LINUX_CMD_OFFSET, LINUX_CMD_SIZE);
/* load mtd partition table */
if (strncmp(buf + MTD_PART_OFFSET, mtd_part_magic, 8) != 0)
return WRONG_MAGIC_MTDPART;
memcpy(dst + MTD_PART_OFFSET, buf + MTD_PART_OFFSET, MTD_PART_SIZE);
}
{
char *src = (char *)(VIVI_PRIV_ROM_BASE); //VIVI_PRIV_ROM_BASE为flash上参数区域的起始地址
size_t size = (size_t)(VIVI_PRIV_SIZE); //VIVI_PRIV_SIZE也就是这三种类型的参数大小也就是48KB
{ //如果是在nand flash上定义了param分区,我们则直接去得到param分区的mtd_partition_t结构体
mtd_partition_t *part = get_mtd_partition("param");
if (part == NULL) {
printk("Could not found 'param' partition/n");
return -1;
}
src = (char *)part->offset; //然后获取到该结构体中定义的该分区的偏移地址,也真正就是存放参数的地址
}
#endif
return read_mem(buf, src, size); //然后从参数的源地址中读取参数先存放到sdram的起始地址也就是0x30000000,然后再拷贝到sdram的参数区,也就是load_saved_priv_data函数中的操作。read_mem函数里面也就是nand_read_ll函数,读nand flash之前已经讲过。
}
typedef struct user_command {
const char *name;
void (*cmdfunc)(int argc, const char **);
struct user_command *next_cmd;
const char *helpstr;
} user_command_t;
user_command_t help_cmd = {
"help",
command_help,
NULL,
"help [{cmds}] /t/t/t-- Help about help?"
};
void command_help(int argc, const char **argv)
{
user_command_t *curr;
/* help <command>. invoke <command> with 'help' as an argument */
if (argc == 2) {
if (strncmp(argv[1], "help", strlen(argv[1])) == 0) {
printk("Are you kidding?/n");
return;
}
argv[0] = argv[1];
argv[1] = "help";
execcmd(argc, argv);
return;
}
printk("Usage:/n");
curr = head_cmd;
while(curr != NULL) {
printk(" %s/n", curr->helpstr);
curr = curr->next_cmd;
}
}
void add_command(user_command_t *cmd)
{
if (head_cmd == NULL) { //对链表的操作,表示如果当前vivi中还没有任何命令,则将新加进来的user_command_t作为链表头指针
head_cmd = tail_cmd = cmd;
} else { //如果之前就存在,则将新加进来的user_command_t结构加载链表尾端就行
tail_cmd->next_cmd = cmd;
tail_cmd = cmd;
}
/*printk("Registered '%s' command/n", cmd->name);*/
}
{
char c;
int ret;
ulong boot_delay;
boot_delay = get_param_value("boot_delay", &ret); //从vivi的环境参数boot_delay中获取到等待的时间
if (ret) boot_delay = DEFAULT_BOOT_DELAY; //若没有设置该参数的值,则利用默认的等待时间
* unconditionally call vivi shell */
/*
* wait for a keystroke (or a button press if you want.)
*/
printk("Press Return to start the LINUX now, any other key for vivi/n");
c = awaitkey(boot_delay, NULL); //这句话也很重要,在等待时间内获取到用户按下去的键盘码值
if (((c != '/r') && (c != '/n') && (c != '/0'))) {
printk("type /"help/" for help./n");
vivi_shell();
}
run_autoboot(); //启动内核
}
{
#ifdef CONFIG_SERIAL_TERM
serial_term();
#else
#error there is no terminal.
#endif
}
{
char cmd_buf[MAX_CMDBUF_SIZE];
printk("%s> ", prompt);
if (cmd_buf[0])
exec_string(cmd_buf);//最终还是调用exec_string来进行命令的处理函数分配
}
}
{
while (1) {
exec_string("boot");
printk("Failed 'boot' command. reentering vivi shell/n");
/* if default boot fails, drop into the shell */
vivi_shell();
}
}
{
int argc;
char *argv[128];
char *resid;
memset(argv, 0, sizeof(argv));
parseargs(buf, &argc, argv, &resid); //从得到的命令字符串解析出命令
if (argc > 0)
execcmd(argc, (const char **)argv);//然后执行命令,在这里其实也是查表,找到命令名和argc相同的user_command_t结构体,然后调用user_command_t结构体中对应的命令处理函数来执行。
buf = resid;
}
}
- vivi源代码最为详细分析(三)
- vivi源代码最为详细分析(一)
- vivi源代码最为详细分析(二)
- Bootloader(Vivi)源代码分析
- vivi源代码分析1
- vivi源代码分析2
- vivi源代码分析3
- Bootloader(Vivi)源代码分析
- vivi源代码分析1
- vivi源代码分析2
- vivi源代码分析3
- Bootloader(Vivi)源代码分析
- vivi代码分析(三)
- s3c2410的Bootloader(Vivi)源代码分析
- s3c2410的Bootloader(Vivi)源代码分析
- vivi分析
- vivi分析
- vivi 命令详细
- CentOS5.6安装Apache Mysql PHP笔记
- 读取目录 正则表达式 用例
- android 图片上传以及php后台代码
- flash 事件流
- hadoop 重启后safemode问题
- vivi源代码最为详细分析(三)
- MyEclipse断点调试文章-tomcat
- 初识 C# 结构和类的区别
- linux 下 apache php-cgi 安装及配置(便于理解)
- USB协议简介
- flex 1037:包不能嵌套
- C语言 打渔晒网
- (转)玩转Solaris10 zone
- 房地产行业软件ApartmentSales开源版发布