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

Linux内核的Nand驱动流程分析

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

  1. FINE_RES_MEM_NAMED((_start),(_size),NULL)

我这里整合了一下上面的信息,将相关的宏都做了一下追踪,因此,s3c_nand_resource的实际定义为

  1. {
  2. .start=(S3C_PA_NAND),
  3. .end=(S3C_PA_NAND)+(SZ_1M)-1,
  4. .name=(NULL),
  5. .flags=(IORESOURCE_MEM),
  6. }

追踪可知,S3C_PA_NAND定义如下

  1. #defineS3C2410_PA_NAND(0x4E000000)
  2. #defineS3C24XX_PA_NANDS3C2410_PA_NAND
  3. #defineS3C_PA_NANDS3C24XX_PA_NAND

也就是说,S3C_PA_NAND是Nand flash寄存器首地址,而SZ_1M明显是个长度,因此,这里的resource实际上是Nand flash寄存器首地址跟接下来的1M空间,可是,Nand的寄存器并没有那么多,这又是为什么呢?这些信息有什么用又在哪里用到了呢?答案很简单,这肯定是给驱动程序使用的了,带着这个疑问我们继续分析代码。定位到/drivers/mtd/nand/s3c2410.c,浏览代码可以看到驱动结构定义

  1. staticstructplatform_drivers3c24xx_nand_driver={
  2. .probe=s3c24xx_nand_probe,
  3. .remove=s3c24xx_nand_remove,
  4. .suspend=s3c24xx_nand_suspend,
  5. .resume=s3c24xx_nand_resume,
  6. .id_table=s3c24xx_driver_ids,
  7. .driver={
  8. .name="s3c24xx-nand",
  9. .owner=THIS_MODULE,
  10. },
  11. };

可以看到,这里指定了结构中的各种操作的函数指针,从名字上可以看出probe是加载驱动程序后执行的第一个函数,remove是移除驱动前最后执行的函数,suspend是挂起操作,等等。先不着急分析这些函数,先来看看内核是如何加载驱动的,s3c24xx_nand_driver又是如何注册到内核的。往下浏览代码可以看到

  1. staticint__inits3c2410_nand_init(void)
  2. {
  3. printk("S3C24XXNANDDriver,(c)2004SimtecElectronics");
  4. returnplatform_driver_register(&s3c24xx_nand_driver);
  5. }
  6. staticvoid__exits3c2410_nand_exit(void)
  7. {
  8. platform_driver_unregister(&s3c24xx_nand_driver);
  9. }
  10. module_init(s3c2410_nand_init);
  11. module_exit(s3c2410_nand_exit);
  12. MODULE_LICENSE("GPL");
  13. MODULE_AUTHOR("BenDooks");
  14. MODULE_DESCRIPTION("S3C24XXMTDNANDdriver");

显然,加载该驱动时s3c2410_nand_init函数将s3c24xx_nand_driver注册到了内核,卸载该驱动时s3c2410_nand_exit将s3c24xx_nand_driver注销,但是这两个函数也不过是两个普通函数,内核如何知道加载驱动时运行s3c2410_nand_init,卸载驱动时运行s3c2410_nand_exit呢?下面的module_init和module_exit解决了这个问题,它们分别告诉内核驱动程序的入口和出口。至于下面的MODULE_LICENSE指定了内核的权限协议,这里指定内核为GPL协议的,只有符合这个协议才能调用这个协议内的函数,因此是驱动程序必须的部分,剩下的两行是驱动的作者和描述,无关紧要,可以没有。现在我们明白了内核如何加载驱动了,我们再去分析probe函数,往上浏览代码可以找到

  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

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

网站地图

Top