mmc整体架构

来源:互联网 发布:如何修改路由器mac地址 编辑:程序博客网 时间:2024/03/29 13:13
Mmc Controller Driver  。
看了这篇文章文章对sd卡的驱动有了一个整体的了解。

linux-2.6.2x的mmc驱动与linux-2.6.1x的mmc驱动的区别
在linux-2.6.2x中,mmc驱动用到的block_device_operations结构已重新定义,请看:
linux-2.6.1x:

struct block_device_operations {    int (*open) (struct inode *, struct file *);    int (*release) (struct inode *, struct file *);    int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);    int (*media_changed) (struct gendisk *);    int (*revalidate_disk) (struct gendisk *);    struct module *owner;};

linux-2.6.2x

struct block_device_operations {    int (*open) (struct inode *, struct file *);    int (*release) (struct inode *, struct file *);    int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);    long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);    long (*compat_ioctl) (struct file *, unsigned, unsigned long);    int (*direct_access) (struct block_device *, sector_t, unsigned long *);    int (*media_changed) (struct gendisk *);    int (*revalidate_disk) (struct gendisk *);    int (*getgeo)(struct block_device *, struct hd_geometry *);    struct module *owner;};

注意到新版本的block驱动接口结构增加了gntgeo成员,使调用者可以直接调用此函数获得设备的几何结构。

工作流程:
mmc驱动主要文件包括
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/
内核启动时,首先执行core/core.c的mmc_init,注册mmc、sd总线,以及一个host class设备。接着执行card/block.c中,申请一个块设备。

数据结构:
mmc总线操作相关函数,由于mmc卡支持多种总数据线,如SPI、SDIO、8LineMMC,而不同的总线的操作控制方式不尽相同,所以通过此结构与相应的总线回调函数相关联。

//总线操作结构struct mmc_bus_ops {    void (*remove)(struct mmc_host *);    void (*detect)(struct mmc_host *);    int (*sysfs_add)(struct mmc_host *, struct mmc_card *card);    void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card);    void (*suspend)(struct mmc_host *);    void (*resume)(struct mmc_host *);};//  mmc卡的总线操作 core/mmc.cstatic const struct mmc_bus_ops mmc_ops = {    .remove = mmc_remove,    .detect = mmc_detect,    .sysfs_add = mmc_sysfs_add,    .sysfs_remove = mmc_sysfs_remove,    .suspend = mmc_suspend,    .resume = mmc_resume,};// sd卡的总线操作 core/sd.cstatic const struct mmc_bus_ops mmc_sd_ops = {    .remove = mmc_sd_remove,    .detect = mmc_sd_detect,    .sysfs_add = mmc_sd_sysfs_add,    .sysfs_remove = mmc_sd_sysfs_remove,    .suspend = mmc_sd_suspend,    .resume = mmc_sd_resume,};// sdio的总线操作 core/sdio.cstatic const struct mmc_bus_ops mmc_sdio_ops = {    .remove = mmc_sdio_remove,    .detect = mmc_sdio_detect,};

关于总线操作的函数:
.detect,驱动程序经常需要调用此函数去检测mmc卡的状态,具体实现是发送CMD13命令,并读回响应,如果响应错误,则依次调用.remove、detach_bus来移除卡及释放总线。

总体架构:
kernel启动时,先后执行mmc_init()及mmc_blk_init(),以对mmc设备及mmc块模块进行初始化。
然后在挂载mmc设备驱动时,执行驱动程序中的xx_mmc_probe(),检测host设备中挂载的sd设备。此时probe函数会创建一个host设备,然后开启一个延时任务mmc_rescan()。
驱动挂载成功后,mmc_rescan()函数被执行,然后对卡进行初始化(步骤后面详细讲述)。
假如扫描到总线上挂有有效的设备,就调用相对应的函数把设备装到系统中,mmc_attach_sdio()、mmc_attach_sd()、mmc_attach_mmc()这三个函数分别是装载sdio设备,sd卡和mmc卡的。
在sd卡中,驱动循环发送ACMD41、CMD55给卡,读取OCR寄存器,成功后,依次发送CMD2(读CID)、CMD3(得到RCA)、 CMD9(读CSD)、CMD7(选择卡)。后面还有几个命令分别是ACMD41&CMD51,使用CMD6切换一些功能,如切换到高速模式。
经过上述步骤,已经确定当前插入的卡是一张有效、可识别的存储卡。然后调用mmc_add_card()把存储卡加到系统中。正式与系统驱动连接在一起。
卡设备加到系统中后,通知mmc块设备驱动。块设备驱动此时调用probe函数,即mmc_blk_probe()函数,mmc_blk_probe() 首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程 mmc_queue_thread()。

mmc_rescan:mmc_rescan()函数是在驱动装载的时候,由驱动xx_mmc_probe()调用 mmc_alloc_host()时启动的一个延时任务。 xx_mmc_probe()->mmc_alloc_host()->INIT_DELAYED_WORK(&host->detect, mmc_rescan);

core部分
1、取得总线
2、检查总线操作结构指针bus_ops,如果为空,则重新利用各总线对端口进行扫描,检测顺序依次为:SDIO、Normal SD、MMC。当检测到相应的卡类型后,就使用mmc_attach_bus()把相对应的总线操作与host连接起来。

void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops){    ...    host->bus_ops = ops;    ...}

3、初始化卡接以下流程初始化:
a、发送CMD0使卡进入IDLE状态
b、发送CMD8,检查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先发送CMD8,如响应为无效命令,则卡为SD1.1,否则就是SD2.0(请参考SD2.0 Spec)。
c、发送CMD5读取OCR寄存器。
d、发送ACMD55、CMD41,使卡进入工作状态。MMC卡并不支持ACMD55、CMD41,如果这步通过了,则证明这张卡是SD卡。
e、如果d步骤错误,则发送CMD1判断卡是否为MMC。SD卡不支持CMD1,而MMC卡支持,这就是SD和MMC类型的判断依据。
f、如果ACMD41和CMD1都不能通过,那这张卡恐怕就是无效卡了,初始化失败。


原创粉丝点击