利用mmc_test.c研究mmc模块

原文地址:

http://blog.csdn.net/tmkeepgood/article/details/39322257       

 

        近日开始研究mmc模块。老是看代码不免困意来袭,为了克服困意,可以通过一些小的试验来加深对该模块的理解。

        第一步:

        首先,自己创建了一个小的测试模块,通过获取mmc模块初始化时sdhci_host结构体的指针(初始化时就将这些sdhci_host结构的指针保存在一个数组,并提供接口导出该数组首地址供其它模块使用)为神秘的mmc子系统打开一扇窗口。


注册sdhci_host的文件中需要做如下改动:

  1. <xxx-sdhci-fix.c>  
  2. static unsigned int host_addr[5] = {0};   
  3. static unsigned int host_count = 0;   
  4.   
  5. static int xxx_sdhci_host_probe(struct platform_device *pdev)  
  6. {  
  7. ...  
  8.         host = sdhci_alloc_host(&pdev->dev, sizeof(struct xxx_sdhci_host));  
  9.         host_addr[host_count ++] = host;  
  10. ...  
  11.   
  12. }  
  13.   
  14. unsigned int *export_host_addr()  
  15. {  
  16.         return host_addr;  
  17. }  
  18. EXPORT_SYMBOL(export_host_addr);  
<xxx-sdhci-fix.c>
static unsigned int host_addr[5] = {0}; 
static unsigned int host_count = 0; 

static int xxx_sdhci_host_probe(struct platform_device *pdev)
{
...
        host = sdhci_alloc_host(&pdev->dev, sizeof(struct xxx_sdhci_host));
        host_addr[host_count ++] = host;
...

}

unsigned int *export_host_addr()
{
        return host_addr;
}
EXPORT_SYMBOL(export_host_addr);


测试文件获取到sdhci_host结构体的方法:

 

  1. <test.c>  
  2. extern unsigned int *export_host_addr();  
  3.   
  4. int test_init()  
  5. {  
  6. ...  
  7.         unsigned int *host_addr = export_host_addr();  
  8.         struct sdhci_host *host = NULL;  
  9.         struct mmc_host *mmc = NULL;  
  10.         struct mmc_card *card = NULL;  
  11. ...  
  12.         host = (struct sdhci_host *)host_addr[0];//至此,我们已经成功获取到sdhci_host   
  13.         mmc = host->mmc;  
  14.         card = mmc->card;  
  15. ...  
  16. }  
<test.c>
extern unsigned int *export_host_addr();

int test_init()
{
...
        unsigned int *host_addr = export_host_addr();
        struct sdhci_host *host = NULL;
        struct mmc_host *mmc = NULL;
        struct mmc_card *card = NULL;
...
        host = (struct sdhci_host *)host_addr[0];//至此,我们已经成功获取到sdhci_host
        mmc = host->mmc;
        card = mmc->card;
...
}


 

 

        通过上述代码可以看出,我们获取到sdhci_host结构体之后,可以进一步获取到对应的mmc_host 结构体,进而获取到和该控制器对应的mmc_card结构体。我当前的mmc子系统用到3个mmc_host(mmc/sdio/sd),对应两个mmc_card:mmc——emmc,sd——外接sd卡。

 

        第二步:

        获取到这些重要的结构体后,我们就可以参考mmc_init的流程,向mmc发送一些指令,如go_idle/send_op_cond/send_cid/send_csd/send_ext_csd(遵循mmc_init流程,其他指令都能顺利执行,唯独send_ext_csd指令会超时,至今原因不明,哪位朋友知道请告知,不胜感激)等,掌握mmc控制器和card交互的最基本指令。

 

        第三步: 

        接下来,想研究一下I/O接口的调用方法,毕竟emmc/sd卡最重要的作用是用来存储数据。恰好,在mmc/card/目录下发现了文件mmc_test.c,打开一看,好像有用来测试读写接口的方法,真是天助我也!果断将该文件编译为动态模块,但加载后发现并未执行任何实际操作,仅仅添加了一个测试驱动。继续看代码,发现只有触发probe函数才会做一些具体的事情:在debugfs中创建两个文件节点test和testlist,供用户通过"echo/cat"指令进行操作——事实上所有实际工作都是用户通过操纵在debug文件系统中创建的两个节点来进行。我们知道,想要触发probe函数,还需要注册一个和驱动名一致的设备。难道我们为了创建这两个文件节点,一定要注册一个名为"mmc_test"的设备才行吗?

 

        答案是不需要如此麻烦!我们完全可以将这两个创建文件节点的接口移到init函数中嘛,或者直接在init函数中就去调用probe函数,问题不久迎刃而解了吗?

 

        再来看probe函数,只需要给它传入一个合法的mmc_card指针就足够了,而我们在第一步已经介绍过如何获取到合法的mmc_card指针,这里直接拿来用就可以了(mmc = sdhci_host->mmc, card = mmc->card)。

 

        万事俱备,开始试验!

