Linux_2.6.11_MTD驱动情景分析 说明

  • 格式:doc
  • 大小:62.00 KB
  • 文档页数:9

Linux 2.6.11 MTD驱动情景分析02/13 2008最近几天为了熟悉linux的驱动开发,我选择了MTD驱动做了一些研究。

我能找到的文章中我觉得有些部分不够细致,所以我还是自己写了一部分分析,希望对别人也能有所帮助,也做为自己的一个备忘。

蓝色文字的部分是从网络上摘录的。

一个嵌入式系统经常会使用NOR flash 或NAND flash来存放bootload,内核和文件系统等等。

下面是网络上找到的linux下的mtd驱动的分析:一、Flash硬件驱动层:硬件驱动层负责在init时驱动Flash硬件,Linux MTD 设备的NOR Flash芯片驱动遵循CFI接口标准,其驱动程序位于drivers/mtd/chips子目录下。

NAND型Flash的驱动程序则位于/drivers/mtd/nand 子目录下。

二、MTD原始设备:原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是各个特定的Flash的数据,例如分区。

用于描述MTD原始设备的数据结构是mtd_info,这其中定义了大量的关于MTD的数据和操作函数。

mtd_table(mtdcore.c)则是所有MTD原始设备的列表,mtd_part(mtd_part.c)是用于表示MTD原始设备分区的结构,其中包含了mtd_info,因为每一个分区都是被看成一个MTD原始设备加在mtd_table中的,mtd_part.mtd_info中的大部分数据都从该分区的主分区mtd_part- >master 中获得。

在drivers/mtd/maps/子目录下存放的是特定的flash的数据,每一个文件都描述了一块板子上的flash。

其中调用add_mtd_device()、del_mtd_device()建立/删除mtd_info结构并将其加入/删除mtd_table(或者调用add_mtd_partition()、del_mtd_partition()(mtdpart.c)建立/删除mtd_part结构并将mtd_part.mtd_info加入/删除mtd_table 中)。

三、MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。

MTD字符设备的定义在mtdchar.c中实现,通过注册一系列file operation函数(lseek、open、close、read、write)。

MTD块设备则是定义了一个描述MTD块设备的结构mtdblk_dev,并声明了一个名为mtdblks的指针数组,该数组中的每一个mtdblk_dev和mtd_table中的每一个mtd_info一一对应。

四、设备节点:通过mknod在/dev子目录下建立MTD字符设备节点(主设备号为90)和MTD块设备节点(主设备号为31),通过访问此设备节点即可访问MTD字符设备和块设备。

五、根文件系统:在Bootloader中将JFFS(或JFFS2)的文件系统映像jffs.image (或jffs2.img)烧到flash的某一个分区中,在/arch/arm/mach-your/arch.c文件的your_fixup函数中将该分区作为根文件系统挂载。

六、文件系统:内核启动后,通过mount 命令可以将flash中的其余分区作为文件系统挂载到mountpoint上。

NOR型Flash芯片驱动与MTD原始设备所有的NOR型Flash的驱动(探测probe)程序都放在drivers/mtd/chips 下,一个MTD原始设备可以由一块或者数块相同的Flash芯片组成。

假设由4块devicetype为x8的Flash,每块大小为8M,interleave为2,起始地址为0x01000000,地址相连,则构成一个MTD原始设备(0x01000000-0x03000000),其中两块interleave成一个chip,其地址从0x01000000到0x02000000,另两块interleave成一个chip,其地址从0x02000000到0x03000000。

请注意,所有组成一个MTD原始设备的Flash芯片必须是同类型的(无论是interleave还是地址相连),在描述MTD原始设备的数据结构中也只是采用了同一个结构来描述组成它的Flash芯片。

每个MTD原始设备都有一个mtd_info结构,其中的priv指针指向一个map_info结构,map_info结构中的fldrv_priv指向一个cfi_private结构,cfi_private结构的cfiq指针指向一个cfi_ident结构,chips指针指向一个flchip 结构的数组。

