<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > Linux內(nèi)核的Nand驅(qū)動流程分析

          Linux內(nèi)核的Nand驅(qū)動流程分析

          作者: 時間:2016-11-28 來源:網(wǎng)絡 收藏
          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驅(qū)動來說,調(diào)用這個函數(shù)的參數(shù)當然是s3c_device_nand,閱讀代碼就可以知道前面定義每個變量的原理了。我看到函數(shù)開頭定義的res就想到了我們前面定義的s3c_nand_resource,往下看能看到
          1. res=pdev->resource;
          2. size=resource_size(res);
          也就是說,這里引用了我們前面定義的s3c_device_nand,我們看下他如何使用的(如果前面的已經(jīng)忘記了,沒關系,退回去看一下),緊接著下面幾行代碼
          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用到的參數(shù)實際上就是我們前面定義的s3c_device_nand中的start,size當然就是end-start得到的,還有就是設備的名字,我們前面定義的是"s3c2410-nand",從函數(shù)名稱可以看出,這里是通過res來申請mem資源,具體的可以自己閱讀下代碼,實際上request_mem_region是個宏,它調(diào)用了另外一個函數(shù),這里我就不作分析了。繼續(xù)往下看,又看到一行
          1. info->regs=ioremap(res->start,size);
          ioremap函數(shù)的作用是將物理地址影射到虛擬地址,這里就是將s3c_device_nand中記錄的Nand寄存器首地址開始的1M空間作了映射,這也就理解為什么是1M空間了,因為內(nèi)核的一級頁表是以1M為單位的,現(xiàn)在就清楚為什么要定義這個s3c_nand_resource了,因為Linux內(nèi)核使用的地址空間是啟動MMU后的虛擬地址空間,而我們給出的寄存器地址是物理地址,內(nèi)核需要將寄存器的物理地址映射到虛擬地址才能正確訪問寄存器,到這里我們知道驅(qū)動程序已經(jīng)可以正確訪問Nand寄存器了,前面的疑惑解開了。

          本文引用地址:http://www.ex-cimer.com/article/201611/322799.htm

          繼續(xù)往下看代碼,到for循環(huán)處停下來,我們需要注意一下這部分代碼,因為我們看到了s3c2410_nand_init_chip,從函數(shù)名稱上很容易可以看出,這就是Nand的初始化代碼,但是這里為什么要使用一個for循環(huán)呢?我們看到循環(huán)控制變量是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);
          在函數(shù)的開頭部分我們找到了plat的定義,看來plat是pdev中獲取到的,我們跟蹤進入這個to_nand_plat函數(shù)看個究竟
          1. staticstructs3c2410_platform_nand*to_nand_plat(structplatform_device*dev)
          2. {
          3. returndev->dev.platform_data;
          4. }
          這個函數(shù)很簡單,就是直接返回了s3c_nand_device中的dev成員的platform_data,而前面我們看到的代碼中沒有出現(xiàn)這個變量,從plat定義處指出的類型可知,這個platform_data的類型是s3c2410_platform_nand,這時,我們可以回到最開始的文件,arch/arm/mach-s3c24xx/mach-mini2440.h,可以找到mini2440_init函數(shù)中有這樣一行代碼


          評論


          技術(shù)專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();