SD卡分析二

4、CORE层分析: CORE层完成了不同协议和规范的实现,并为HOST层的驱动提供了接口函数,在HOST层我们曾经调用的两个函数: mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); mmc_add_host(mmc ); 我们就从这两个函数入手,来分析CORE层与HOST层是如何交互的。 先看mmc_alloc_host函数: dev_set_name(&host->class_dev, "mmc%d", host->index); host->parent = dev; host->class_dev.parent = dev; host->class_dev.class = &mmc_host_class; device_initialize(&host->class_dev); 这几句是将导致在/SYS/CLASS/mmc_host下出现mmc0目录,添加类设备,在2.6.21后的版本中,类设备的class_device已近被device所取代,LDD3P387的内容有点OUT了 INIT_DELAYED_WORK(&host->detect, mmc_rescan); 初始化了一个工作队列,延时函数为mmc_rescan,这个延时函数很重要,下午要详细分析 最后对host 做一些默认配置,不过这些配置在probe函数的后面都被重置了。 分析mmc_add_host(mmc ); device_add(&host->class_dev); 这里才真正的添加了类设备。 其中调用了mmc_start_host void mmc_start_host(struct mmc_host *host) { mmc_power_off(host); mmc_detect_change(host, 0); } mmc_power_off中对ios进行了设置,然后调用mmc_set_ios(host); host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); mmc_set_ios(host)中的关键语句host->ops->set_ios(host, ios);这里的set_ios实际上就是我们前面所提到的.set_ios = s3cmci_set_ios, 再看 mmc_detect_change(host, 0);最后一句是 mmc_schedule_delayed_work(&host->detect, delay); 实际上就是调用我们前面说的延时函数mmc_rescan mmc_power_up(host);//这个函数实际上与前面的mmc_power_off类似,不过设置了启动时需要的ios mmc_go_idle(host); //CMD0 ,from inactive to idle mmc_send_if_cond(host, host->ocr_avail);//发送SD_SEND_IF_COND,是使用SD2.0卡才需要设置的命令 /*suppot for 2.0 card*/ * ...then normal SD... */ err = mmc_send_app_op_cond(host, 0, &ocr); if (!err) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); goto out; } 蓝色部分是遵照SD卡协议的SD卡启动过程,包括了非激活模式、卡识别模式和数据传输模式三种模式共九种状态的转换,你需要参照相关规范来理解。可以先参考下面三章图对模式和状态,以及状态转换有个初步了解。 我们最初的SD卡的状态时inactive状态调用mmc_go_idle(host)后,发送命令CMD0是其处于IDLE状态。 我们详细分析一下 mmc_go_idle memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_GO_IDLE_STATE; MMC_GO_IDLE_STATE就是命令CMD0 cmd.arg = 0;此命令无参数 cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; err = mmc_wait_for_cmd(host, &cmd, 0);//见注1 mmc_delay(1); 注1:mmc_wait_for_cmd(host, &cmd, 0)是用来发送命令的,我们揭开它的神秘面纱吧。 memset(&mrq, 0, sizeof(struct mmc_request)); memset(cmd->resp, 0, sizeof(cmd->resp)); cmd->retries = retries; mrq.cmd = cmd;将命令嵌入到一个mmc 请求中 cmd->data = NULL;mmc命令的data部分设置为NULL,这样表示我们要传输的是命令而不是数据 mmc_wait_for_req(host, &mrq);//关键部分 在该函数中调用了mmc_start_request,而这个函数调用了 host->ops->request(host, mrq),这个request函数就是我们在前面分析的s3cmci_request,这样MMC 核心第二次核HOST层握手了 我们再看看: err = mmc_send_app_op_cond(host, 0, &ocr);//注一 if (!err) { if (mmc_attach_sd(host, ocr))//注二 mmc_power_off(host); goto out; 注一:实际上是要发送ACMD41命令,这条命令可以用来获取SDcard的允许电压范围值,由于这是一条应用命令,所有发送它之前需要发送CMD_55命令。执行完后card状态变为READY获取的电压范围保存在ocr中,再调用mmc_attach_sd(host, ocr)看这个电压范围是否满足主机的要求,不满足,则power_off主机。 注二:mmc_attach_sd完成匹配,和初始化卡的功能 host->ocr = mmc_select_voltage(host, ocr);看是否匹配,如果匹配则做下面初始化工作 mmc_sd_init_card(host, host->ocr, NULL);我们分析该函数 (1)mmc_all_send_cid()这个函数发生CMD2,获取卡的身份信息,进入到身份状态 (2)card = mmc_alloc_card(host, &sd_type);分配一张SD类型的card结构 (3)接着调用mmc_send_relative_add,获取卡的相对地址,注意一前卡和主机通信都采用默认地址,现在有了自己的地址了,进入到stand_by状态 (4)通过发送SEND_CSD (CMD9) 获取CSD 寄存器的信息,包括block长度,卡容量等信息 (5) mmc_select_card(card)发送CMD7,选中目前RADD地址上的卡,任何时候总线上只有一张卡被选中,进入了传输状态, (6)调用mmc_app_send_scr发送命令ACMD51获取SRC寄存器的内容,进入到SENDING-DATA状态 在函数中还将获得的各个卡寄存器的内容解码,并保存到cmd结构的相应成员中。 (7)if (host->ops->get_ro(host) > 0) mmc_card_set_readonly(card); 通过调用get_ro(host)函数,实际上就是s3cmci_get_ro函数了。我们判断是否写保护,如果是的,将card状态设置为只读状态 最后再 mmc_attach_sd里,我们将card结构添加进去 mmc_add_card(host->card); dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);这里我们以host名+rca地址来命名卡我们可以看到在/sys/devices/platform/s3c2440- sdi/mmc_host:mmc0/下出现mmc0:0002的目录,这个0002就是rca地址 到这里我们分析完了MMC 的核心层 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zoe6553/archive/2011/01/06/6120554.aspx

你可能感兴趣的:(SD卡分析二)