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