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

Linux内核的Nand驱动流程分析

时间:11-28 来源:互联网 点击:
最近在做Linux内核移植,总体的感觉是这样的,想要彻底的阅读Linux内核代码几乎是不可能的,至少这还不是嵌入式学期初期的重要任务。内核代码解压后有250M左右,据统计,有400多万行,而且涉及到了软件和硬件两方面的诸多知识,凭一人之力在短时间内阅读Linux内核代码是根本不可能的,强行阅读可能会打消我们嵌入式学习的积极性,最后甚至可能放弃嵌入式学习,如果真的想阅读内核代码来提高自己水平的话可以等熟练掌握嵌入式以后再回过头来阅读,这样理解也会更深刻,更透彻。

我认为Linux内核移植的初期阶段应该将重点放在分析内核设备驱动上。实际上,Linux内核的移植就是设备驱动的移植,内核本身不会直接访问硬件,是通过驱动程序来间接控制硬件的,而其他的高级功能如内存管理,进程管理等是通用的,无需做其他配置,所以我们只需要配置相关的驱动即可实现Linux内核移植。驱动移植的关键在于了解在驱动的结构,本文将以Nand驱动为例,分析Linux内核的驱动结构。

在分析驱动结构之前,还需要了解下内核识别设备的方式,内核通过驱动程序识别设备的方法有两种,一种是驱动程序本身带有设备信息,比如开始地址、中断号等,加载驱动时就可以根据驱动中的信息来识别设备;另一种是驱动程序本身没有设备信息,但是内核中已经根据其他方式确定了很多设备信息,加载驱动时将驱动程序与这些设备逐个比较,确定两者是否匹配,如果匹配就可以使用该驱动来识别设备了。内核常采用的是第二种方式,这样方式可将各种设备集中在一个文件中管理,当开发板的配置改变时便于修改代码。对应的,内核文件include/linux/platform_device.h中定义了两个结构,一个是platform_device,用来描述设备信息,一个是platform_driver,用来描述驱动信息,内核启动后首先构造链表将plartfrom_device结构组织起来得到一个设备链表,当加载某个驱动时根据platform_driver提供的信息与设备链表一一进行匹配,这就是内核设备识别的大体过程,具体的过程比这复杂很多,这里不做过多研究。下面我们开始分析Linux内核的Nand驱动。

这里以Linux内核的3.5.3中默认的mini2440开发板为例,首先定位到arm/arm/mach-s3c24xx/mach-mini2440.c,然后找到如下结构:

  1. staticstructplatform_device*mini2440_devices[]__initdata={
  2. &s3c_device_ohci,
  3. &s3c_device_wdt,
  4. &s3c_device_i2c0,
  5. &s3c_device_rtc,
  6. &s3c_device_usbgadget,
  7. &mini2440_device_eth,
  8. &mini2440_led1,
  9. &mini2440_led2,
  10. &mini2440_led3,
  11. &mini2440_led4,
  12. &mini2440_button_device,
  13. &s3c_device_nand,
  14. &s3c_device_sdi,
  15. &s3c_device_iis,
  16. &uda1340_codec,
  17. &mini2440_audio,
  18. &samsung_asoc_dma,
  19. };

显然,这里就是内核需要的设备列表,通过后面的mini2440_init函数中的

  1. platform_add_devices(mini2440_devices,ARRAY_SIZE(mini2440_devices));

注册到内核,然后由内核进行管理,显然,跟我们分析的Nand相关的就是s3c_device_nand,这就代表我们开发版上的Nand flash,我们先定位到它的定义,在arch/arm/plat-samsung/devs.c中有如下代码

  1. staticstructresources3c_nand_resource[]={
  2. [0]=DEFINE_RES_MEM(S3C_PA_NAND,SZ_1M),
  3. };
  4. structplatform_devices3c_device_nand={
  5. .name="s3c2410-nand",
  6. .id=-1,
  7. .num_resources=ARRAY_SIZE(s3c_nand_resource),
  8. .resource=s3c_nand_resource,
  9. };

第二个 结构就是s3c_device_nand的定义,之所以带上第一个结构是因为定义s3c_device_nand时用到了s3c_nand_resource,我们先看一下s3c_device_nand的定义,s3c_device_nand只明确定义了Nand设备的名称和设备ID,并没有给出具体的寄存器信息,加上s3c_nand_resource的名字带有资源的意思,因此我们断定,寄存器信息应该在s3c_nand_resource中,从s3c_nand_resource的定义中我们只能看到很少的信息,要想了解具体信息需要看一下struct resource和宏DEFINE_RES_MEM的定义及

  1. structresource{
  2. resource_size_tstart;
  3. resource_size_tend;
  4. constchar*name;
  5. unsignedlongflags;
  6. structresource*parent,*sibling,*child;
  7. };

这里 可以看到,struct resource中定义了起始,结束,名字等信息,我们再来看一下DEFINE_RES_MEM的定义

  1. #defineDEFINE_RES_NAMED(_start,_size,_name,_flags)
  2. {
  3. .start=(_start),
  4. .end=(_start)+(_size)-1,
  5. .name=(_name),
  6. .flags=(_flags),
  7. }
  8. #defineDEFINE_RES_MEM_NAMED(_start,_size,_name)
  9. DEFINE_RES_NAMED((_start),(_size),(_name),IORESOURCE_MEM)
  10. #defineDEFINE_RES_MEM(_start,_size)
  11. DE

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

网站地图

Top