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設備的管理。另一方面,要完成系統分發過來的讀寫請求的處理。


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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章