bus_ops = &mmc_sd_ops; mmc_attach_bus(host, bus_ops); }
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) {
host->bus_ops = ops; host->bus_refs = 1; host->bus_dead = 0; }
static const struct mmc_bus_ops mmc_sd_ops = { .remove = mmc_sd_remove, // 拔出SD卡的操作函数 .detect = mmc_sd_detect, // 探测SD卡的操作函数 .suspend = NULL, .resume = NULL,
.power_restore = mmc_sd_power_restore, // 重新启动SD卡的操作函数 };
这里的mmc_sd_detect和mmc_sd_remove就是拔出SD卡所需要用到的函数,下文将详细讨论。这里需要注意的是,插入SD卡的时候,并不执行mmc_sd_detect和
mmc_sd_remove这两个函数,但是会注册它们,也就是说,这两个函数的功能已经实现,将来可以使用。 3.1.2 设置时钟和总线
int mmc_attach_sd(struct mmc_host *host, u32 ocr) {
host->ocr = mmc_select_voltage(host, ocr); ... ... }
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) {
mmc_set_ios(host);
... ... }
static inline void mmc_set_ios(struct mmc_host *host) {
struct mmc_ios *ios = &host->ios;
host->ops->set_ios(host, ios); // 设置主控制器时钟和总线的回调函数,具体实现由主控制器驱动完成 }
从这里可以体会到回调函数的精髓:协议层里利用回调函数为所有满足该协议的设备提供统一的接口,而具体实现由底层不同的设备驱动各自完成。注意到,之所以要定义一些放之四海而皆准的公用的类,比如struct mmc_host,就是需要通过struct mmc_host *host指针作为形参传到协议层所提供的接口函数中,从而得以调用。 3.1.3 启动SD卡
int mmc_attach_sd(struct mmc_host *host, u32 ocr) {
mmc_sd_init_card(host, host->ocr, NULL); ... ... }
mmc_sd_init_card主要完成以下任务,
? ? ?
SD卡的启动过程
得到寄存器CID, CSD, SCR, RCA的数据 其他操作比如切换到高速模式,初始化card
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard) {
/* SD卡的启动过程 */ mmc_go_idle(host);
mmc_send_if_cond(host, ocr);
mmc_send_app_op_cond(host, ocr, NULL); mmc_all_send_cid(host, cid);
mmc_send_relative_addr(host, &card->rca); /* 得到寄存器CID, CSD, SCR的数据 */ mmc_send_csd(card, card->raw_csd); mmc_decode_csd(card); mmc_decode_cid(card);
mmc_app_send_scr(card, card->raw_scr); mmc_decode_scr(card); /* 其它操作 */
mmc_alloc_card(host, &sd_type); mmc_select_card(card); mmc_read_switch(card); mmc_switch_hs(card); ... ... }
1) SD卡的启动过程
根据SD2.0协议,SD卡的状态可分为两种模式:卡识别模式(card-identification mode)和数据传输模式(data-transfer mode)。这里,我们关注启动SD卡的卡识别模式。
结合代码,
mmc_go_idle(host); CMD0 Idle State
mmc_send_if_cond(host, ocr); CMD8
mmc_send_app_op_cond(host, ocr, NULL); ACMD41 Ready State
mmc_all_send_cid(host, cid); CMD2 Identification State
mmc_send_relative_addr(host, &card->rca); CMD3
Stand-by State
2) 寄存器CID, CSD, SCR, RCA -> 发送指令并得到寄存器的值
当主控制器向SD卡发送cmd指令,比如mmc_send_cid(card, card->raw_cid),请求得到SD卡CID寄存器的值,当主控制器发送cmd完成后,芯片产生一个内部中断,处理结束cmd的中断函数,之后得到来自SD卡的response,即CID寄存器的值,存放于host->cmd->resp[i]中。关于内部中断处理,参看上文的中断一节里的 mmc_wait_for_cmd()。 mmc_send_cid(card, card->raw_cid);这个函数发送了接收CSD寄存器的请求,并且得到了来自SD卡的CSD寄存器的值。
int mmc_send_cid(struct mmc_card *card, u32 *cid) {
return mmc_send_cxd_native(card->host, card->rca << 16, cid, MMC_SEND_CID); }
static int mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) {
cmd.opcode = opcode; cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
memcpy(cxd, cmd.resp, sizeof(u32) * 4); // 得到response赋给cxd,即card->raw_cid ... ... }
-> 解析寄存器的值
为什么要解析?先来看看寄存器CID在SD卡协议里的定义,它是一个128位的寄存器,存放了关于这块SD卡的基本信息,就像自己的身份证。通过mmc_send_cid()将这个寄存器的数值赋给了card->raw_cid (定义 u32 raw_cid[4];) ,为了方便得到具体某一个信息,