分类: LINUX
2011-03-17 17:42:16
SD/MMC卡组成的存储系统是许多嵌入设备的主要存储设备,相当于PC机的硬盘,在嵌入设备上的SD/MMC卡控制器通过MMC协议来解析命令控制SD/MMC卡的操作。SD/MMC卡上有一些寄存器来控制卡的状态及读写操作。MMC协议规定的寄存器有:CID寄存器,128位,是卡的鉴别寄存器,存有卡的鉴别信息;RCA寄存器是16位,存有卡的本地系统的相对地址,在初始化时由控制器动态指定。DSR寄存器是16位,是配置卡的驱动程序的寄存器,是可选的。CSD寄存器是卡特定数据信息描述寄存器,是可选的。OCR寄存器是操作控制寄存器。MMC卡的系统定义及相关协议请查询《MMC卡系统定义3.1版本》。
MMC驱动程序以分通用设备层、MMC抽象设备层、MMC协议层和具体设备层四层来构建,上一层抽象出下一层的共有特性,每一层以相应的结构来描述。通用设备层对于块设备来说,主要负责设备内核对象在sysfs文件系统中的管理、请求队列管理、及与文件系统的接口,MMC抽象设备层抽出MMC卡的共有特性,如: MMC卡的请求管理、电源管理等。MMC协议层将MMC操作分解成标准的MMC协议,具体设备层则负责具体物理设备的寄存器控制等。这种分层结构层次分明,管理有效。MMC驱动程序的层次结构如下图。
MMC驱动程序主要处理两部分的内容,一是创建通用硬盘结构向系统注册,以便系统对MMC设备的管理。另一方面,要完成系统分发过来的读写请求的处理。
MMC设备由控制器及插卡组成,对应的设备结构为mmc_host结构和mmc_card结构。MMC卡设备相关结构关系图如上图。下面分别说明设备相关结构:
每个卡的插槽对应一个块的数据结构mmc_blk_data,结构列出如下(在drivers/mmc/mmc_block.c中):
struct mmc_blk_data { spinlock_t lock; struct gendisk *disk; //通用硬盘结构 struct mmc_queue queue; //MMC请求队列结构 unsigned int usage; unsigned int block_bits; //卡每一块大小所占的bit位 };
结构mmc_card是一个插卡的特性描述结构,它代有了一个插卡。列出如下(在include/linux/mmc/card.h中):
struct mmc_card { struct list_head node; //在主设备链表中的节点 struct mmc_host *host; // 卡所属的控制器 struct device dev; //通用设备结构 unsigned int rca; //设备的相对本地系统的地址 unsigned int state; //卡的状态 #define MMC_STATE_PRESENT (1<<0) //卡出现在sysfs文件系统中 #define MMC_STATE_DEAD (1<<1) //卡不在工作状态 #define MMC_STATE_BAD (1<<2) //不认识的设备 u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ struct mmc_cid cid; //卡的身份鉴别,值来自卡的CID寄存器 struct mmc_csd csd; //卡特定信息,值来自卡的CSD寄存器 };
结构mmc_host描述了一个MMC卡控制器的特性及操作等,结构mmc_host列出如下(在include/linux/mmc/host.h中):
struct mmc_host { struct device *dev; //通用设备结构 struct mmc_host_ops *ops; //控制器操作函数集结构 unsigned int f_min; unsigned int f_max; u32 ocr_avail; //卡可用的OCR寄存器值 char host_name[8]; //控制器名字 //主控制器中与块层请求队列相关数据 unsigned int max_seg_size; //最大片断的尺寸 unsigned short max_hw_segs; //最大硬件片断数 unsigned short max_phys_segs; //最大物理片断数 unsigned short max_sectors; //最大扇区数 unsigned short unused; //私有数据 struct mmc_ios ios; //当前i/o总线设置 u32 ocr; //当前的OCR设置 struct list_head cards; //接在这个主控制器上的设备 wait_queue_head_t wq; //等待队列 spinlock_t lock; //卡忙时的锁 struct mmc_card *card_busy; //正与主控制器通信的卡 struct mmc_card *card_selected; //选择的MMC卡 struct work_struct detect; //工作结构 };
结构mmc_host_ops是控制器的操作函数集,它包括请求处理函数指针和控制器对卡I/O的状态的设置函数指针,结构mmc_host_ops列出如下:
struct mmc_host_ops { void (*request)(struct mmc_host *host, struct mmc_request *req); void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); }
结构mmc_ios描述了控制器对卡的I/O状态,列出如下:
struct mmc_ios { unsigned int clock; //时钟频率 unsigned short vdd; unsigned char bus_mode; //命令输出模式 unsigned char power_mode; //电源供应模式 };
结构mmc_driver是MMC设备驱动程序结构,列出如下:
struct mmc_driver { struct device_driver drv; int (*probe)(struct mmc_card *); void (*remove)(struct mmc_card *); int (*suspend)(struct mmc_card *, u32); int (*resume)(struct mmc_card *); };
对于MMC卡的操作是通过MMC请求结构mmc_request的传递来完成的,来自系统块层的读写请求到达MMC设备抽象层时,用系统的读写请求填充初始化MMC卡的读写请求,经MMC协议分解后,然后把请求发给设备,再调用具体设备的请求处理函数来完成请求的处理。MMC卡读写请求结构示意图中上图。下面分析MMC卡读写请求相关结构:
结构mmc_request描述了读写MMC卡的请求,它包括命令、数据及请求完成后的回调函数。结构mmc_request列出如下(在include/linux/mmc/mmc.h中):
struct mmc_request { struct mmc_command *cmd; struct mmc_data *data; struct mmc_command *stop; void *done_data; //回调函数的参数 void (*done)(struct mmc_request *);//请求完成的回调函数 };
结构mmc_queue是MMC的请求队列结构,它封装了通用请求队列结构,加入了MMC卡相关结构,结构mmc_queue列出如下(在drivers/mmc/mmc_queue.h中):
struct mmc_queue { struct mmc_card *card; //MMC卡结构 struct completion thread_complete; //线程完成结构 wait_queue_head_t thread_wq; //等待队列 struct semaphore thread_sem; unsigned int flags; struct request *req; //通用请求结构 int (*prep_fn)(struct mmc_queue *, struct request *); //发出读写请求函数 int (*issue_fn)(struct mmc_queue *, struct request *); void *data; struct request_queue *queue; //块层通用请求队列 struct scatterlist *sg; //碎片链表 };
结构mmc_data描述了MMC卡读写的数据相关信息,如:请求、操作命令、数据及状态等。结构mmc_data列出如下(在include/linuc/mmc/mmc.h中):
struct mmc_data { unsigned int timeout_ns; //数据超时( ns,最大80ms) unsigned int timeout_clks; //数据超时(以时钟计数) unsigned int blksz_bits; //数据块大小的bit位 unsigned int blocks; //块数 unsigned int error; //数据错误 unsigned int flags; //数据操作标识 #define MMC_DATA_WRITE (1 << 8) #define MMC_DATA_READ (1 << 9) #define MMC_DATA_STREAM (1 << 10) unsigned int bytes_xfered; struct mmc_command *stop; //停止命令 struct mmc_request *mrq; //相关的请求 unsigned int sg_len; //碎片链表的长度 struct scatterlist *sg; // I/O碎片链表指针 };
结构mmc_command描述了MMC卡操作相关命令及数据、状态信息等,结构列出如下:
struct mmc_command { u32 opcode; u32 arg; u32 resp[4]; unsigned int flags; //期望的反应类型 #define MMC_RSP_NONE (0 << 0) #define MMC_RSP_SHORT (1 << 0) #define MMC_RSP_LONG (2 << 0) #define MMC_RSP_MASK (3 << 0) #define MMC_RSP_CRC (1 << 3) /* expect valid crc */ #define MMC_RSP_BUSY (1 << 4) /* card may send busy */ /* * These are the response types, and correspond to valid bit * patterns of the above flags. One additional valid pattern * is all zeros, which means we don't expect a response. */ #define MMC_RSP_R1 (MMC_RSP_SHORT|MMC_RSP_CRC) #define MMC_RSP_R1B (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_LONG|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_SHORT) unsigned int retries; /* max number of retries */ unsigned int error; /* command error */ #define MMC_ERR_NONE 0 #define MMC_ERR_TIMEOUT 1 #define MMC_ERR_BADCRC 2 #define MMC_ERR_FIFO 3 #define MMC_ERR_FAILED 4 #define MMC_ERR_INVALID 5 struct mmc_data *data; //与命令相关的数据片断 struct mmc_request *mrq; //与命令相关的请求 };
函数mmc_blk_init注册一个MMC块设备驱动程序,它先将MMC块设备名注册到名称数组major_names中,然后,还把驱动程序注册到sysfs文件系统中的总线和设备目录中。一方面,sysfs文件系统中可显示MMC块设备相关信息,另一方面,sysfs文件系统以树形结构管理着MMC块设备驱动程序。
函数mmc_blk_init分析如下(在drivers/mmc/mmc_block.c中):
static int __init mmc_blk_init(void) { int res = -ENOMEM; //将卡名字mmc和major注册到块设备的名称数组major_names中 res = register_blkdev(major, "mmc"); if (res < 0) { printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n", major, res); goto out; } if (major == 0) major = res; //在devfs文件系统中创建mmc目录 devfs_mk_dir("mmc"); return mmc_register_driver(&mmc_driver); out: return res; }
mmc_driver驱动程序实例声明如下:
static struct mmc_driver mmc_driver = { .drv = { .name = "mmcblk", }, .probe = mmc_blk_probe, // MMC块设备驱动程序探测函数 .remove = mmc_blk_remove, .suspend = mmc_blk_suspend, .resume = mmc_blk_resume, };
函数mmc_register_driver 注册一个媒介层驱动程序。其中参数drv是MMC媒介层驱动程序结构。
函数mmc_register_driver分析如下(在drivers/mmc/mmc_sysfs.c中):
int mmc_register_driver(struct mmc_driver *drv) { drv->drv.bus = &mmc_bus_type; drv->drv.probe = mmc_drv_probe; drv->drv.remove = mmc_drv_remove; //把块设备注册到sysfs文件系统中对应的总线及设备目录下 return driver_register(&drv->drv); }
函数mmc_blk_probe是MMC控制器探测函数,它探测MMC控制器是否存在,并初始化控制器的结构,同时,还探测MMC卡的状态并初始化。函数mmc_blk_probe调用层次图如上图。
函数mmc_blk_probe列出如下:
static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md; //每个插槽一个结构mmc_blk_data int err; if (card->csd.cmdclass & ~0x1ff) return -ENODEV; if (card->csd.read_blkbits < 9) {//所读的块小于1扇区 printk(KERN_WARNING "%s: read blocksize too small (%u)\n", mmc_card_id(card), 1 << card->csd.read_blkbits); return -ENODEV; } //分配每个插槽的卡的块数据结构,初始化了通用硬盘及请求队列 md = mmc_blk_alloc(card); if (IS_ERR(md)) return PTR_ERR(md); //设置块大小,发命令设置卡为选中状态 err = mmc_blk_set_blksize(md, card); if (err) goto out; printk(KERN_INFO "%s: %s %s %dKiB\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), (card->csd.capacity << card->csd.read_blkbits) / 1024); mmc_set_drvdata(card, md);//即card ->driver_data = md add_disk(md->disk); //向系统注册通用硬盘结构,它包括每分区信息 return 0; out: mmc_blk_put(md); return err; }
函数*mmc_blk_alloc给每一插槽分配一个结构mmc_blk_data,并分配设置通用硬盘结构和初始了请求队列结构。
函数*mmc_blk_alloc分析如下(在drivers/mmc/mmc_block.c中):
//最大支持8个控制器,每个控制器可控制4个卡,每个卡最大8个分区。 #define MMC_SHIFT 3 //表示每个卡最大支持8个分区 #define MMC_NUM_MINORS (256 >> MMC_SHIFT) //为256/8=32 //即定义dev_use[32/(8*4)] = devuse[1],一个控制器用32位表示使用情况 static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) { struct mmc_blk_data *md; int devidx, ret; //查找dev_use中第一个bit为0的位序号(在MMC_NUM_MINORS位以内) //找到第个空闲的分区 devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); if (devidx >= MMC_NUM_MINORS) return ERR_PTR(-ENOSPC); __set_bit(devidx, dev_use);//将分区对应的位设置为1,表示使用。 md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);//分配对象空间 if (md) { memset(md, 0, sizeof(struct mmc_blk_data)); //分配gendisk结构及通用硬盘的分区hd_struct结构,并初始化内核对象 md->disk = alloc_disk(1 << MMC_SHIFT); if (md->disk == NULL) { kfree(md); md = ERR_PTR(-ENOMEM); goto out; } spin_lock_init(&md->lock); md->usage = 1; //初始化请求队列 ret = mmc_init_queue(&md->queue, card, &md->lock); if (ret) { put_disk(md->disk); kfree(md); md = ERR_PTR(ret); goto out; } //赋上各种请求队列处理函数 md->queue.prep_fn = mmc_blk_prep_rq;//准备请求 md->queue.issue_fn = mmc_blk_issue_rq;//发出请求让设备开始处理 md->queue.data = md; //初始化通用硬盘 md->disk->major = major; md->disk->first_minor = devidx << MMC_SHIFT; md->disk->fops = &mmc_bdops; //块设备操作函数集 md->disk->private_data = md; md->disk->queue = md->queue.queue; md->disk->driverfs_dev = &card->dev; /*带有永久的块设备可移去的介质应被设置GENHD_FL_REMOVABLE标识,对于永久的介质可移去的块设备不应设置GENHD_FL_REMOVABLE。MMC块设备属于永久介质可移去的块设备,不能设置GENHD_FL_REMOVABLE。用户空间应使用块设备创建/销毁热插拔消息来告诉何时卡存在。*/ sprintf(md->disk->disk_name, "mmcblk%d", devidx); sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); md->block_bits = card->csd.read_blkbits; //为请求队列设置硬件扇区大小 blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); set_capacity(md->disk, card->csd.capacity);//设置卡的容量 } out: return md; }
函数mmc_init_queue初始化一个MMC卡请求队列结构,其中参数mq是mmc请求队列,参数card是加在这个队列里的mmc卡,参数lock是队列锁。函数mmc_init_queue调用层次图如上图。
函数mmc_init_queue分析如下(在drivers/mmc/mmc_queue.c中):
int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; if (host->dev->dma_mask && *host->dev->dma_mask) limit = *host->dev->dma_mask; mq->card = card; //初始化块层的请求队列,请求合并策略,赋上请求处理函数mmc_request。 mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; //初始化请求队列的扇区及片断限制 blk_queue_prep_rq(mq->queue, mmc_prep_request);//赋上准备请求函数 blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_sectors(mq->queue, host->max_sectors); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mq->queue->queuedata = mq; mq->req = NULL; mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup; } init_completion(&mq->thread_complete); init_waitqueue_head(&mq->thread_wq); init_MUTEX(&mq->thread_sem); //创建请求队列处理线程mmc_queue_thread ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); if (ret >= 0) { wait_for_completion(&mq->thread_complete); init_completion(&mq->thread_complete); ret = 0; goto out; } cleanup: kfree(mq->sg); mq->sg = NULL; blk_cleanup_queue(mq->queue); out: return ret; }
函数mmc_prep_request 在准备一个MMC请求时做一些状态转移及保护操作,函数列出如下(在drivers/mmc/ mmc_queue.c中):
static int mmc_prep_request(struct request_queue *q, struct request *req) { struct mmc_queue *mq = q->queuedata; int ret = BLKPREP_KILL; if (req->flags & REQ_SPECIAL) { //在req->special 中已建立命令块,表示请求已准备好 BUG_ON(!req->special); ret = BLKPREP_OK; } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { //块I/O请求需要按照协议进行翻译 ret = mq->prep_fn(mq, req); } else { //无效的请求 blk_dump_rq_flags(req, "MMC bad request"); } if (ret == BLKPREP_OK)//请求已准备好,不需再准备了 req->flags |= REQ_DONTPREP; return ret; }
函数mmc_blk_prep_rq是准备请求时调用的函数,这里仅做了简单的保护处理,列出如下(在drivers/mmc/mmc_block.c中):
static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; int stat = BLKPREP_OK; //如果没有设备,没法完成初始化 if (!md || !mq->card) { printk(KERN_ERR "%s: killing request - no device/host\n", req->rq_disk->disk_name); stat = BLKPREP_KILL; } return stat; }
函数mmc_request是通用MMC请求处理函数,它唤醒请求队列处理线程。它在特定的主控制器上被任何请求队列调用。当主控制器不忙时,我们查找在这个主控制器上的任何一个队列中的请求,并且尝试发出这个请求进行处理。
函数mmc_request分析如下(在driver/mmd/mmc_queue.c中):
static void mmc_request(request_queue_t *q) { struct mmc_queue *mq = q->queuedata; if (!mq->req)//如果有请求,唤醒请求队列处理线程 wake_up(&mq->thread_wq); }
线程函数mmc_queue_thread调用了具体设备的请求处理函数,利用线程机制来处理请求。函数mmc_queue_thread分析如下:
static int mmc_queue_thread(void *d) { struct mmc_queue *mq = d; struct request_queue *q = mq->queue; DECLARE_WAITQUEUE(wait, current); //声明一个当前进程的等待队列 //设置当前进程状态,来让线程自己来处理挂起 current->flags |= PF_MEMALLOC|PF_NOFREEZE; //让线程继承init进程,从而不会使用用户进程资源 daemonize("mmcqd"); complete(&mq->thread_complete); //设置线程完成时的回调函数 down(&mq->thread_sem); add_wait_queue(&mq->thread_wq, &wait); //加线程到等待队列 do { struct request *req = NULL; spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); if (!blk_queue_plugged(q)) //如果队列是非堵塞状态,得到下一个请求 mq->req = req = elv_next_request(q); spin_unlock_irq(q->queue_lock); if (!req) {//如果请求为空 if (mq->flags & MMC_QUEUE_EXIT) break; up(&mq->thread_sem); schedule(); down(&mq->thread_sem); continue; } set_current_state(TASK_RUNNING); //这里调用了mmc_blk_issue_rq开始处理请求 mq->issue_fn(mq, req); } while (1); remove_wait_queue(&mq->thread_wq, &wait); up(&mq->thread_sem); //调用请求处理完后的回调函数 complete_and_exit(&mq->thread_complete, 0); return 0; }
函数mmc_blk_issue_rq初始化MMC块请求结构后,向卡发出请求命令,并等待请求的完成,函数分析如下:
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; int ret; //认领控制器,发命令到卡设置card为选中状态 if (mmc_card_claim_host(card)) goto cmd_err; do { struct mmc_blk_request brq; struct mmc_command cmd; //初始化MMC块请求结构 memset(&brq, 0, sizeof(struct mmc_blk_request)); brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; brq.cmd.arg = req->sector << 9; brq.cmd.flags = MMC_RSP_R1; brq.data.timeout_ns = card->csd.tacc_ns * 10; brq.data.timeout_clks = card->csd.tacc_clks * 10; brq.data.blksz_bits = md->block_bits; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_R1B; if (rq_data_dir(req) == READ) {//读请求 brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; brq.data.flags |= MMC_DATA_READ; } else {//写 brq.cmd.opcode = MMC_WRITE_BLOCK; brq.cmd.flags = MMC_RSP_R1B; brq.data.flags |= MMC_DATA_WRITE; brq.data.blocks = 1; } brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL; brq.data.sg = mq->sg; brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); //等待请求完成 mmc_wait_for_req(card->host, &brq.mrq); …… do { int err; cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1; err = mmc_wait_for_cmd(card->host, &cmd, 5); if (err) { printk(KERN_ERR "%s: error %d requesting status\n", req->rq_disk->disk_name, err); goto cmd_err; } } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); //一个块被成功传输 spin_lock_irq(&md->lock); ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); if (!ret) { //整个请求完全成功完成 add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req);//从队列中删除请求 end_that_request_last(req);//写一些更新信息 } spin_unlock_irq(&md->lock); } while (ret); mmc_card_release_host(card); return 1; cmd_err: mmc_card_release_host(card); spin_lock_irq(&md->lock); do { //结束请求req上的I/O,操作成功时返回0 ret = end_that_request_chunk(req, 0, req->current_nr_sectors << 9); } while (ret); add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req); end_that_request_last(req); spin_unlock_irq(&md->lock); return 0; }
函数mmc_card_claim_host发出命令选择这个卡card,函数列出如下(在 include/linuc/mmc/card.h中):
static inline int mmc_card_claim_host(struct mmc_card *card) { return __mmc_claim_host(card->host, card); }
函数__mmc_claim_host专有地认领一个控制器,参数host是认领的mmc控制器,参数card是去认领控制器的卡。函数__mmc_claim_host为一套操作认领一个控制器,如果card是被传递的一个有效的卡,并且它不是上次被选择的卡,那么在函数返回之前发出命令选择这个卡card。
函数__mmc_claim_host分析如下(在drivers/mmc/mmc.c中):
int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) { DECLARE_WAITQUEUE(wait, current);//给当前进程声明一个等待队列 unsigned long flags; int err = 0; add_wait_queue(&host->wq, &wait);//加host->wq到等待队列中 spin_lock_irqsave(&host->lock, flags); while (1) { set_current_state(TASK_UNINTERRUPTIBLE);//设置当前进程不可中断状态 if (host->card_busy == NULL) //如果没有忙的卡,跳出循环 break; spin_unlock_irqrestore(&host->lock, flags); schedule(); //如果有忙的卡,去调度执行 spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING);//设置当前进程为运行状态 host->card_busy = card; //指定当前忙的卡 spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); //从等待队列中移去host->wq //如果卡不是选择状态,发出命令到卡设置为选择状态 if (card != (void *)-1 && host->card_selected != card) { struct mmc_command cmd; host->card_selected = card; cmd.opcode = MMC_SELECT_CARD; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1; //等待命令完成 err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); } return err; }
函数mmc_wait_for_req开始执行一个请求并等待请求完成,函数分析如下(在drivers/mmc/mmc.c中):
int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) { DECLARE_COMPLETION(complete); mrq->done_data = &complete; mrq->done = mmc_wait_done; mmc_start_request(host, mrq); wait_for_completion(&complete); return 0; }
函数mmc_start_request开始排队执行一个在控制器上的命令,参数host是执行命令的控制器,参数mrq是将要开始执行的请求。调用者应持有锁并且关中断。
函数mmc_start_request分析如下(在drivers/mmc/mmc.c中):
void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { DBG("MMC: starting cmd %02x arg %08x flags %08x\n", mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); WARN_ON(host->card_busy == NULL); mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { mrq->cmd->data = mrq->data; mrq->data->error = 0; mrq->data->mrq = mrq; if (mrq->stop) { mrq->data->stop = mrq->stop; mrq->stop->error = 0; mrq->stop->mrq = mrq; } } //调用请求处理函数,对于amba主控制器来说就是mmci_request函数 host->ops->request(host, mrq); }