现在的位置: 首页 > 综合 > 正文

SD/MMC卡块设备驱动程序

2012年09月10日 ⁄ 综合 ⁄ 共 8122字 ⁄ 字号 评论关闭

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
=

抱歉!评论已关闭.