ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

mmc驱动代码分析(未完待续)

2021-04-05 21:59:20  阅读:553  来源: 互联网

标签:blk 代码 driver 未完待续 host mmc sdhci s3c


mmc驱动代码分析(未完待续)

参考资料

先附上参考资料,也方便自己查询。

原理性的知识就不做分析了,参考资料里的大佬分析得都很好。

蜗窝科技网站的mmcemmc相关的文章,Linux Kernel Internals

Hacker_Albert博客mmc相关的文章。

Linux设备驱动开发详解-基于最新的Linux 4.0内核》–宋宝华 编著

mmc驱动代码分析(未完待续)

本文章的分析基于linux-4.9.259版本内核,可通过163镜像站下载linux-4.9.259.tar.xz

MMC/SD存储卡的驱动位于内核源码的目录drivers/mmc下,下面又分为card、core、host3个子目录。card层实际上跟Linux的块设备子系统对接,实现块设备驱动以及完成请求,但是具体的协议经过core层的接口,最终通过host完成传输,因此整个MMC子系统的框架如下图所示。card目录除实现标准的MMC/SD存储卡以外,还包含一些SDIO外设和驱动。core目录除了给card提供接口外,也定义好了host驱动的框架。

在这里插入图片描述

上图MMC子系统的框架是通过Fedora33系统的LibreOffice Draw软件画的,谁说Linux只有字符界面,画图,视频,什么都行。

card/block.c 文件 的mmc_blk_init初始化块设备,通过

res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");

注册块设备。再通过

res = mmc_register_driver(&mmc_driver);

向core层注册mmc驱动。

其中mmc_driver结构体有2个重要成员函数,mmc_blk_probe函数是在检测到mmc卡插入时执行,mmc_blk_remove函数是在mmc卡移除时执行。

static struct mmc_driver mmc_driver = {
    .drv        = {  
        .name   = "mmcblk",
        .pm = &mmc_blk_pm_ops,
    },   
    .probe      = mmc_blk_probe,
    .remove     = mmc_blk_remove,
    .shutdown   = mmc_blk_shutdown,
};

core/bus.c文件下的mmc_bus_probe调用mmc_blk_probe

static struct bus_type mmc_bus_type = {
    .name       = "mmc",
    .dev_groups = mmc_dev_groups,
    .match      = mmc_bus_match,
    .uevent     = mmc_bus_uevent,
    .probe      = mmc_bus_probe,
    .remove     = mmc_bus_remove,
    .shutdown   = mmc_bus_shutdown,
    .pm     = &mmc_bus_pm_ops,
}; 

mmc_bus_type的分析 TODO

函数调用顺序为:mmc_blk_probe-> mmc_blk_alloc-> mmc_blk_alloc_req-> mmc_init_queue

mmc_blk_alloc_req函数中,通过

md->disk->fops = &mmc_bdops;

指定块设备操作的函数,当应用层执行open、close、ioctl等操作时调用相应的接口:

static const struct block_device_operations mmc_bdops = {
    .open           = mmc_blk_open,
    .release        = mmc_blk_release,
    .getgeo         = mmc_blk_getgeo,
    .owner          = THIS_MODULE,
    .ioctl          = mmc_blk_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl       = mmc_blk_compat_ioctl,
#endif
};

mmc_init_queue中通过

mq->queue = blk_init_queue(mmc_request_fn, lock);

绑定了请求处理函数mmc_request_fn。再通过

mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", host->index, subname ? subname : "");

运行mmc对应的内核线程mmc_queue_thread

当应用层调用read,write等接口时,mmc_request_fn函数会唤醒mmc对应的内核线程mmc_queue_thread来处理请求。mmc对应的内核线程mmc_queue_thread执行mmc_blk_issue_rq函数,mmc_blk_issue_rq函数再调用mmc_blk_issue_rw_rqmmc_blk_issue_rw_rq函数最终会调用core层的mmc_start_req函数。

mmc_start_req函数里调用host驱动的mmc_host_ops成员函数(位于文件host/sdhci.c):

static const struct mmc_host_ops sdhci_ops = {
    .request    = sdhci_request,
    .post_req   = sdhci_post_req,
    .pre_req    = sdhci_pre_req,
    .set_ios    = sdhci_set_ios,
    .get_cd     = sdhci_get_cd,
    .get_ro     = sdhci_get_ro,
    .hw_reset   = sdhci_hw_reset,
    .enable_sdio_irq = sdhci_enable_sdio_irq,
    .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
    .prepare_hs400_tuning       = sdhci_prepare_hs400_tuning,
    .execute_tuning         = sdhci_execute_tuning,
    .select_drive_strength      = sdhci_select_drive_strength,
    .card_event         = sdhci_card_event,
    .card_busy  = sdhci_card_busy,
};

接下来以Samsung SoC平台为例子分析host driver(文件host/sdhci-s3c.c):

注册platfom驱动:

static struct platform_driver sdhci_s3c_driver = { 
    .probe      = sdhci_s3c_probe,
    .remove     = sdhci_s3c_remove,
    .id_table   = sdhci_s3c_driver_ids,
    .driver     = { 
        .name   = "s3c-sdhci",
        .of_match_table = of_match_ptr(sdhci_s3c_dt_match),
        .pm = &sdhci_s3c_pmops,
    },  
};

module_platform_driver(sdhci_s3c_driver);

当设备和驱动匹配时调用sdhci_s3c_driver中的成员函数sdhci_s3c_probe

sdhci_s3c_probe函数先初始化参数,其中sdhci_s3c_opssdhci_ops类型,是host driver要实现的核心内容,由于各个host的硬件有所差异,所以实际和硬件交互的驱动部分还是在host driver中实现:

static struct sdhci_ops sdhci_s3c_ops = {
    .get_max_clock      = sdhci_s3c_get_max_clk,
    .set_clock      = sdhci_s3c_set_clock,
    .get_min_clock      = sdhci_s3c_get_min_clock,
    .set_bus_width      = sdhci_s3c_set_bus_width,
    .reset          = sdhci_reset,
    .set_uhs_signaling  = sdhci_set_uhs_signaling,
};

sdhci_s3c_probe函数最后调用sdhci_add_host注册sdhci_host,在注册之前已经设置的信息有:sdhci的寄存器的映射过后的基地址、quirks、quirks2、中断号、提供给sdhci core用来操作硬件的操作函数 等。

上面讲到的mmc_start_req函数调用Samsung SoC平台的sdhci_s3c_ops成员函数(通过struct mmc_host_ops sdhci_ops里的成员函数调用)。

标签:blk,代码,driver,未完待续,host,mmc,sdhci,s3c
来源: https://blog.csdn.net/lion544301/article/details/115447673

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有