linux设备驱动-SD卡驱动详解2core层
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函数总结