1、使用mmc子系统管理mmc,sd,sdio等设备;
2、mmc子系统涉及到的文件夹在driver/mmc下,包括core,host,card文件夹;
3、几个重要的结构体;
struct mmc_card;
struct mmc_driver;
struct mmc_host;
struct mmc_host_ops;
mmc核心层提供了一些接口
mmc core的入口
主要就是在执行mmc_init的时候,注册了mmc总线和sdio总线;
// drivers/mmc/core/core.c
2754 static int __init mmc_init(void)
2755 {
2756 int ret;
2758 workqueue = alloc_ordered_workqueue("kmmcd", 0);
2759 if (!workqueue)
2760 return -ENOMEM;
2762 mmc_of_reserve_idx();
2764 ret = mmc_register_bus();
2765 if (ret)
2766 goto destroy_workqueue;
2768 ret = mmc_register_host_class();
2769 if (ret)
2770 goto unregister_bus;
2772 ret = sdio_register_bus();
2773 if (ret)
2774 goto unregister_host_class;
2776 return 0;
2778 unregister_host_class:
2779 mmc_unregister_host_class();
2780 unregister_bus:
2781 mmc_unregister_bus();
2782 destroy_workqueue:
2783 destroy_workqueue(workqueue);
2785 return ret;
2786 }
对mmc host操作的接口
struct mmc_host;
203 struct mmc_host {
204 struct device *parent;
205 struct device class_dev; // 由此看,mmc_host是作为内核中的一个设备;
206 int index;
207 const struct mmc_host_ops *ops;
// ...
}
// 在drivers/mmc/core/host.c中提供了对mmc_host操作的一组接口
588 void mmc_free_host(struct mmc_host *host)
589 {
451 struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
452 {
564 void mmc_remove_host(struct mmc_host *host)
565 {
530 int mmc_add_host(struct mmc_host *host)
531 {
///
//
看看
mmc_add_host(struct mmc_host *host)
到底做了什么
530 int mmc_add_host(struct mmc_host *host)
531 {
532 int err;
534 WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
535 !host->ops->enable_sdio_irq);
// 加入内核设备管理
537 err = device_add(&host->class_dev);
538 if (err)
539 return err;
541 led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
543 #ifdef CONFIG_DEBUG_FS
544 mmc_add_host_debugfs(host);
545 #endif
546 mmc_host_clk_sysfs_init(host);
547
548 mmc_start_host(host); // 这里将会去调用扫描任务
549 register_pm_notifier(&host->pm_notify);
551 return 0;
552 }
554 EXPORT_SYMBOL(mmc_add_host);
对mmc card的接口
选择一个host分析
使用imx6的host
首先注册了一个platform设备驱动,这里会跟设备树或平台设备匹配;
// drivers/mmc/host/sdhci-esdhc-imx.c
static struct platform_driver sdhci_esdhc_imx_driver = {
1387 .driver = {
1388 .name = "sdhci-esdhc-imx",
1389 .owner = THIS_MODULE,
1390 .of_match_table = imx_esdhc_dt_ids,
1391 .pm = &sdhci_esdhc_pmops,
1392 },
1393 .id_table = imx_esdhc_devtype,
1394 .probe = sdhci_esdhc_imx_probe,
1395 .remove = sdhci_esdhc_imx_remove,
1396 };
1397
1398 module_platform_driver(sdhci_esdhc_imx_driver);
匹配后会执行probe;
// drivers/mmc/host/sdhci-esdhc-imx.c
1116 static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
1117 {
1118 const struct of_device_id *of_id =
1119 of_match_device(imx_esdhc_dt_ids, &pdev->dev);
1120 struct sdhci_pltfm_host *pltfm_host;
// ...
1299
1300 err = sdhci_add_host(host);
1301 if (err)
1302 goto disable_clk;
// ...
}
最后会调用
sdhci_add_host(host)
最后还是调用到了
mmc_add_host(struct mmc_host *host)
// drivers/mmc/host/sdhci.c
// 这个文件是imx6自己给mmc core的接口又封装了一层
2884 int sdhci_add_host(struct sdhci_host *host)
2885 {
2886 struct mmc_host *mmc;
2887 u32 caps[2] = {
0, 0};
2888 u32 max_current_caps;
2889 unsigned int ocr_avail;
2890 int ret;
2891
2892 WARN_ON(host == NULL);
2893 if (host == NULL)
2894 return -EINVAL;
2895
2896 mmc = host->mmc;
// ...
// 这里给mmc一组操作集,是imx实现了的
3036 mmc->ops = &sdhci_ops;
3037 mmc->f_max = host->max_clk;
// ...
3396 mmc_add_host(mmc);
3397
3398 pr_info("%s: SDHCI controller on %s [%s] using %s\n",
3399 mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
3400 (host->flags & SDHCI_USE_ADMA) ? "ADMA" :
3401 (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
3402
3403 sdhci_enable_card_detection(host);
3404
3405 return 0;
3406
3407 #ifdef SDHCI_USE_LEDS_CLASS
3408 reset:
3409 sdhci_reset(host, SDHCI_RESET_ALL);
3410 sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
3411 free_irq(host->irq, host);
3412 #endif
3413 untasklet:
3414 tasklet_kill(&host->card_tasklet);
3415 tasklet_kill(&host->finish_tasklet);
3416
3417 return ret;
3418 }
imx对mmc core接口封装一层,主要是简化了使用者的很多初始化工作,比如下面已经实现了mmc_host的操作集;
// drivers/mmc/host/sdhci.c
2200 static const struct mmc_host_ops sdhci_ops = {
2201 .request = sdhci_request,
2202 .post_req = sdhci_post_req,
2203 .pre_req = sdhci_pre_req,
2204 .set_ios = sdhci_set_ios,
2205 .get_cd = sdhci_get_cd,
2206 .get_ro = sdhci_get_ro,
2207 .hw_reset = sdhci_hw_reset,
2208 .enable_sdio_irq = sdhci_enable_sdio_irq,
2209 .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
2210 .prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
2211 .execute_tuning = sdhci_execute_tuning,
2212 .card_event = sdhci_card_event,
2213 .card_busy = sdhci_card_busy,
2214 };
mmc_host的创建,是probe
sdhci_esdhc_imx_probe(struct platform_device *pdev)
调用
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0);
创建的
117 struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
118 const struct sdhci_pltfm_data *pdata,
119 size_t priv_size)
120 {
121 struct sdhci_host *host;
// ...
134
135 /* Some PCI-based MFD need the parent here */
136 if (pdev->dev.parent != &platform_bus && !np)
137 host = sdhci_alloc_host(pdev->dev.parent,
138 sizeof(struct sdhci_pltfm_host) + priv_size);
139 else
140 host = sdhci_alloc_host(&pdev->dev,
141 sizeof(struct sdhci_pltfm_host) + priv_size);
// ...
192 }
sdhci_alloc_host()
也是imx对
mmc_alloc_host()
做了一层封装;
// drivers/mmc/host/sdhci.c
2864 struct sdhci_host *sdhci_alloc_host(struct device *dev,
2865 size_t priv_size)
2866 {
2867 struct mmc_host *mmc;
2868 struct sdhci_host *host;
2870 WARN_ON(dev == NULL);
// 这里调用了mmc core的接口
2872 mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev);
2873 if (!mmc)
2874 return ERR_PTR(-ENOMEM);
2876 host = mmc_priv(mmc);
2877 host->mmc = mmc;
2879 return host;
2880 }
我们现在知道了,mmc host层主要就是调用mmc core的接口,注册了一个mmc host,以及实现了mmc host的操作集mmc host opts,这里暂时先不管这个mmc host怎么被使用到,后面再分析;
还有一个比较重要的点就是
mmc_detect_change函数
最后会调用到
mmc_rescan函数,
mmc_rescan函数会去扫描有没有有效的sd卡插入;
除了在probe的时候会最终调用mmc_rescan;
在probe的时候注册了一个中断,
这个中断会去调用
mmc_detect_change
并最终调用了
mmc_rescan
mmc_rescan是在分配mmc_host的时候给初始化的
// drivers/mmc/core/host.c
451 struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
452 {
453 int err;
454 struct mmc_host *host;
455 int alias_id, min_idx, max_idx;
// ...
495 spin_lock_init(&host->lock);
496 init_waitqueue_head(&host->wq);
// 初始化了一个工作队列
497 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
498 #ifdef CONFIG_PM
499 host->pm_notify.notifier_call = mmc_pm_notify;
500 #endif
// ...
}
所以probe会检查一下有效sd卡,后期sd卡插入,产生中断会去检查一下有效sd卡;
接下来看下mmc card是怎么注册到内核的
上面说到,mmc_add_host()注册mmc_host的时候会去调用
mmc_detect_change()
最终会去调用
mmc_rescan()
先看看mmc_rescan()做了什么
在这里插入代码片
在扫描到sd卡后,
会调用
mmc_add_card
去添加一个 mmc_card
struct mmc_card
这个mmc_card也是注册在mmc_bus上的一个设备
mmc_card添加后符合总线驱动模型,会去扫描mmc_driver;
最后看下mmc_driver是怎么注册到总线上的
// drivers/mmc/card/block.c
2518 static struct mmc_driver mmc_driver = {
2519 .drv = {
2520 .name = "mmcblk",
2521 },
2522 .probe = mmc_blk_probe,
2523 .remove = mmc_blk_remove,
2524 .suspend = mmc_blk_suspend,
2525 .resume = mmc_blk_resume,
2526 .shutdown = mmc_blk_shutdown,
2527 };
2529 static int __init mmc_blk_init(void)
2530 {
2531 int res;
2533 if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
2534 pr_info("mmcblk: using %d minors per device\n", perdev_minors);
2536 max_devices = 256 / perdev_minors;
2537
2538 res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
2539 if (res)
2540 goto out;
2542 res = mmc_register_driver(&mmc_driver);
2543 if (res)
2544 goto out2;
2546 return 0;
2547 out2:
2548 unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
2549 out:
2550 return res;
2551 }
2553 static void __exit mmc_blk_exit(void)
2554 {
2555 mmc_unregister_driver(&mmc_driver);
2556 unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
2557 }
2559 module_init(mmc_blk_init);
2560 module_exit(mmc_blk_exit);
小结
1、mmc子系统,分成3部分,
2、core提供了一些api供其他2部分调用;
3、host,负责初始化mmc控制器(cpu硬件),注册mmc_host设备;
4、host,负责扫描合法sd卡,并在成功扫描后,注册一个mmc_card到mmc_bus总线;
5、card,负责注册mmc_driver驱动到mmc_bus总线,匹配设备后创建设备节点供应用层调用;
参考:
linux mmc 框架源码分析
emmc框架分析
Linux SD/MMC/SDIO驱动分析
eMMC驱动分析