linux4.3.2 块设备驱动简析

嵌入式技术

1372人已加入

描述

最近比较闲,准备玩玩xilinx的SoC,但又由于预算不够,买不起ZedBoard,所以最后入手了Z-Turn这块板子。它是米尔科技设计的,板子整体是蛮漂亮的,就是软资源不足——不能很好地玩转啊,这是个硬伤。过年在家,闲的无聊,就准备研究一下以前 一直想了解的linux中块设备的驱动架构,好吧扯了很多废话,让我们进入正题吧。

z-turn这块板子上,系统可以从SPI flash或者TF卡中启动,我们来看一下它的uboot env中与从tf卡启动的相关的部分(此处省去不相关的东西):root=/dev/mmcblk0p2。从此我们知道系统是从编号为0的块设备的part2区域去加载linux的根文件系统的,很多人可能理解为什么是编号为0的块设备,但可能会对为什么会是part2区域产生一定的疑惑。

对此,我是这样理解的:TF卡和电脑的硬盘一样,可以分成几个partions(C盘、D盘......)。在linux里面识别为 mmcblkxpy,其中x是mmc设备的编号,y是partion的编号。比如插入一块tf卡,识别为0号,就是mmcblk0。在本系统中具体分区如下图所示:

图1.1

可以看出TF卡分成了2个分区,第一个是fat32格式的文件系统分区,linux会识别为mmcblk0p1,第二个是ext4文件系统的分区,linux会识别为mmcblk0p2。一般来说没有特殊的软件支持,windows系统只识别第一个分区,不信话你可以吧TF通过读卡器,插到电脑上试试,是可以识别fat32的分区,也就是说,你是可以拷贝来更新uboot、linux等文件的。当然你如果使用专用的软件,你也可以去更新ext4文件系统,在本系统中ext4里面就是ubuntu。

好了,前戏结束了,让我们进一步跟进,开始讨论这个mmcblk0是怎么在内核中被注册。首先我们当然想到了函数(省去了具体代码):
int register_blkdev(unsigned int major, const char *name)
{
1. 从全局变量数组major_names找到一个是NULL(空闲)的成员
2. 通过参数major和那么,构造并初始化一个blk_major_name类型的对象p
3. 检查major_name中是否有major相同的,如果有就挑选出来,并把对象p填充到该数组中
}

大家可能发现了,注册了不也是什么功能都实现不了吗?对啊,很多注册函数本来就是这个样子,为了混个脸熟,占个位子嘛!

我们打开设备树文件linux-xlnx/arch/arm/boot/dts/zynq-7000.dtsi。通过搜索关键词sdhci,可以搜索到TF卡的设备驱动的节点部分,源码如下:
sdhci0: sdhci@e0100000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
clocks = , ;
interrupt-parent = ;
interrupts = ;
reg = ;
};
我们都知道,linux启动以后,系统过通过dts去生成各个设备驱动,并通过这些设备驱动去probe平台驱动,此处也是一样,它肯定对应了一个平台驱动,源码位于:linux-xlnx/drivers/mmc/host/sdhci-of-arasan.c。大家可能会疑问为什么是arasan,而不是xilinx呢?我查看了下,arasan这是一家可以提供各种SDIO、SPI等可以连接MMC/eMMC存储设备的接口的IP核的公司,xilixn估计就是用的它的IP核,毕竟方便易用好移植吗。

通过不停得追踪,发现此处注册一个设备驱动有如下的函数滴啊用关系:sdhci_arasan_probe->sdhci_add_host->mmc_add_host->device_add,顺利地把这个设备注册到了系统中。device_add?为什么不是device_register,该设备驱动驱动是在哪里被构造的?好回去继续找吧!函数调用关系如下:sdhci_arasan_probe->sdhci_pltfm_init->sdhci_alloc_host->mmc_alloc_host,就是这个函数里面构造了这个设备驱动;大家阅读的时候可能发现了,设备的是名字是"mmc%d",转换出来就是"mmc0","mmc1"......和设备"mmcblk0p2"有一毛钱关系啊,突然感觉失去了线索。但是想想我们这里也只是注册了一个mmc驱动,和block驱动还是很大的区别的吧!所以呢我觉得这应该就是个设备驱动,需要通过总线(应该就是MMC总线了)去match正真的驱动——块设备驱动。

在文件linux-xlnx/drivers/mmc/card/block.c中我找了函数mmc_blk_init,该函数被module_init引用,应该是驱动入口函数了,我们看看它具体是干嘛的。先通过register_blkdev(MMC_BLOCK_MAJOR, "mmc")注册了一个名字是mmc的块设备;接着通过mmc_register_driver(&mmc_driver)这个mmc设备驱动,这是里面最重要的函数。

int mmc_register_driver(struct mmc_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
return driver_register(&drv->drv);
}

主要就是吧该驱动注册到mmc总线上面去。再次通过层层追踪,发现mmc_blk_probe->mmc_blk_alloc->mmc_blk_alloc_req->snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), "mmcblk%d%s", md->name_idx, subname ? subname : "")将某设备的名字配置成了"mmcblk%d%s",终于找到它了。

我们简单概括一下以上的流程:
1. linux读取dts,获取各个设备
2. 匹配设备驱动,调用该设备驱动的probe程序,生成设备驱动inode文件
3. 该设备驱动通过总线去匹配正真的驱动文件,并调用该驱动的probe程序 ->在dev下生成了mmcblkXpY的inode文件
4. 该系统通过uboot的启动参数,获知需要从那个mmcblkXpY去加载根文件系统,去实现整个系统的初始化

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 相关推荐

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分