root@scx35_sp7731gea:/sys/kernel/debug/mmc1/mmc1:1234 # ls
ls
state
status
test
testlist


        加载该测试模块后可以看到,在该目录下创建了2个测试节点:test和testlist。执行第25项测试的指令如下:
root@scx35_sp7731gea:/sys/kernel/debug/mmc1/mmc1:1234 # echo 25 > test


      测试结果如下:
<6>[ 2479.634882] c1 mmc_test: mmc1: Starting tests of card mmc1:1234...
<6>[ 2479.634912] c1 mmc_test: mmc1: Test case 25. Best-case read performance into scattered pages...
<6>[ 2479.748526] c2 mmc_test: mmc1: Transfer of 1 x 8 sectors (1 x 4 KiB) took 0.000564193 seconds (7259 kB/s, 7089 KiB/s, 1772.44 IOPS, sg_len 1)
<6>[ 2479.748570] c2 mmc_test: mmc1: Result: OK
<6>[ 2479.748633] c2 mmc_test: mmc1: Tests completed.

 

       下述指令,可以看出test模块支持的测试项:
root@scx35_sp7731gea:/sys/kernel/debug/mmc1/mmc1:1234 # cat testlist
cat testlist
1:      Basic write (no data verification)
2:      Basic read (no data verification)
3:      Basic write (with data verification)
4:      Basic read (with data verification)
5:      Multi-block write
6:      Multi-block read
7:      Power of two block writes
8:      Power of two block reads
9:      Weird sized block writes
10:     Weird sized block reads
11:     Badly aligned write
12:     Badly aligned read
13:     Badly aligned multi-block write
14:     Badly aligned multi-block read
15:     Correct xfer_size at write (start failure)
16:     Correct xfer_size at read (start failure)
17:     Correct xfer_size at write (midway failure)
18:     Correct xfer_size at read (midway failure)
19:     Highmem write
20:     Highmem read
21:     Multi-block highmem write
22:     Multi-block highmem read
23:     Best-case read performance
24:     Best-case write performance
25:     Best-case read performance into scattered pages
26:     Best-case write performance from scattered pages
27:     Single read performance by transfer size
28:     Single write performance by transfer size
29:     Single trim performance by transfer size
30:     Consecutive read performance by transfer size
31:     Consecutive write performance by transfer size
32:     Consecutive trim performance by transfer size
33:     Random read performance by transfer size
34:     Random write performance by transfer size
35:     Large sequential read into scattered pages
36:     Large sequential write from scattered pages
37:     Write performance with blocking req 4k to 4MB
38:     Write performance with non-blocking req 4k to 4MB
39:     Read performance with blocking req 4k to 4MB
40:     Read performance with non-blocking req 4k to 4MB
41:     Write performance blocking req 1 to 512 sg elems
42:     Write performance non-blocking req 1 to 512 sg elems
43:     Read performance blocking req 1 to 512 sg elems
44:     Read performance non-blocking req 1 to 512 sg elems
45:     eMMC hardware reset

        由此,可以打开一个操作mmc/sd卡的入口,再结合代码,很轻松就可以弄清楚各个指令是如何调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值