新聞中心

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

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

作者: 時間: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驅動來說,調(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)核需要將寄存器的物理地址映射到虛擬地址才能正確訪問寄存器,到這里我們知道驅動程序已經(jīng)可以正確訪問Nand寄存器了,前面的疑惑解開了。

本文引用地址:http://butianyuan.cn/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ù)中有這樣一行代碼


評論


技術專區(qū)

關閉