从总线模型谈SD/MMC架构
来源:互联网 发布:网络与新媒体就业 编辑:程序博客网 时间:2024/05/17 22:15
mmc总线:mmc_bus_type
mmc驱动结构体注册:mmc_register_driver函数。
mmc设备结构体注册:mmc_alloc_card和mmc_add_card函数。
1、匹配问题:
由于总线的匹配函数mmc_bus_match直接返回1:
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
根据总线模型:
driver_register
bus_add_driver
driver_attach(drv)
driver_probe_device
really_probe(dev, drv);
ret = dev->bus->probe(dev);
也就是:
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
return drv->probe(card); //调用驱动的probe
}
结论:就是把驱动和设备的匹配任务扔给了驱动来完成:really_probe函数调用总线的probe函数,返回0就会调用driver_bound(dev)函数吧驱动和设备进行绑定了。
这里很容易可以推导出mmc_card和mmc_driver 两者第一必须存在,第二mmc_card在drv->probe(card)调用返回值必须为0,这样就算mmc总线的设备和驱动绑定成功。
2、mmc_register_driver驱动注册:
static int __init mmc_blk_init(void) //属于块设备:
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); //将相应的块设备添加到数组中,主设备号、名称、指向下一个指针
res = mmc_register_driver(&mmc_driver);//这里会使用第一点的匹配,调用probe函数,这个函数就是块设备的核心函数mmc_blk_probe
调用probe函数:
mmc_blk_probe
md = mmc_blk_alloc(card); //mmc_blk_data结构体
md->disk = alloc_disk(1 << MMC_SHIFT);//分配gendisk结构
ret = mmc_init_queue(&md->queue, card, &md->lock);
mq->queue = blk_init_queue(mmc_request, lock); //请求队列,实现块读写操作
mq->thread = kthread_run (mmc_queue_thread, mq, "mmcqd"); //线程,负责处理请求队列的请求
mmc_set_drvdata(card, md);
add_disk(md->disk); //注册,到这里就可以通过队列来实现块设备的读写操作
对于上面mmc_blk_probe的传入参数是mmc_card,基于这个结构体进行,所以得看看这个结构体如何产生的
3、mmc设备结构体注册:mmc_alloc_card和mmc_add_card函数:
SD/MMC卡设备注册这一方比较麻烦,根据协议要注册设备前需要经过一些列初始化和检测之类的操作,之后这些满足了才有条件注册,我们把这个整个过程称为设备探测函数。对于6410开发板而言就是s3cmci_probe函数,实现部分放在host目录下。
s3cmci_probe函数的调用又要使用到另一个驱动模型:平台总线。
通过平台设备把6410关于MMC控制器的硬件寄存器、中断号注册入内核,所以这部分是和硬件息息相关。
s3cmci_probe函数任务:1、获取平台设备硬件信息、2、通过mmc_alloc_host函数实现把mmc_card注册到(核心层)内核,这样又会触动MMC总线模型的匹配和MMC驱动的probe函数调用,也就是前面的内容。
其中对于硬件资源获取和普通平台总线模型一样,就是获取寄存器地址、中断号、注册中断、时钟、DMA通道等。
现在看看mmc_alloc_host函数实现:
mmc_alloc_host
mmc_rescan
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
return;//当前卡是否有插入,没有返回
mmc_go_idle(host); //放CM0,进入IDEL状态
err = mmc_send_io_op_cond(host, 0, &ocr); //判断卡类型
if (!err) {
//SDIO卡
}
err = mmc_send_app_op_cond(host, 0, &ocr);
if (!err) {
//SD卡
}
err = mmc_send_op_cond(host, 0, &ocr);
if (!err) {\
//MMC卡
}
判断卡类型之后就调用mmc_attach_sXX(host, ocr)函数来初始化对应的卡。MMC卡对应于mmc_attach_mmc函数。
下面根据协议来初始化卡:
mmc_attach_mmc
mmc_init_card
1、mmc_go_idle(host);\\进入IDEL
2、mmc_send_op_cond; \\ACMD41,进入ready状态
。。。//根据MMC卡初始化发命令,具体可参考http://wenku.baidu.com/view/457131c3d5bbfd0a795673bd.html
mmc_add_card //把mmc_card设备结构体注册到MMC总线,这个就回到前面,会匹配MMC驱动了。
上面都是基于SD卡已经接到开发板了,如果卡是后来才插入的呢?
那就得靠中断来实现了,但是我们可以猜想中断处理函数一定会调用到mmc_rescan函数(区分卡类型、初始化卡、注册卡设备到MMC总线)。
中断处理函数在哪里?前面说过平台驱动s3cmci_probe有说到了负责中断注册.
s3cmci_irq_cd中断处理函数:
s3cmci_irq_cd(int irq, void *dev_id)
mmc_detect_change(host->mmc, msecs_to_jiffies(500));
mmc_schedule_delayed_work(&host->detect, delay);//在mmc_alloc_host函数里INIT_DELAYED_WORK(&host->detect, mmc_rescan);所以这里调用mmc_rescan。
最后一个问题,设备节点在哪里产生的?
猜想:驱动和设备匹配成功后产生,并且在负责(块设备)驱动那一方负责产生.用户空间操作设备节点就是操作块设备节点,然后块设备节点才来调用设备这边实现的操作函数。
mmc_blk_probe
add_disk(md->disk);
bdi_register_dev(bdi, disk_devt(disk));
dev = device_create_vargs(bdi_class, parent, MKDEV(0, 0), bdi, fmt, args);
总结一下:
对于MMC/SD卡而言分为了三个目录:card\Host\Core。
card目录一看就知道和块设备操作有关,所以这个目录负责SD卡的块设备驱动注册;
接着就剩下Core目录和Host目录,Core目录实现了MMC\SDIO\MMC卡的底层操作以及命令发送之类的,主要还有一个就是MMC总线设备模型也是在这个目录下的BUS文件实现,还有一个core文件实现了SD/SDIO/MMC的协议。
而Host就是我们的MMC/SD控制器了,所有的协议都是一种约定,最底层还是需要硬件来搭建起来,这方面就是交给了Host来实现。
所以我们呢可以猜想:块设备那一层会得到用户的操作请求,这个请求要经过核心层,因为核心层才知道如何根据SD/MMC协议来实现用户的请求,和核心层的要实现协议里的每一条数据或者命令都是依靠低层Host来实现。
总线模型总结:首先是MMC总线,该总线的注册在core.c文件完成,MMC的驱动注册在block.c文件,MMC的设备注册有个前提,那就是在一个平台驱动里注册s3cmci_probe,这个驱动是SD/MMC的主机控制器。所以MMC/SD的设备层实际是MMC/SD的主机控制层。
1、在平台设备上把6410芯片手册的关于MMC/SD的操作寄存器和中断号封装为平台设备注册入内核;
2、内核有个平台驱动会根据平台总线去匹配平台设备,匹配成功调用平台驱动的probe函数,例如s3cmci_probe;
3、在s3cmci_probe函数里获取主机控制器的硬件资源填充mmc_host结构体,并且通过mmc_alloc_host函数,会间接调用mmc_rescan函数来勘测设备是否存在,如果不存在:
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
如果存在:调用mmc_attach_mmc函数初始化MMC卡,并会间接调用mmc_add_card函数注册MMC的设备。
4、如果注册MMC总线的设备,又会触发MMC总线匹配MMC的驱动链表,进而调用MMC的驱动来完成块设备的初始化。
当开发板没有MMC卡:
MMC设备不会被注册到MMC总线上,原因:
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
当开发板有MMC卡:
如果系统刚启动:那么就会通过s3cmci_probe-->mmc_rescan-->mmc_attach_mmc-->mmc_add_card;
如果系统已经启动:产生中断s3cmci_irq_cd-->host->detect(mmc_rescan)-->mmc_attach_mmc-->mmc_add_card;
- 从总线模型谈SD/MMC架构
- 从总线模型看IIC架构
- 从总线模型看USB架构
- sd/mmc驱动总线函数指针解析
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- 关于linux mmc/sd驱动程序架构
- SD/MMC
- [sd card] mmc硬件总线扫描流程(以sd card为例)
- linux设备模型之mmc,sd子系统<一>
- linux设备模型之mmc,sd子系统<二>
- linux设备模型之mmc,sd子系统<三>
- Linux设备驱动程序架构分析之MMC/SD(一)
- NetBeans 7.x 安装Python插件的方法
- 百度 2014 校园招聘 软件研发工程师 笔试题(天津站)
- thrift介绍及应用(四)—hadoop的thrift接口
- [JNI] How to get the java's native method body?
- c++中map的基本用法和嵌套用法
- 从总线模型谈SD/MMC架构
- 应用商店低级混战:360建议用户卸载小米应用商店,双方发声明隔空交火
- uva 10599 - Robots(II)(LIS)
- myeclipse 编辑页面的时候自动提示功能
- 从零开始学WCF(5)生成客户端
- ios仿EGORefreshTableHeaderView上提下拉翻页插件
- ubuntu 13.04 普通用户丢失sudo权限后的恢复办法
- MySQL 连接问题
- Android度量单位说明(DIP,DP,PX,SP)