Linux内核MTD驱动程序与SD卡驱动程序.docx
- 文档编号:26610598
- 上传时间:2023-06-20
- 格式:DOCX
- 页数:208
- 大小:1.22MB
Linux内核MTD驱动程序与SD卡驱动程序.docx
《Linux内核MTD驱动程序与SD卡驱动程序.docx》由会员分享,可在线阅读,更多相关《Linux内核MTD驱动程序与SD卡驱动程序.docx(208页珍藏版)》请在冰豆网上搜索。
Linux内核MTD驱动程序与SD卡驱动程序
Linux内核MTD驱动程序与SD卡驱动程序
flash闪存设备和SD插卡设备是嵌入式设备用到的主要存储设备,它们相当于
PC机的硬盘。
在嵌入设备特别是手持设备中,flash闪存是焊接在嵌入设备主板
上的flash闪存芯片。
在嵌入设备上有MMC/SD卡控制器及插槽,可通过MMC/SD
来扩充存储空间。
嵌入设备的存储设备的空间划分及所有逻辑设备和文件系统示例列出如下图:
图:
嵌入设备的存储空间划分及文件系统示例图
在嵌入设备上的flash芯片上blob和zImage直接按内存线性地址存储管理,对于flash芯片上留出的供用户使用的存储空间,使用MTDBLOCK块设备和JFFS2文件系统。
对于flash芯片的分区表信息则以MTDCHAR字符设备来存储管理。
在嵌入设备上的MMC/SD插卡则由MMCBLOCK驱动程序和VFAT文件系统进行存储管理。
本章分析了MTD设备和MMC/SD驱动程序。
Figure3-1.UBI/MTDIntegration
[隐藏]
1MTD内存技术设备
o1.1MTD内存技术设备层次结构
o1.2设备层和原始设备层的函数调用关系
o1.3MTD相关结构
o1.4MTD块设备初始化
o1.5MTD块设备的读写操作
o1.6MTD核心初始化
o1.7MTD字符设备
o1.8具体flash芯片的探测及映射
o1.9驱动程序实例分析
2SD/MMC卡块设备驱动程序
o2.1MMC抽象设备层相关结构
2.1.1
(1)设备描述结构
2.1.2
(2)读写请求相关结构
o2.2MMC抽象设备层MMC块设备驱动程序
2.2.1
(1)MMC块设备驱动程序初始化
2.2.2
(2)MMC块设备驱动程序探测函数
2.2.3(3)MMC卡请求的处理
o2.3具体MMC控制器驱动程序示例
2.3.1
(1)amba控制器驱动程序相关结构
2.3.2
(2)amba控制器的初始化
2.3.3(3)设备探测函数mmci_probe
2.3.4(4)amba控制器操作函数
MTD内存技术设备
Linux中MTD子系统在系统的硬件驱动程序和文件系统之间提供通用接口。
在MTD上常用的文件文件系统是JFFS2日志闪存文件系统版本2(JournalingFlash
FileSystem)。
JFFS2用于微型嵌入式设备的原始闪存芯片的文件系统。
JFFS2文件系统是日志结构化的,这意味着它基本上是一长列节点。
每个节点包含有关文件的部分信息―可能是文件的名称、也许是一些数据。
与Ext2文件系统相比,JFFS2因为有以下这些优点:
JFFS2在扇区级别上执行闪存擦除/写/读操作要比Ext2文件系统好。
JFFS2
提供了比Ext2fs更好的崩溃/掉电安全保护。
当需要更改少量数据时,Ext2文
件系统将整个扇区复制到内存(DRAM)中,在内存中合并新数据,并写回整个扇
区。
这意味着为了更改单个字,必须对整个扇区(64KB)执行读/擦除/写例
程,这样做的效率非常低。
JFFS2是附加文件而不是重写整个扇区,并且具有
崩溃/掉电安全保护这一功能。
JFFS2是是为FLASH定制的文件系统,JFFS1实现了日志功能,JFFS2实现了压
缩功能。
它的整个设计提供了更好的闪存管理。
JFFS2的缺点很少,主要是当文件系统已满或接近满时,JFFS2会大大放慢运行速度。
这是因为垃圾收集的问题。
MTD驱动程序是专门为基于闪存的设备所设计的,它提供了基于扇区的擦除和读写操作的更好的接口。
MTD子系统支持众多的闪存设备,并且有越来越多的驱动程序正被添加进来以用于不同的闪存芯片。
MTD子系统提供了对字符设备MTD_CHAR和块设备MTD_BLOCK的支持。
MTD_CHAR
提供对闪存的原始字符访问,象通常的IDE硬盘一样,在MTD_BLOCK块设备上可
创建文件系统。
MTD_CHAR字符设备文件是/dev/mtd0、mtd1、mtd2等,MTD_BLOCK
块设备文件是/dev/mtdblock0、mtdblock1等等。
NAND和NOR是制作Flash的工艺,CFI和JEDEC是flash硬件提供的接口,linux通过这些用通用接口抽象出MTD设备。
JFFS2文件系统就建立在MTD设备上。
NORflash带有SRAM接口,可以直接存取内部的每一个字节。
NAND器件使用串
行I/O口来存取数据,8个引脚用来传送控制、地址和数据信息。
NAND读和写操作用512字节的块。
MTD内存技术设备层次结构
MTD(memorytechnologydevice内存技术设备)在硬件和文件系统层之间的提供了一个抽象的接口,MTD是用来访问内存设备(如:
ROM、flash)的中间层,它将内存设备的共有特性抽取出来,从而使增加新的内存设备驱动程序变得更简单。
MTD的源代码都在/drivers/mtd目录中。
MTD中间层细分为四层,按从上到下依次为:
设备节点、设备层和硬件驱动层。
MTD中间层层次结构图如下:
MTD设备层、MTD原始
图1MTD中间层层次结构图
Flash硬件驱动层对应的是不同硬件的驱动程序,符合CFI接口标准的Flash芯片驱动驱动程序在NAND型Flash的驱动程序在/drivers/mtd/nand
它负责驱动具体的硬件。
例如:
drivers/mtd/chips目录中,中。
在原始设备层中,各种内存设备抽象化为原始设备,原始设备实际上是一种块设备,MTD字符设备的读写函数也调用原始设备的操作函数来实现。
MTD使用MTD信息结构mtd_info来描述了原始设备的操作函数、各种信息,所有原始设备的
信息也用一个全局的结构数组来描述,列出如下(在drivers/mtd/mtdcore.c中):
structmtd_info*mtd_table[MAX_MTD_DEVICES];
每个原始设备可能分成多个设备分区,设备分区是将一个内存分成多个块,每个设备分区用一个结构mtd_part来描述,所有的分区组成一个链表
mtd_partitions,这个链表的声明列出如下(在drivers/mtd/mtdpart.c中):
/*Ourpartitionlinkedlist*/
staticLIST_HEAD(mtd_partitions);
MTD原始设备到具体设备之间存在的一些映射关系数据在drivers/mtd/maps/目录下的对应文件中。
这些映射数据包括分区信息、I/O映射及特定函数的映射等。
这种映射关系用映射信息结构map_info描述。
在MTD设备层中,MTD字符设备
通过注册的fileoperation函数集来操作设备,而这些函数是通过原始设备层的操作函数来实现的,即调用了块设备的操作函数。
MTD块设备实际了从块层到块设备的接口函数。
所有的块设备组成一个数组*mtdblks[MAX_MTD_DEVICES],
这个结构数组列出如下(在drivers/mtd/mtdblock.c中):
staticstructmtdblk_dev{
structmtd_info*mtd;
intcount;
structsemaphorecache_sem;
unsignedchar*cache_data;
unsignedlongcache_offset;
unsignedintcache_size;
enum{STATE_EMPTY,STATE_CLEAN,STATE_DIRTY}cache_state;}*mtdblks[MAX_MTD_DEVICES];
由于flash设备种类的多样性,MTD用MTD翻译层将三大类flash设备进行的封
装。
每大类设备有自己的操作函数集,它们的mtdblk_dev结构实例都存在mtdblks数组中。
MTD设备在内核中的层次图如下图。
图MTD设备在内核中的层次图
MTD原始设备层中封装了三大类设备,分别是InverseFlash、NANDFlash和MTD。
它们的上体读写方法不一样。
这里只分析了MTD,因为它是最常用的。
设备层和原始设备层的函数调用关系
原始设备层主要是通过mtd_info结构来管理设备,函数add_mtd_partitions()
和del_mtd_partitions()将的设备分区的mtd_info结构加入mtd_table数组中,mtdpart.c中还实现了part_read、part_write等函数,这些函数注册在每个分区中,指向主分区的read、write函数,之所以这样做而不直接将主分区的
read、write函数连接到每个分区中的原因是因为函数中的参数mtd_info会被调用者置为函数所属的mtd_info,即mtd->read(mtd,),而参数mtd_info其实应该指向主分区。
设备层和原始设备层的函数调用关系图如图2。
MTD各种结构之间的关系图如图3。
图2设备层和原始设备层的函数调用关系
图3MTD各种结构之间的关系
MTD相关结构
MTD块设备的结构mtdblk_dev代表了一个闪存块设备,MTD字符设备没有相对应的结构。
结构mtdblk_dev列出如下:
structmtdblk_dev{
structmtd_infomtd;/Locked*/
下层原始设备层的
MTD设备结构
intcount;
structsemaphorecache_sem;
unsignedchar*cache_data;//缓冲区数据地址
unsignedlongcache_offset;//在缓冲区中读写位置偏移
//缓冲区中的读写数据大小(通常被设置为MTD设备的erasesize)
unsignedintcache_size;
enum{STATE_EMPTY,STATE_CLEAN,STATE_DIRTY}cache_state;//缓冲区状态
}
结构mtd_info描述了一个MTD原始设备,每个分区也被实现为一个mtd_info,
如果有两个MTD原始设备,每个上有三个分区,在系统中就一共有6个mtd_info
结构,这些mtd_info的指针被存放在名为mtd_table的数组里。
结构mtd_info分析如下:
structmtd_info{
u_chartype;
//内存技术的类型
u_int32_tflags;
//标志位
u_int32_tsize;
//mtd
设备的大小
//“主要的”erasesize(同一个mtd设备可能有数种不同的erasesize)u_int32_terasesize;
u_int32_toobblock;//oob块大小,例如:
512
u_int32_toobsize;//
每个块
oob数据量,例如
16
u_int32_tecctype;
//ecc
类型
u_int32_teccsize;
//自动
ecc可以工作的范围
//Kernel-onlystuffstartshere.char*name;
intindex;
//可变擦除区域的数据,如果是0,意味着整个设备为erasesize
intnumeraseregions;//不同erasesize的区域的数目(通常是1)
structmtd_erase_region_info*eraseregions;
u_int32_tbank_size;
structmodule*module;
//此routine用于将一个erase_info加入erasequeueint(*erase)(structmtd_info*mtd,structerase_info*instr);
/*ThisstuffforeXecute-In-Place*/
int(*point)(structmtd_info*mtd,loff_tfrom,size_tlen,
size_t*retlen,u_char**mtdbuf);
/*Weprobablyshouldn’tallowXIPiftheunpointisn
’taNULL
*/
void(*unpoint)(structmtd_info*mtd,u_char*addr);int(*read)(structmtd_info*mtd,loff_tfrom,size_tlen,
size_t*retlen,u_char*buf);
int(*write)(structmtd_info*mtd,loff_tto,size_tlen,size_t*retlen,constu_char*buf);
int(*read_ecc)(structmtd_info*mtd,loff_tfrom,
size_tlen,size_t*retlen,u_char*buf,u_char
*eccbuf);
int(*write_ecc)(structmtd_info*mtd,loff_tto,size_tlen,size_t*retlen,constu_char*buf,u_char*eccbuf);
int(*read_oob)(structmtd_info*mtd,loff_tfrom,size_tlen,size_t*retlen,u_char*buf);
int(*write_oob)(structmtd_info*mtd,loff_tto,size_tlen,size_t*retlen,constu_char*buf);
/*iovec-basedread/writemethods.WeneedtheseespeciallyforNANDflash,
withitslimitednumberofwritecyclespererase.
NB:
The‘count’parameteristhenumberofvectors,eachof
whichcontainsan(ofs,len)tuple.
*/
int(*readv)(structmtd_info*mtd,structiovec*vecs,unsignedlongcount,loff_tfrom,size_t*retlen);
int(*writev)(structmtd_info*mtd,conststructiovec*vecs,unsignedlongcount,loff_tto,size_t*retlen);
/*Sync*/
void(*sync)(structmtd_info*mtd);
/*Chip-supporteddevicelocking*/
int(*lock)(structmtd_info*mtd,loff_tofs,size_tlen);int(*unlock)(structmtd_info*mtd,loff_tofs,size_tlen);/*PowerManagementfunctions*/
int(*suspend)(structmtd_info*mtd);
void(*resume)(structmtd_info*mtd);
void*priv;//指向map_info结构
}
设备层的mtdblcok设备的notifier声明如下:
staticstructmtd_notifiernotifier={
mtd_notify_add,
mtd_notify_remove,
NULL
};
mtd_part结构是用于描述MTD原始设备分区的,结构mtd_part中的list成员
链成一个链表mtd_partitons。
每个mtd_part结构中的mtd_info结构用于描述
本分区,被加入mtd_table数组中,其中mtd_info结构大部分成员由其主分区
mtd_part->master决定,各种函数也指向主分区的相应函数。
结构mtd_part
列出如下:
/*Ourpartitionlinkedlist*/
staticLIST_HEAD(mtd_partitions);
MTD原始设备分区
的链表
structmtd_part{
structmtd_infomtd;
//分区的信息(大部分由其
master
决定)
structmtd_info*master;
u_int32_toffset;
intindex;
structlist_headlist;
//该分区的主分区
//该分区的偏移地址
//分区号
};
结构mtd_partition描述mtd设备分区的结构,在MTD原始设备层调用函数add_mtd_partions时传递分区信息使用。
结构列出如下(在
include/linux/mtd/partition.h
中):
structmtd_partition{
char*name;
u_int32_tsize;
//分区名
//分区大小
u_int32_toffset;
//在主
MTD空间的偏移
u_int32_tmask_flags;
};
MTD块设备初始化
图函数init_mtdblock调用层次图
在具体的设备驱动程序初始化时,它会添加一个MTD设备结构到mtd_table数组中。
MTD翻译层通过查找这个数组,可访问到各个具体设备驱动程序。
函数init_mtdblock注册一个MTD翻译层设备,初始化处理请求的线程,赋上MTD翻译层设备操作函数集实例,注册这个设备的通用硬盘结构。
函数
init_mtdblock调用层次图如上图。
mtd块设备驱动程序利用一个线程,当有读写请求时,从缓冲区将数据写入块设备或从块设备读入到缓冲区中。
函数init_mtdblock分析如下(在drivers/mtd/mtdblock.c中):
staticint__initinit_mtdblock(void)
{
returnregister_mtd_blktrans(&mtdblock_tr);
}
MTD翻译层设备操作函数集实例列出如下:
staticstructmtd_blktrans_opsmtdblock_tr={
.name
.major
.part_bits
.open
.flush
.release
.readsect
.writesect
.add_mtd
=“mtdblock”,
=31,
=0,
=mtdblock_open,
=mtdblock_flush,
=mtdblock_release,
=mtdblock_readsect,
=mtdblock_writesect,
=mtdblock_add_mtd,
.remove_dev
=mtdblock_remove_dev,
.owner
=THIS_MODULE,
};
staticLIST_HEAD(blktrans_majors);
intregister_mtd_blktrans(structmtd_blktrans_ops*tr)
{
intret,i;
//如果第一个设备类型被注册了,注册notifier来阻止/*Registerthenotifierif/whenthefirstdevicetypeisregistered,topreventthelink/initorderingfromfucking
usover.*/
if(!
blktrans_notifier.list.next)//如果不存在
//注册MTD翻译层块设备,创建通用硬盘结构并注册
register_mtd_user(&blktrans_notifier);tr->blkcore_priv=kmalloc(sizeof(*tr->blkcore_priv),
GFP_KERNEL);
if(!
tr->blkcore_priv)
return-ENOMEM;
memset(tr->blkcore_priv,0,sizeof(*tr->blkcore_priv));down(&mtd_table_mutex);
//创建blk_major_name结构初始化后加到&major_names[]数组中ret=register_blkdev(tr->major,tr->name);
spin_lock_init(&tr->blkcore_priv->queue_lock);init_completion(&tr->blkcore_priv->thread_dead);init_waitqueue_head(&tr->blkcore_priv->thread_wq);
//创建请求队列并初始化,赋上块设备特定的请求处理函数mtd_blktrans
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 内核 MTD 驱动程序 SD