协议层为我们解析了寄存器里的域,并赋给card->cid,比如厂商名称,就可以通过card->cid.manfid直接读取到。
static int mmc_decode_cid(struct mmc_card *card) {
u32 *resp = card->raw_cid;
card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); card->cid.serial = UNSTUFF_BITS(resp, 16, 32); card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; return 0; }
3.1.4 注册SD卡设备驱动
int mmc_attach_sd(struct mmc_host *host, u32 ocr) {
/* mmc_alloc_card(host, &sd_type); 在mmc_sd_init_card()已完成 */
mmc_add_card(host->card); ... ... }
上文已经提到,设备驱动程序都会通过alloc_xxx()和add_xxx()两步来注册驱动,其实质是调用/drivers/base/core.c里的device_initialize()和device_add(),device_add()完成建立kobject,sys文件,发送uevent,等工作。 3.2 拔出SD卡
void mmc_rescan(struct work_struct *work) {
struct mmc_host *host = container_of(work, struct mmc_host, detect.work); mmc_bus_get(host);
/* if there is a card registered, check whether it is still present */
if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead) host->bus_ops->detect(host); mmc_bus_put(host); ... ... }
这里的mmc_bus_get/put(),为SD总线加上一个自旋锁,规定同时只能有一个线程在SD总线上操作。
3.2.1 bus_ops->detect() mmc_rescan()扫描SD总线,如果发现host->ops上赋了值,即之前已有SD卡注册过,就执行bus_ops->detect()操作去探测SD总线上是否还存在SD卡,如果不存在了,就执行bus_ops->remove()拔出SD卡。之前已经提到,这个bus_ops->detect()已在mmc_attach_sd()注册完成了。
static void mmc_sd_detect(struct mmc_host *host) {
mmc_claim_host(host); /*
* Just check if our card has been removed. */
err = mmc_send_status(host->card, NULL); mmc_release_host(host); if (err) {
mmc_sd_remove(host); mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); } }
这里的mmc_claim_host(host)通过set_current_state(TASK_RUNNING);将当前进程设置为正在运行进程。
mmc_send_status()发送得到SD卡状态的请求,如果未能得到状态数据,则执行mmc_sd_remove(host)拔出SD卡。
int mmc_send_status(struct mmc_card *card, u32 *status) {
struct mmc_command cmd;
cmd.opcode = MMC_SEND_STATUS; /* #define MMC_SEND_STATUS 13 */ cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err)
return err; // 接收来自SD卡的response失败,即没有发现SD卡
if (status)
*status = cmd.resp[0]; return 0; }
主控制器发送命令CMD13,要求得到SD卡的状态寄存器CSR和SSR。
SD协议规定,状态寄存器CSR是必须的,这个32位寄存器作为R1的一个域返回给主控制器,
状态寄存器SSR作为扩充功能,具体参考SD2.0协议。
3.2.2 bus_ops->remove() 拔出SD卡,其实就是注册SD卡驱动的反操作,实质就是执行device_del()和device_put()。 static void mmc_sd_remove(struct mmc_host *host) {
mmc_remove_card(host->card);
host->card = NULL; }
void mmc_remove_card(struct mmc_card *card) {
if (mmc_card_present(card)) device_del(&card->dev); put_device(&card->dev); }
4. 块设备
首先,必须知道为什么要用到块设备。在linux下,SD卡通过block块的方式(以512字节为最小单位)进行数据传输,它必须遵从块设备架构。在linux块设备层,I/O调度者通过请求队列机制负责对块数据的处理。
SD卡子系统分为三层,主设备层,协议层和块设备层。块设备驱动位于/drivers/mmc/card/block.c,主要完成两个任务,
? ?
建立设备节点
通过请求队列机制进行数据传输