微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux内核的Nand驱动流程分析

Linux内核的Nand驱动流程分析

时间:11-28 来源:互联网 点击:

  1. (err!=0)
  2. gotoexit_error;
  3. sets=(plat!=NULL)?plat->sets:NULL;
  4. nr_sets=(plat!=NULL)?plat->nr_sets:1;
  5. info->mtd_count=nr_sets;
  6. /*allocateourinformation*/
  7. size=nr_sets*sizeof(*info->mtds);
  8. info->mtds=kzalloc(size,GFP_KERNEL);
  9. if(info->mtds==NULL){
  10. dev_err(&pdev->dev,"failedtoallocatemtdstorage");
  11. err=-ENOMEM;
  12. gotoexit_error;
  13. }
  14. /*initialiseallpossiblechips*/
  15. nmtd=info->mtds;
  16. for(setno=0;setno
  17. pr_debug("initialisingset%d(%p,info%p)",setno,nmtd,info);
  18. s3c2410_nand_init_chip(info,nmtd,sets);
  19. nmtd->scan_res=nand_scan_ident(&nmtd->mtd,
  20. (sets)?sets->nr_chips:1,
  21. NULL);
  22. if(nmtd->scan_res==0){
  23. s3c2410_nand_update_chip(info,nmtd);
  24. nand_scan_tail(&nmtd->mtd);
  25. s3c2410_nand_add_partition(info,nmtd,sets);
  26. }
  27. if(sets!=NULL)
  28. sets++;
  29. }
  30. err=s3c2410_nand_cpufreq_register(info);
  31. if(err<0){
  32. dev_err(&pdev->dev,"failedtoinitcpufreqsupport");
  33. gotoexit_error;
  34. }
  35. if(allow_clk_suspend(info)){
  36. dev_info(&pdev->dev,"clockidlesupportenabled");
  37. s3c2410_nand_clk_set_state(info,CLOCK_SUSPEND);
  38. }
  39. pr_debug("initialisedok");
  40. return0;
  41. exit_error:
  42. s3c24xx_nand_remove(pdev);
  43. if(err==0)
  44. err=-EINVAL;
  45. returnerr;
  46. }

对于我们的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寄存器了,前面的疑惑解开了。

继续往下看代码,到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函数中有这样一行代码

  1. s3c_nand_set_platdata(&mini2440_nand_info);

这就是上面platform_data的来源,找到mini2440_nand_info的定义也就找到了上面用到的platform_data

  1. /*NANDFlashonMINI2440board*/
  2. staticstructmtd_partitionmini2440_default_nand_part[]__initdata={
  3. [0]={
  4. .name="u-boot",
  5. .size=SZ_256K,
  6. .offset=0,
  7. },
  8. [1]={
  9. .name="u-boot-env",
  10. .size=S

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top