其中mtd_info、map_info和cfi_private结构用于描述MTD原始设备;因为组成MTD原始设备的NOR型Flash相同,cfi_ident结构用于描述Flash芯片的信息;而flchip结构用于描述每个Flash芯片的专有信息(比如说起始地址)总的来说,嵌入式系统中一般来说会有一块或多块连续的NOR flash或NAND flash空间(每一个可能是多块相同的芯片来构成)每一个这样的空间被看成一个MTD原始设备(我不知道这个名字谁起的,我也这么用吧)根据一些文章和代码中使用的变量名,我后面称呼它为主分区。

你可以按照自己的需要把主分区分成几个区,我的开发板用的分区信息如下:来自alchemy_flash.c:static struct mtd_partition alchemy_partitions[] = {{.name = "User FS", //这里给根文件系统.size = BOARD_FLASH_SIZE - 0x00400000,.offset = 0x0000000},{.name = "YAMON",//这块给bootloader.size = 0x0100000,.offset = MTDPART_OFS_APPEND, //表示接着上一个分区.mask_flags = MTD_WRITEABLE},{.name = "raw kernel",.size = (0x300000 - 0x40000), /* last 256KB is yamon env */ //这块给自解压//的压缩内核,最后留了点给booterloader的环境变量,它没有被设备驱动使用,而是由booterloader以自己的方式访问。

.offset = MTDPART_OFS_APPEND,}};如果你增加或者是减少了你的flash空间(通过增加或减少flash芯片)或则你想调整几个分区的大小,你只需要修改这个表就可以了。

如果你还有一块NAND区,那么你可能有如下的分区表(au1550nd.c):const static struct mtd_partition partition_info[] = {{.name = "NAND FS 0",.offset = 0,.size = 8*1024*1024},{.name = "NAND FS 1",.offset = MTDPART_OFS_APPEND,.size = MTDPART_SIZ_FULL}};整个alchemy_flash.c就两个函数:alchemy_mtd_init(void)和alchemy_mtd_cleanup()。

int __init alchemy_mtd_init(void){struct mtd_partition *parts;int nb_parts = 0;unsigned long window_addr;unsigned long window_size;/* Default flash buswidth */alchemy_map.bankwidth = BOARD_FLASH_WIDTH;window_addr = 0x20000000 - BOARD_FLASH_SIZE;window_size = BOARD_FLASH_SIZE;#ifdef CONFIG_MIPS_MIRAGE_WHY/* Boot ROM flash bank only; no user bank */window_addr = 0x1C000000;window_size = 0x04000000;/* USERFS from 0x1C00 0000 to 0x1FC00000 */alchemy_partitions[0].size = 0x03C00000;#endif/** Static partition definition selection*/parts = alchemy_partitions;nb_parts = NB_OF(alchemy_partitions);alchemy_map.size = window_size;/** Now let's probe for the actual flash. Do it here since* specific machine settings might have been set above.*/printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n",alchemy_map.bankwidth*8);alchemy_map.virt = ioremap(window_addr, window_size);mymtd = do_map_probe("cfi_probe", &alchemy_map);if (!mymtd) {iounmap(alchemy_map.virt);return -ENXIO;}mymtd->owner = THIS_MODULE;add_mtd_partitions(mymtd, parts, nb_parts);return 0;}看看红色的区域,do_map_probe返回了一个mtd_info结构指针。

那么表明这个函数在正确找到你的驱动(cfi驱动)后会填好这个表把其中的读写函数等设置到正确的值,具体的实现放到以后分析吧,其中的一个map_info参数,我暂时没有完全读懂,因为我以前不曾研究flash的底层驱动,你需要设置好bankwidth和基地址,和驱动名字,我只能通过一些信息猜测他用来管理这个主分区并给底层驱动使用的,如坏块信息就保存在这里。