新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Linux內核的Nand驅動流程分析

        Linux內核的Nand驅動流程分析

        作者: 時間:2016-11-28 來源:網絡 收藏
        1. staticints3c24xx_nand_probe(structplatform_device*pdev)
        2. {
        3. structs3c2410_platform_nand*plat=to_nand_plat(pdev);
        4. enums3c_cpu_typecpu_type;
        5. structs3c2410_nand_info*info;
        6. structs3c2410_nand_mtd*nmtd;
        7. structs3c2410_nand_set*sets;
        8. structresource*res;
        9. interr=0;
        10. intsize;
        11. intnr_sets;
        12. intsetno;
        13. cpu_type=platform_get_device_id(pdev)->driver_data;
        14. pr_debug("s3c2410_nand_probe(%p)",pdev);
        15. info=kzalloc(sizeof(*info),GFP_KERNEL);
        16. if(info==NULL){
        17. dev_err(&pdev->dev,"nomemoryforflashinfo");
        18. err=-ENOMEM;
        19. gotoexit_error;
        20. }
        21. platform_set_drvdata(pdev,info);
        22. spin_lock_init(&info->controller.lock);
        23. init_waitqueue_head(&info->controller.wq);
        24. /*gettheclocksourceandenableit*/
        25. info->clk=clk_get(&pdev->dev,"nand");
        26. if(IS_ERR(info->clk)){
        27. dev_err(&pdev->dev,"failedtogetclock");
        28. err=-ENOENT;
        29. gotoexit_error;
        30. }
        31. s3c2410_nand_clk_set_state(info,CLOCK_ENABLE);
        32. /*allocateandmaptheresource*/
        33. /*currentlyweassumewehavetheoneresource*/
        34. res=pdev->resource;
        35. size=resource_size(res);
        36. info->area=request_mem_region(res->start,size,pdev->name);
        37. if(info->area==NULL){
        38. dev_err(&pdev->dev,"cannotreserveregisterregion");
        39. err=-ENOENT;
        40. gotoexit_error;
        41. }
        42. info->device=&pdev->dev;
        43. info->platform=plat;
        44. info->regs=ioremap(res->start,size);
        45. info->cpu_type=cpu_type;
        46. if(info->regs==NULL){
        47. dev_err(&pdev->dev,"cannotreserveregisterregion");
        48. err=-EIO;
        49. gotoexit_error;
        50. }
        51. dev_dbg(&pdev->dev,"mappedregistersat%p",info->regs);
        52. /*initialisethehardware*/
        53. err=s3c2410_nand_inithw(info);
        54. if(err!=0)
        55. gotoexit_error;
        56. sets=(plat!=NULL)?plat->sets:NULL;
        57. nr_sets=(plat!=NULL)?plat->nr_sets:1;
        58. info->mtd_count=nr_sets;
        59. /*allocateourinformation*/
        60. size=nr_sets*sizeof(*info->mtds);
        61. info->mtds=kzalloc(size,GFP_KERNEL);
        62. if(info->mtds==NULL){
        63. dev_err(&pdev->dev,"failedtoallocatemtdstorage");
        64. err=-ENOMEM;
        65. gotoexit_error;
        66. }
        67. /*initialiseallpossiblechips*/
        68. nmtd=info->mtds;
        69. for(setno=0;setno
        70. pr_debug("initialisingset%d(%p,info%p)",setno,nmtd,info);
        71. s3c2410_nand_init_chip(info,nmtd,sets);
        72. nmtd->scan_res=nand_scan_ident(&nmtd->mtd,
        73. (sets)?sets->nr_chips:1,
        74. NULL);
        75. if(nmtd->scan_res==0){
        76. s3c2410_nand_update_chip(info,nmtd);
        77. nand_scan_tail(&nmtd->mtd);
        78. s3c2410_nand_add_partition(info,nmtd,sets);
        79. }
        80. if(sets!=NULL)
        81. sets++;
        82. }
        83. err=s3c2410_nand_cpufreq_register(info);
        84. if(err<0){
        85. dev_err(&pdev->dev,"failedtoinitcpufreqsupport");
        86. gotoexit_error;
        87. }
        88. if(allow_clk_suspend(info)){
        89. dev_info(&pdev->dev,"clockidlesupportenabled");
        90. s3c2410_nand_clk_set_state(info,CLOCK_SUSPEND);
        91. }
        92. pr_debug("initialisedok");
        93. return0;
        94. exit_error:
        95. s3c24xx_nand_remove(pdev);
        96. if(err==0)
        97. err=-EINVAL;
        98. returnerr;
        99. }
        對于我們的Nand驅動來說,調用這個函數的參數當然是s3c_device_nand,閱讀代碼就可以知道前面定義每個變量的原理了。我看到函數開頭定義的res就想到了我們前面定義的s3c_nand_resource,往下看能看到
        1. res=pdev->resource;
        2. size=resource_size(res);
        也就是說,這里引用了我們前面定義的s3c_device_nand,我們看下他如何使用的(如果前面的已經忘記了,沒關系,退回去看一下),緊接著下面幾行代碼
        1. info->area=request_mem_region(res->start,size,pdev->name);
        2. if(info->area==NULL){
        3. dev_err(&pdev->dev,"cannotreserveregisterregion");
        4. err=-ENOENT;
        5. gotoexit_error;
        6. }
        顯然,這里的request_mem_region用到的參數實際上就是我們前面定義的s3c_device_nand中的start,size當然就是end-start得到的,還有就是設備的名字,我們前面定義的是"s3c2410-nand",從函數名稱可以看出,這里是通過res來申請mem資源,具體的可以自己閱讀下代碼,實際上request_mem_region是個宏,它調用了另外一個函數,這里我就不作分析了。繼續往下看,又看到一行
        1. info->regs=ioremap(res->start,size);
        ioremap函數的作用是將物理地址影射到虛擬地址,這里就是將s3c_device_nand中記錄的Nand寄存器首地址開始的1M空間作了映射,這也就理解為什么是1M空間了,因為內核的一級頁表是以1M為單位的,現在就清楚為什么要定義這個s3c_nand_resource了,因為Linux內核使用的地址空間是啟動MMU后的虛擬地址空間,而我們給出的寄存器地址是物理地址,內核需要將寄存器的物理地址映射到虛擬地址才能正確訪問寄存器,到這里我們知道驅動程序已經可以正確訪問Nand寄存器了,前面的疑惑解開了。

        本文引用地址:http://www.104case.com/article/201611/322799.htm

        繼續往下看代碼,到for循環處停下來,我們需要注意一下這部分代碼,因為我們看到了s3c2410_nand_init_chip,從函數名稱上很容易可以看出,這就是Nand的初始化代碼,但是這里為什么要使用一個for循環呢?我們看到循環控制變量是nr_sets,往上可以找到

        1. sets=(plat!=NULL)?plat->sets:NULL;
        2. nr_sets=(plat!=NULL)?plat->nr_sets:1;
        也就是說sets和nr_sets是從plat中獲取的,再往上找plat
        1. structs3c2410_platform_nand*plat=to_nand_plat(pdev);
        在函數的開頭部分我們找到了plat的定義,看來plat是pdev中獲取到的,我們跟蹤進入這個to_nand_plat函數看個究竟
        1. staticstructs3c2410_platform_nand*to_nand_plat(structplatform_device*dev)
        2. {
        3. returndev->dev.platform_data;
        4. }
        這個函數很簡單,就是直接返回了s3c_nand_device中的dev成員的platform_data,而前面我們看到的代碼中沒有出現這個變量,從plat定義處指出的類型可知,這個platform_data的類型是s3c2410_platform_nand,這時,我們可以回到最開始的文件,arch/arm/mach-s3c24xx/mach-mini2440.h,可以找到mini2440_init函數中有這樣一行代碼


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 茶陵县| 旌德县| 青神县| 青阳县| 满城县| 綦江县| 桦川县| 武胜县| 康保县| 山东| 宁安市| 广汉市| 钟山县| 东乌| 泸州市| 犍为县| 虹口区| 龙胜| 德阳市| 肇源县| 昌都县| 增城市| 抚顺市| 贺兰县| 微山县| 冀州市| 万年县| 邯郸市| 南昌县| 扎囊县| 巴林左旗| 石泉县| 张家口市| 闽清县| 麻城市| 柳江县| 西充县| 南部县| 兴业县| 永州市| 沂南县|