core层作为整个MMC 的核心,这部分完成了不同协议和规范的实现,并为HOST 层的驱动提供了接口函数。
CORE 部分: 这是整个MMC 的核心存,这部分完成了不同协议和规范的实现,并为HOST 层的驱动提供了接口函数。
HOST 部分是针对不同主机的驱动程序,这一部是驱动程序工程师需要根据自己的特点平台来完成的。
CARD 部分:因为这些记忆卡都是块设备,当然需要提供块设备的驱动程序,这部分就是实现了将你的SD 卡如何实现为块设备的。
它们分布于下面的文件夹中 Linux/drivers/mmc中:
1 数据结构
1.1 mmc_host
定义位于:linux-3.10.73\include\linux\mmc\host.h
1 struct mmc_host {
2 struct device *parent;
3 struct device class_dev;
4 int index;
5 const struct mmc_host_ops *ops;
6 unsigned int f_min;
7 unsigned int f_max;
8 unsigned int f_init;
9 u32 ocr_avail;
10 u32 ocr_avail_sdio; /* SDIO-specific OCR */
11 u32 ocr_avail_sd; /* SD-specific OCR */
12 u32 ocr_avail_mmc; /* MMC-specific OCR */
13 struct notifier_block pm_notify;
14 u32 max_current_330;
15 u32 max_current_300;
16 u32 max_current_180;
17
18 ...
19
20 unsigned long private[0] ____cacheline_aligned;
21 }
1.2 总线
platform bus //MMC host controller 作为一种 platform device, 它是需要注册到 platform bus上 的 。
1 struct bus_type platform_bus_type = {
2 .name = "platform",
3 .dev_attrs = platform_dev_attrs,
4 .match = platform_match,
5 .uevent = platform_uevent,
6 .pm = &platform_dev_pm_ops,
7 };
mmc bus type ,在mmc_init()中被创建的.通过调用 mmc_register_bus() 来注册 MMC 总线 。定义位于:drivers\mmc\core\bus.c
1 static struct bus_type mmc_bus_type = {
2 .name = "mmc",
3 .dev_attrs = mmc_dev_attrs,
4 .match = mmc_bus_match,
5 .uevent = mmc_bus_uevent,
6 .probe = mmc_bus_probe,
7 .remove = mmc_bus_remove,
8 .pm = &mmc_bus_pm_ops,
9 };
sdio bus type,在mmc_init()中被创建的.通过调用sdio_register_bus() 来注册 SDIO 总线 。定义位于:drivers\mmc\core\sdio_bus.c。
1 static struct bus_type sdio_bus_type = {
2 .name = "sdio",
3 .dev_attrs = sdio_dev_attrs,
4 .match = sdio_bus_match,
5 .uevent = sdio_bus_uevent,
6 .probe = sdio_bus_probe,
7 .remove = sdio_bus_remove,
8 .pm = SDIO_PM_OPS_PTR,
9 };
1.3 操作结构体
其中mmc总线操作相关函数,由于mmc卡支持多种总数据线,如SPI、SDIO、8LineMMC而不同的总线的操作控制方式不尽相同,所以通过此结构与相应的总线回调函数相关联。
sdio的总线操作 core/sdio.c
1 static const struct mmc_bus_ops mmc_sdio_ops = {
2 .remove = mmc_sdio_remove,
3 .detect = mmc_sdio_detect,
4 .suspend = mmc_sdio_suspend,
5 .resume = mmc_sdio_resume,
6 .power_restore = mmc_sdio_power_restore,
7 .alive = mmc_sdio_alive,
8 };
mmc卡的总线操作 core/mmc.c
1 static const struct mmc_bus_ops mmc_ops = {
2 .awake = mmc_awake,
3 .sleep = mmc_sleep,
4 .remove = mmc_remove,
5 .detect = mmc_detect,
6 .suspend = NULL,
7 .resume = NULL,
8 .power_restore = mmc_power_restore,
9 .alive = mmc_alive,
10 };
sd卡的总线操作 core/sd.c
1 static const struct mmc_bus_ops mmc_sd_ops = {
2 .remove = mmc_sd_remove,
3 .detect = mmc_sd_detect,
4 .suspend = NULL,
5 .resume = NULL,
6 .power_restore = mmc_sd_power_restore,
7 .alive = mmc_sd_alive,
8 };
.detect操作函数:驱动程序经常需要调用此函数去检测mmc卡的状态,具体实现是发送CMD13命令,并读回响应,如果响应错误,则依次调用.remove、detach_bus来移除卡及释放总线。
2 core的flow
内核启动时,首先执行core/core.c的mmc_init,注册mmc、sd总线,以及一个host class设备。接着执行card/block.c中mmc_blk_init(),申请一个块设备。
2.1 初始化
2.1.1 mmc_init
定义位于:linux-3.10.73\drivers\mmc\core\core.c
1 static int __init mmc_init(void)
2 {
3 int ret;
4
5 workqueue = alloc_ordered_workqueue("kmmcd", 0);//建立队列,主要用来支持热插热拔
6 if (!workqueue)
7 return -ENOMEM;
8
9 ret = mmc_register_bus();//注册mmc总线
10 if (ret)
11 goto destroy_workqueue;
12
13 ret = mmc_register_host_class();//注册mmc host class
14 if (ret)
15 goto unregister_bus;
16
17 ret = sdio_register_bus();//注册SDIO总线
18 if (ret)
19 goto unregister_host_class;
20
21 return 0;
22
23 unregister_host_class:
24 mmc_unregister_host_class();
25 unregister_bus:
26 mmc_unregister_bus();
27 destroy_workqueue:
28 destroy_workqueue(workqueue);
29
30 return ret;
31 }
2.1.2 函数mmc_blk_init
定义位于:mmc/card/block.c
1 static int __init mmc_blk_init(void)
2 {
3 int res;
4
5 if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
6 pr_info("mmcblk: using %d minors per device\n", perdev_minors);
7
8 max_devices = 256 / perdev_minors;
9
10 res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");//注册一个块设备
11 if (res)
12 goto out;
13
14 res = mmc_register_driver(&mmc_driver);//注册一个mmc设备驱动
15 if (res)
16 goto out2;
17
18 return 0;
19 out2:
20 unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
21 out:
22 return res;
23 }
mmc_driver
1 static struct mmc_driver mmc_driver = {
2 .drv = {
3 .name = "mmcblk",
4 },
5 .probe = mmc_blk_probe,
6 .remove = mmc_blk_remove,
7 .suspend = mmc_blk_suspend,
8 .resume = mmc_blk_resume,
9 };
mmc_driver probe函数
1 static int mmc_blk_probe(struct mmc_card *card)
2 {
3 struct mmc_blk_data *md, *part_md;
4 char cap_str[10];
5
6 /*
7 * Check that the card supports the command class(es) we need.
8 */
9 if (!(card->csd.cmdclass & CCC_BLOCK_READ))
10 return -ENODEV;
11
12 md = mmc_blk_alloc(card);
13 if (IS_ERR(md))
14 return PTR_ERR(md);
15
16 string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
17 cap_str, sizeof(cap_str));
18 pr_info("%s: %s %s %s %s\n",
19 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
20 cap_str, md->read_only ? "(ro)" : "");
21
22 if (mmc_blk_alloc_parts(card, md))
23 goto out;
24
25 mmc_set_drvdata(card, md);
26 mmc_fixup_device(card, blk_fixups);
27
28 if (mmc_add_disk(md))
29 goto out;
30
31 list_for_each_entry(part_md, &md->part, part) {
32 if (mmc_add_disk(part_md))
33 goto out;
34 }
35 return 0;
36
37 out:
38 mmc_blk_remove_parts(card, md);
39 mmc_blk_remove_req(md);
40 return 0;
41 }
2.2 注册mmc总线
定义位于:drivers\mmc\core\bus.c
1 int mmc_register_bus(void)
2 {
3 return bus_register(&mmc_bus_type);//注册bus
4 }
5
6 static struct bus_type mmc_bus_type = {
7 .name = "mmc",
8 .dev_attrs = mmc_dev_attrs,
9 .match = mmc_bus_match,
10 .uevent = mmc_bus_uevent,
11 .probe = mmc_bus_probe,
12 .remove = mmc_bus_remove,
13 .pm = &mmc_bus_pm_ops,
14 };
2.3 注册host class
定义位于:drivers\mmc\core\host.c
1 static struct class mmc_host_class = {
2 .name = "mmc_host",
3 .dev_release = mmc_host_classdev_release,
4 };
5
6 int mmc_register_host_class(void)
7 {
8 return class_register(&mmc_host_class);
9 }
2.4 注册sdio总线
定义位于:drivers\mmc\core\sdio_bus.c
1 static struct bus_type sdio_bus_type = {
2 .name = "sdio",
3 .dev_attrs = sdio_dev_attrs,
4 .match = sdio_bus_match,
5 .uevent = sdio_bus_uevent,
6 .probe = sdio_bus_probe,
7 .remove = sdio_bus_remove,
8 .pm = SDIO_PM_OPS_PTR,
9 };
10
11 int sdio_register_bus(void)
12 {
13 return bus_register(&sdio_bus_type);
14 }
2.5 mmc_rescan函数
mmc_rescan 函数是需要重点关注的,因为SD卡协议中的检测,以及卡识别等都是在此函数中实现。
插入SD卡,主控制器产生中断,进入中断处理函数s3cmci_irq_cd,其中调用的函数 mmc_detect_change,它将最终调用queue_delayed_work执行工作队列里的mmc_rescan函数。
mmc_rescan扫描SD总线上是否存在SD卡,是mmc host的detect work的功能函数,用于探测目标卡的类型并且根据mmc/sd/sdio协议进行comm的初始化。
1 void mmc_rescan(struct work_struct *work)
2 {
3 struct mmc_host *host =
4 container_of(work, struct mmc_host, detect.work);//
5 int i;
6
7 if (host->rescan_disable)
8 return;
9
10 /* If there is a non-removable card registered, only scan once */
11 if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered)
12 return;
13 host->rescan_entered = 1;
14
15 mmc_bus_get(host);//
16
17 /*
18 * if there is a _removable_ card registered, check whether it is
19 * still present
20 */
21 if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
22 && !(host->caps & MMC_CAP_NONREMOVABLE))
23 host->bus_ops->detect(host);//
24
25 host->detect_change = 0;//
26
27 /*
28 * Let mmc_bus_put() free the bus/bus_ops if we've found that
29 * the card is no longer present.
30 */
31 mmc_bus_put(host);//减少引用计数,即释放
32 mmc_bus_get(host);//增加bus引用计数
33
34 /* if there still is a card present, stop here */
35 if (host->bus_ops != NULL) {
36 mmc_bus_put(host);//如果卡仍然存在,减少引用计数,不必探测了
37 goto out;
38 }
39
40 /*
41 * Only we can add a new handler, so it's safe to
42 * release the lock here.
43 */
44 mmc_bus_put(host);//
45
46 if (host->ops->get_cd && host->ops->get_cd(host) == 0) {//有卡,退出
47 mmc_claim_host(host);//
48 mmc_power_off(host);//
49 mmc_release_host(host);//
50 goto out;
51 }
52
53 mmc_claim_host(host);//
54 for (i = 0; i < ARRAY_SIZE(freqs); i++) {
55 if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))//
56 break;
57 if (freqs[i] <= host->f_min)
58 break;
59 }
60 mmc_release_host(host);//
61
62 out:
63 if (host->caps & MMC_CAP_NEEDS_POLL)
64 mmc_schedule_delayed_work(&host->detect, HZ);//
65 }
初始化卡接以下流程初始化:
发送CMD0使卡进入IDLE状态
发送CMD8,检查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先发送CMD8,如响应为无效命令,则卡为SD1.1,否则就是SD2.0(请参考SD2.0 Spec)。
发送CMD5读取OCR寄存器。
发送ACMD55、CMD41,使卡进入工作状态。MMC卡并不支持ACMD55、CMD41,如果这步通过了,则证明这张卡是SD卡。
如果d步骤错误,则发送CMD1判断卡是否为MMC。SD卡不支持CMD1,而MMC卡支持,这就是SD和MMC类型的判断依据。
如果ACMD41和CMD1都不能通过,那这张卡恐怕就是无效卡了,初始化失败。
假如扫描到总线上挂有有效的设备,就调用相对应的函数把设备装到系统中,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()把存储卡加到系统中。正式与系统驱动连接在一起。
2.6 函数mmc_rescan_try_freq
1 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
2 {
3 host->f_init = freq; //根据mmc_recan函数传进来的参数知道,首先传进来的是400kHZ.一般mmc/sd/sdio的初始化时钟采用的是400kHZ
4
5 #ifdef CONFIG_MMC_DEBUG
6 pr_info("%s: %s: trying to init card at %u Hz\n",
7 mmc_hostname(host), __func__, host->f_init);
8 #endif
9 mmc_power_up(host);//上电,我们知道,在mmc_add_host时,会调用mmc_start_host,而那里首先是将host掉电的。这里上电
10
11 /*
12 * Some eMMCs (with VCCQ always on) may not be reset after power up, so
13 * do a hardware reset if possible.
14 */
15 mmc_hw_reset_for_init(host);//复位硬件,可以选择性实现。
16
17 /*
18 * sdio_reset sends CMD52 to reset card. Since we do not know
19 * if the card is being re-initialized, just send it. CMD52
20 * should be ignored by SD/eMMC cards.
21 */
22 sdio_reset(host);
23 mmc_go_idle(host);//发送CMD0 复位SD卡
24
25 mmc_send_if_cond(host, host->ocr_avail);
26 /*Linux 卡的探测顺序是:先辨别卡是否是sdio功能卡或者是sdio与sd卡的组合卡,然后辨别是否是SD卡,最后才会辨别是否是mmc卡*/
27 /* Order's important: probe SDIO, then SD, then MMC */
28 if (!mmc_attach_sdio(host))//匹配sdio接口
29 return 0;
30 if (!mmc_attach_sd(host))
31 return 0;
32 if (!mmc_attach_mmc(host))
33 return 0;
34
35 mmc_power_off(host);
36 return -EIO;
37 }
函数sdio_reset(host);/的作用:
(1)如果目标卡是纯SD卡(对MMC卡不了解,所以不加评论),则目标卡不会应答,一般主机host的寄存器会报错,但是这个无关紧要,可以不理它。
(2)如果目标卡是纯SDIO卡,那么这里就是复位SDIO卡,通过命令CMD52来实现的。
(3)如果目标卡是SD卡和SDIO卡的组合卡,则需要先发送CMD52来复位SDIO卡,再复位SD卡,因为CMD52要先于CMD0发送。
函数mmc_send_if_cond(host, host->ocr_avail);的作用 :
为了支持sd version 2.0以上的sd卡,在初始化的过程中必须在发送ACMD41之前,先发送CMD8,CMD8一般是用于检测SD卡是否能运行在host提供的电压范围内。大家可能发现,这个调用过程没有检查是否出错,其实一般CMD8是用来辨别目标卡是否是高容量SD卡,如果是,CMD8 会有R7应答,R7应答中会有目标SD卡支持的电压范围以及CMD8中发送过去的“check pattern(一般是0xAA)”,否则,目标卡不会应答,在Linux 内核代码中,判断是这样的,如果应答,目标卡就是SD高容量卡,否则出现应答超时错误,就是标准SD卡!这里的调用,主要作用是为了在发送ACMD41之前发送CMD8,这是version 2.0及以上的规定顺序,后面还会有发送CMD8的地方,那里才是真正检测目标卡的类型的地方。
2.6.1 函数mmc_go_idle
1 int mmc_go_idle(struct mmc_host *host)
2 struct mmc_command cmd = {0};
3 cmd.opcode = MMC_GO_IDLE_STATE; //即CMD0
4 cmd.arg = 0; //此命令无参数
5 err = mmc_wait_for_cmd(host, &cmd, 0)
6
7 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
8 memset(cmd->resp, 0, sizeof(cmd->resp)); //调用了 mmc_start_request,
9 cmd->retries = retries;
10 mrq.cmd = cmd;
11 mmc_wait_for_req(host, &mrq);
12
13 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) ----重要函数
14 __mmc_start_req(host, mrq);
15
16 static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
17 mmc_start_request(host, mrq);
18
19 static void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
20 host->ops->request(host, mrq); //即 msmsdcc_request, MMC 核心与核HOST 层握手了
host即struct mmc_host类型,在drivers\mmc\host\s3cmci.c的probe函数中定义赋值:
1 static int s3cmci_probe(struct platform_device *pdev)
2 {
3 ...
4 mmc->ops = &s3cmci_ops;
5 ...
6 }
7
8 static struct mmc_host_ops s3cmci_ops = {
9 .request = s3cmci_request,
10 .set_ios = s3cmci_set_ios,
11 .get_ro = s3cmci_get_ro,
12 .get_cd = s3cmci_card_present,
13 .enable_sdio_irq = s3cmci_enable_sdio_irq,
14 };
request函数分析见linux设备驱动-SD卡驱动详解3 host层。
2.7 sdio的挂载
2.7.1 函数mmc_attach_sdio
定义位于:drivers\mmc\core\sdio.c
1 int mmc_attach_sdio(struct mmc_host *host)
2 {
3 int err, i, funcs;
4 u32 ocr;
5 struct mmc_card *card;
6
7 BUG_ON(!host);
8 WARN_ON(!host->claimed);
9
10 err = mmc_send_io_op_cond(host, 0, &ocr);//
11 if (err)
12 return err;
13
14 mmc_attach_bus(host, &mmc_sdio_ops);//
15 if (host->ocr_avail_sdio)
16 host->ocr_avail = host->ocr_avail_sdio;
17
18 /*
19 * Sanity check the voltages that the card claims to
20 * support.
21 */
22 if (ocr & 0x7F) {
23 pr_warning("%s: card claims to support voltages "
24 "below the defined range. These will be ignored.\n",
25 mmc_hostname(host));
26 ocr &= ~0x7F;
27 }
28
29 host->ocr = mmc_select_voltage(host, ocr);//设置时钟和总线 ---------------- 详解1
30
31 /*
32 * Can we support the voltage(s) of the card(s)?
33 */
34 if (!host->ocr) {
35 err = -EINVAL;
36 goto err;
37 }
38
39 /*
40 * Detect and init the card.
41 */
42 if (mmc_host_uhs(host))
43 /* to query card if 1.8V signalling is supported */
44 host->ocr |= R4_18V_PRESENT;
45
46 err = mmc_sdio_init_card(host, host->ocr, NULL, 0);//
47 if (err) {
48 if (err == -EAGAIN) {
49 /*
50 * Retry initialization with S18R set to 0.
51 */
52 host->ocr &= ~R4_18V_PRESENT;
53 err = mmc_sdio_init_card(host, host->ocr, NULL, 0);//
54 }
55 if (err)
56 goto err;
57 }
58 card = host->card;
59
60 /*
61 * Enable runtime PM only if supported by host+card+board
62 */
63 if (host->caps & MMC_CAP_POWER_OFF_CARD) {
64 /*
65 * Let runtime PM core know our card is active
66 */
67 err = pm_runtime_set_active(&card->dev);//
68 if (err)
69 goto remove;
70
71 /*
72 * Enable runtime PM for this card
73 */
74 pm_runtime_enable(&card->dev);//
75 }
76
77 /*
78 * The number of functions on the card is encoded inside
79 * the ocr.
80 */
81 funcs = (ocr & 0x70000000) >> 28;
82 card->sdio_funcs = 0;
83
84 /*
85 * Initialize (but don't add) all present functions.
86 */
87 for (i = 0; i < funcs; i++, card->sdio_funcs++) {
88 err = sdio_init_func(host->card, i + 1);
89 if (err)
90 goto remove;
91
92 /*
93 * Enable Runtime PM for this func (if supported)
94 */
95 if (host->caps & MMC_CAP_POWER_OFF_CARD)
96 pm_runtime_enable(&card->sdio_func[i]->dev);
97 }
98
99 /*
100 * First add the card to the driver model...
101 */
102 mmc_release_host(host);
103 err = mmc_add_card(host->card);//注册一个mmc card
104 if (err)
105 goto remove_added;
106
107 /*
108 * ...then the SDIO functions.
109 */
110 for (i = 0;i < funcs;i++) {
111 err = sdio_add_func(host->card->sdio_func[i]);//注册一个sdio func
112 if (err)
113 goto remove_added;
114 }
115
116 mmc_claim_host(host);//
117 return 0;
118
119
120 remove_added:
121 /* Remove without lock if the device has been added. */
122 mmc_sdio_remove(host);
123 mmc_claim_host(host);//
124 remove:
125 /* And with lock if it hasn't been added. */
126 mmc_release_host(host);//
127 if (host->card)
128 mmc_sdio_remove(host);
129 mmc_claim_host(host);
130 err:
131 mmc_detach_bus(host);//
132
133 pr_err("%s: error %d whilst initialising SDIO card\n",
134 mmc_hostname(host), err);
135
136 return err;
137 }
详解1:mmc_select_voltage函数设置时钟和总线,协议层里利用回调函数为所有满足该协议的设备提供统一的接口,而具体实现由底层不同的设备驱动各自完成。注意到,之所以要定义一些放之四海而皆准的公用的类,比如struct mmc_host,就是需要通过struct mmc_host *host指针作为形参传到协议层所提供的接口函数中,从而得以调用。
1 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
2 {
3 mmc_set_ios(host);
4
5 ... ...
6 }
7
8 static inline void mmc_set_ios(struct mmc_host *host)
9 {
10 struct mmc_ios *ios = &host->ios;
11
12 host->ops->set_ios(host, ios); // 设置主控制器时钟和总线的回调函数,具体实现由主控制器驱动完成
13 }
2.7.2 函数mmc_add_card
定义位于:drivers\mmc\core\bus.c
最终call device_add,就是将card注册进linux设备模型 ,注册结果就是可以在/sys/bus/mmc/devices目录下见到card 的名字,如mmc2:0001
1 /*
2 * Register a new MMC card with the driver model.
3 */
4 int mmc_add_card(struct mmc_card *card)
5 {
6 int ret;
7 const char *type;
8 const char *uhs_bus_speed_mode = "";
9 static const char *const uhs_speeds[] = {
10 [UHS_SDR12_BUS_SPEED] = "SDR12 ",
11 [UHS_SDR25_BUS_SPEED] = "SDR25 ",
12 [UHS_SDR50_BUS_SPEED] = "SDR50 ",
13 [UHS_SDR104_BUS_SPEED] = "SDR104 ",
14 [UHS_DDR50_BUS_SPEED] = "DDR50 ",
15 };
16
17
18 dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);//设置device 名字
19
20 switch (card->type) {
21 case MMC_TYPE_MMC:
22 type = "MMC";
23 break;
24 case MMC_TYPE_SD:
25 type = "SD";
26 if (mmc_card_blockaddr(card)) {
27 if (mmc_card_ext_capacity(card))
28 type = "SDXC";
29 else
30 type = "SDHC";
31 }
32 break;
33 case MMC_TYPE_SDIO:
34 type = "SDIO";
35 break;
36 case MMC_TYPE_SD_COMBO:
37 type = "SD-combo";
38 if (mmc_card_blockaddr(card))
39 type = "SDHC-combo";
40 break;
41 default:
42 type = "?";
43 break;
44 }
45
46 if (mmc_sd_card_uhs(card) &&
47 (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
48 uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
49
50 if (mmc_host_is_spi(card->host)) {
51 pr_info("%s: new %s%s%s card on SPI\n",
52 mmc_hostname(card->host),
53 mmc_card_highspeed(card) ? "high speed " : "",
54 mmc_card_ddr_mode(card) ? "DDR " : "",
55 type);
56 } else {
57 pr_info("%s: new %s%s%s%s%s card at address %04x\n",
58 mmc_hostname(card->host),
59 mmc_card_uhs(card) ? "ultra high speed " :
60 (mmc_card_highspeed(card) ? "high speed " : ""),
61 (mmc_card_hs200(card) ? "HS200 " : ""),
62 mmc_card_ddr_mode(card) ? "DDR " : "",
63 uhs_bus_speed_mode, type, card->rca);
64 }
65
66 #ifdef CONFIG_DEBUG_FS
67 mmc_add_card_debugfs(card);
68 #endif
69 mmc_init_context_info(card->host);
70
71 ret = device_add(&card->dev);//添加设备device
72 if (ret)
73 return ret;
74
75 mmc_card_set_present(card);
76
77 return 0;
78 }
2.7.3 sdio总线上driver
以上已向系统添加设备device。以TIdrivers\net\wireless\ti\wlcore\sdio.c的wlan为例:
1 static struct sdio_driver wl1271_sdio_driver = {
2 .name = "wl1271_sdio",
3 .id_table = wl1271_devices,
4 .probe = wl1271_probe,
5 .remove = wl1271_remove,
6 #ifdef CONFIG_PM
7 .drv = {
8 .pm = &wl1271_sdio_pm_ops,
9 },
10 #endif
11 };
12
13 static int __init wl1271_init(void)
14 {
15 return sdio_register_driver(&wl1271_sdio_driver);//向sdio总线注册driver
16 }
函数sdio_register_driver,定义位于:drivers\mmc\core\sdio_bus.c
1 /**
2 * sdio_register_driver - register a function driver
3 * @drv: SDIO function driver
4 */
5 int sdio_register_driver(struct sdio_driver *drv)
6 {
7 drv->drv.name = drv->name;
8 drv->drv.bus = &sdio_bus_type;
9 return driver_register(&drv->drv);
10 }
总结:(1)以上device和driver是挂在sdio总线上的,sdio总线在kernel启动时加载的;
(2)以drivers\mmc\host\s3cmci.c为例作为host,sdio设备插入时产生中断,调用mmc_resan建立host等工作,最终添加sdio总线上的设备device;
(3)以下的mmc总线和sd卡也是类似。
2.8 sd卡的挂载
2.8.1 函数mmc_attach_sd
完成匹配,和初始化卡的功能 。定义位于:drivers\mmc\core\sd.c
1 /*
2 * Starting point for SD card init.
3 */
4 int mmc_attach_sd(struct mmc_host *host)
5 {
6 int err;
7 u32 ocr;
8
9 BUG_ON(!host);
10 WARN_ON(!host->claimed);
11
12 err = mmc_send_app_op_cond(host, 0, &ocr);//检测是否是支持SD卡
13 if (err)
14 return err;
15
16 mmc_sd_attach_bus_ops(host);
17 if (host->ocr_avail_sd)
18 host->ocr_avail = host->ocr_avail_sd;
19
20 /*
21 * We need to get OCR a different way for SPI.
22 */
23 if (mmc_host_is_spi(host)) {
24 mmc_go_idle(host);
25
26 err = mmc_spi_read_ocr(host, 0, &ocr);
27 if (err)
28 goto err;
29 }
30
31 /*
32 * Sanity check the voltages that the card claims to
33 * support.
34 */
35 if (ocr & 0x7F) {
36 pr_warning("%s: card claims to support voltages "
37 "below the defined range. These will be ignored.\n",
38 mmc_hostname(host));
39 ocr &= ~0x7F;
40 }
41
42 if ((ocr & MMC_VDD_165_195) &&
43 !(host->ocr_avail_sd & MMC_VDD_165_195)) {
44 pr_warning("%s: SD card claims to support the "
45 "incompletely defined 'low voltage range'. This "
46 "will be ignored.\n", mmc_hostname(host));
47 ocr &= ~MMC_VDD_165_195;
48 }
49
50 host->ocr = mmc_select_voltage(host, ocr);//设置MMC电压
51
52 /*
53 * Can we support the voltage(s) of the card(s)?
54 */
55 if (!host->ocr) {
56 err = -EINVAL;
57 goto err;
58 }
59
60 /*
61 * Detect and init the card.
62 */
63 err = mmc_sd_init_card(host, host->ocr, NULL);//对mmc卡进行初始化,主要是读取mmc卡里的一些寄存器信息,且对这些寄存器的值进行设置
64 if (err)
65 goto err;
66
67 mmc_release_host(host);
68 err = mmc_add_card(host->card);//调用 mmc_add_card 来把 mmc_card 挂载到 mmc_bus_type 总线去
69 mmc_claim_host(host);
70 if (err)
71 goto remove_card;
72
73 return 0;
74
75 remove_card:
76 mmc_release_host(host);
77 mmc_remove_card(host->card);
78 host->card = NULL;
79 mmc_claim_host(host);
80 err:
81 mmc_detach_bus(host);
82
83 pr_err("%s: error %d whilst initialising SD card\n",
84 mmc_hostname(host), err);
85
86 return err;
87 }
2.8.2 函数mmc_send_app_op_cond
定义位于:drivers\mmc\core\sd_ops.c
1 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
2 {
3 ...
4 cmd.opcode = SD_APP_OP_COND; //ACMD41,获取 SDcard 的允许电压范围值,保存在 ocr 中. 所有发送它之前需要发送 CMD_55 命令。执行完后 card 状态变为 READY
5 ...
6 }
2.8.3 函数mmc_sd_init_card
1 static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,struct mmc_card *oldcard)
2 {
3 ...
4 err = mmc_sd_get_cid(host, ocr, cid, &rocr); //发送 CMD2 ,获取卡的身份信息,进入到身份状态
5 ...
6 card = mmc_alloc_card(host, &sd_type); //分配一张 SD 类型的 card 结构
7 ...
8 err = mmc_send_relative_addr(host, &card->rca); //获取卡的相对地址,注意一前卡和主机通信都采用默认地址,现在有了自己的地址了,进入到 stand_by 状态
9 ...
10 err = mmc_sd_get_csd(host, card); ----mmc_send_csd(card, card->raw_csd);//CMD9, 获取 CSD 寄存器的信息,包括 block 长度,卡容量等信息
11 ...
12 err = mmc_select_card(card); //发送 CMD7, 选中目前 RADD 地址上的卡,任何时候总线上只有一张卡被选中,进入了传输状态
13 ...
14 err = mmc_sd_setup_card(host, card, oldcard != NULL);
15 ...
16 }
函数mmc_sd_setup_card
1 int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,bool reinit)
2 {
3 ...
4 mmc_app_send_scr(card, card->raw_scr); //发送命令 ACMD51 获取 SRC 寄存器的内容,进入到 SENDING-DATA 状态
5 ...
6 if (host->ops->get_ro(host) > 0 ) // get_ro(host) 即是 msmsdcc_get_ro
7 mmc_card_set_readonly(card); //是否写保护,如果是的,将 card 状态设置为只读状态
8 ...
9 }
卡设备加到系统中后,对于块设备来说,会通知mmc块设备驱动。块设备驱动此时调用probe函数,即mmc_blk_probe()函数,mmc_blk_probe()首 先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程 mmc_queue_thread()。
3 sdio core总结
mmc_rescan函数总结
行胜于言,自强不息。