Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1072348
  • 博文数量: 277
  • 博客积分: 8313
  • 博客等级: 中将
  • 技术积分: 2976
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-22 11:25
文章分类

全部博文(277)

文章存档

2013年(17)

2012年(66)

2011年(104)

2010年(90)

我的朋友

分类: LINUX

2011-03-17 17:42:16

SD/MMC卡块设备驱动程序

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设备的管理。另一方面,要完成系统分发过来的读写请求的处理。


Linux kernel mtd mmc sd driver 11.gif
图 MMC驱动程序的层次结构

MMC抽象设备层相关结构

(1)设备描述结构

Linux kernel mtd mmc sd driver 10.gif
图 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 *);
};


(2) 读写请求相关结构

Linux kernel mtd mmc sd driver 02.gif
图 MMC卡读写请求结构示意图

对于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抽象设备层MMC块设备驱动程序

(1)MMC块设备驱动程序初始化

函数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);
}


(2)MMC块设备驱动程序探测函数


Linux kernel mtd mmc sd driver 12.gif
图 函数mmc_blk_probe调用层次图

函数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;
}


(3)MMC卡请求的处理


Linux kernel mtd mmc sd driver 01.gif
图 函数mmc_init_queue调用层次图

函数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);
}



阅读(2203) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~