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抽象设备层相关结构



(1)设备描述结构




图 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) 读写请求相关结构




图 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块设备驱动程序探测函数





图 函数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卡请求的处理





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

}