Vivi(Bootloader)源代码分析与移植 - 图文(8)

2019-06-17 17:48

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

可见,vivi现在支持三种类型的存储接口,一种是CFI,也就是Intel发起的一个flash的接口标准,主要就是intel的nor flash系列;一种是smc,智能卡系列接口,nand flash就是通过这个接口实现读写的;一种是AMD的flash系列。选择什么启动方式,就要选择相应的配置项。

核心部分根据配置应该调用smc_init函数。-->【drivers/mtd/maps/s3c2410_flash.c】。这里最为核心的就是两个数据结构,一个是mtd_info,位于【include/mtd/mtd.h】,如下: struct mtd_info { u_char type; u_int32_t flags;

u_int32_t size; // Total size of the MTD

/* \飗e users may take this * 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 oobblock; // Size of OOB blocks (e.g. 512)

u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) u_int32_t ecctype; u_int32_t eccsize;

// Kernel-only stuff starts here. char *name; int index;

/* Data for variable erase regions. If numeraseregions is zero, * it means that the whole device has erasesize as given above. */

int numeraseregions;

struct mtd_erase_region_info *eraseregions;

/* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size; struct module *module;

36

int (*erase) (struct mtd_info *mtd, struct erase_info *instr); /* This stuff for eXecute-In-Place */

int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ 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 (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);

int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);

int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); 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 (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);

/* This function is not yet implemented */

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); void *priv; };

mtd_info是表示MTD设备的结构,每个分区也被表示为一个mtd_info,如果有两个MTD设备,每个设备有三个分区,那么在系统中就一共有6个mtd_info结构。关于mtd_info,在《Linux MTD源代码分析》中讲解非常透彻,不过需要注意的是,在vivi的实现中没有使用mtd_table,另外priv指向的是nand_chip,这些都是与Linux下不同的地方,主要是为了简化。另一个是nand_chip,这个结构则包含了nand flash的所有信息。 struct nand_chip {

#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);

37

/*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 */ };

所谓的初始化,其实就是填充处理上述两个数据结构的过程。填充完毕之后,后续的工作都会基于此展开。下面开始看smc_init的代码。

mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)); this = (struct nand_chip *)(&mymtd[1]);

在这里,第一句参考前面heap的实现代码,重点看第二句代码。这句代码是有一定的技巧性,但是也存在着很大的风险。其中,mymtd是指向struct mtd_info的指针,那么mymtd[1]实际上是等效于*(mymtd + 1)的数学计算模式,注意mymtd并非数组,这里仅仅利用了编译器翻译的特点。对于指针而言,加1实际上增加的指针对应类型的值,在这里地址实际上增加了sizeof(struct mtd_info),因为前面分配了两块连续的地址空间,所以&(*(mymtd + 1))实际上就是mtd_info数据结构结束的下一个地址,然后实现强制转换,于是this就成为了nand_chip的入口指针了。但是,这里必须要把握好,因为这个地方是不会进行内存的检查的,也就是说,如果你使用了mymtd[2],那么仍然按照上述公式解析,虽然可以运算,可是就是明显的指针泄漏了,可能会出现意料不到的结果。写了一个测试程序,对这点进行了探讨,要小心内存问题。

38

了解清楚了,mymtd指向mtd_info的入口,this指向nand_chip的入口。

memset((char *)mymtd, 0, sizeof(struct mtd_info)); memset((char *)this, 0, sizeof(struct nand_chip));

mymtd->priv = this;

上述代码首先初始化这两个结构体,即均为0.然后利用priv把二者联系起来,也就是mymtd通过其成员priv指向this,那么mymtd中的抽闲操作函数,比如read、write等,真正的是通过this来实现的。很明显,this的实现部分属于flash硬件驱动层,而mymtd部分则属于MTD设备层,二者的联系就是通过成员priv实现的。

接下来首先是初始化nand flash设备,这跟前面的基础实验一致。

/* 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;

然后填充nand flash的数据结构的一个实例this,分成了两个部分,nand flash基本操作函数成员的初始化、其余信息的填写。

/* 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);

上面这些都不难理解,感觉在结构体设计上还是比较出色的,把成员和相应的操作封

39

装起来,面向对象的一种方法。下面看smc_insert,根据刚才填充的nand_flash结构,构造mtd_info结构无非还是按照结构体填写相应的信息,细节部分就不深入探讨了。

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(\ this->data_buf = NULL; return -ENOMEM; }

return 0; }

第一部分扫描填充mymtd数据结构。后面主要用于nand flash的oob缓冲处理。具体部分可以参考《s3c2410完全开发》。我们先来看看smc_scan函数的执行(drivers/mtd/nand/smc_core.c这个文件中包含的是nand flash中绝大多数真正进行操作的函数):

int smc_scan(struct mtd_info *mtd) {

int i, nand_maf_id, nand_dev_id; //定义flash的厂家ID和设备ID

struct nand_chip *this = mtd->priv; //获得与mtd设备相联系的真正的flash设备结构 /* Select the device */ 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命令,然后等待一段时间。 /* Send the command for reading device ID */

nand_command(mtd, NAND_CMD_READID, 0x00, -1);//向nand发送读ID的命令 this->wait_for_ready(); //等待nand结果数据准备好 /* Read manufacturer and device IDs */

nand_maf_id = this->read_data();//nand数据准备好后,通过read_data可以相继的读出厂家ID和设备ID

nand_dev_id = this->read_data();

/* Print and sotre flash device information */

for (i = 0; nand_flash_ids[i].name != NULL; i++) { //在数组nand_flash_ids中查找与ID相符合的项,可以看到下面对数组说明

40


Vivi(Bootloader)源代码分析与移植 - 图文(8).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:【恒心】【好卷速递】甘肃省张掖市2012届高三4月高考诊断试卷 文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: