zoukankan      html  css  js  c++  java
  • linux驱动移植的重要数据结构

    转载:http://www.embeddedlinux.org.cn/html/jishuzixun/201304/14-2538.html

     

    对于嵌入式 Linux 系统来说,有各种体系结构的处理器和硬件平台,并且用户需要根据需求自己定制硬件板。只要是硬件平台有些变化,即使非常小,可能也需要做一些移植工作。内核移植是嵌入式Linux系统中最常见的一项工作。

    内核移植工作主要是修改跟硬件平台相关的代码,一般不涉及 Linux 内核通用的程序。

    移植的难度也取决于两种硬件平台的差异。Linux 对于特定的硬件平台的软件就叫作 BSP

    Board Support Package)。

    由于 Linux 内核具备可移植性的特点,并且已经支持了各种体系结构的很多种目标板,

    我们很容易从中找到跟自己硬件类似的目标板。参考内核已经支持的目标板来移植 BSP,就

    如同使用模板开发程序。

    因此,移植linux内核的过程大多数情况下就是移植BSP的过程。三星公司提供了smdk24xx开发板的BSP。对于mini2440开发板来说,移植linux内核,只要修改smdk24xx开发板的BSP使该linux支持mini2440开发板就可以了。

    linux内核源代码的ARCH目录存放的是体系结构相关的代码,对于每个架构的CPUarm目录下都有一个对应的目录,比如arch/armarch/i386。而arm架构的处理器种类又有很多,所以,在arch/arm目录下对于每种arm架构处理器也有一个对应的子目录,比如arch/arm/mach-s3c2440arch/arm/mach-s3c2410等。在arch/arm目录下有一个plat-s3c24xx目录,根据目录名它应该是与s3c24xx系列处理器的平台设备相关的一个目录。注意,所谓的"平台设备"并不是与字符设备、块设备和网络设备并列的概念,而是linux系统描述设备的一个附加手段。在plat-s3c24xx目录下有一个common-smdk.c文件,根据文件名,它应该是三星公司的smdk24xx系列开发板都需要的一个文件。在移植驱动的时候经常需要修改arch/arm/plat-s3c24xx/common-smdk.c文件。对于arch/arm/mach-s3c2440目录,它是专门用来保存 S3C2410 系列处理器平台相关程序,其中 Kconfig  Makefile 是用于内核配置编译的。其他文件分为 2 类,一类是处理器通

    用的,例如:clock.c clock.h cpu.c cpu.h s3c2410.c s3c2410.h等;另一类是目标板相关的,例如:bast.h bast-irq.c mach-bast.c等。在这些文件中,实现了处理器和目标板相关的一些定义和初始化函数。还有些相关的定义包含在 include/asm-arm/arch-s3c2410/下的头文件中。

        linux内核中对于每种支持的开发板都会使用宏MACHINE_STARTMACHINE_END来定义一个machine_desc结构。MACHINE_STARTMCHINE_END的定义如下:

    1/*include/asm-arm/mach/arch.h */

    #define MACHINE_START(_type,_name)         

    static const struct machine_desc __mach_desc_##_type   

     __used                        

     __attribute__((__section__(".arch.info.init"))) = {   

        .nr     = MACH_TYPE_##_type,       

        .name       = _name,

       

    #define MACHINE_END            

    };

    在arch/arm/mach-s3c2410/mach-smdk2440.c中可以找到SMDK2440开发板的定义如下:

       

    MACHINE_START(S3C2440, "SMDK2440")

        .phys_io    = S3C2410_PA_UART,

        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

        .boot_params    = S3C2410_SDRAM_PA + 0x100,

       

        .init_irq   = s3c24xx_init_irq,

        .map_io     = smdk2440_map_io,

        .init_machine   = smdk2440_machine_init,

        .timer      = &s3c24xx_timer,

    MACHINE_END

    把MACHINE_START、MACHINE_END扩展开来就是定义了一个名为__mach_desc_S3C2440的结构体变量:

    const struct machine_desc __mach_desc_S3C2440 __used

     __attribute__((__section__(".arch.info.init"))) =

    {  

        .nr    = MACH_TYPE_S3C2440,             //开发板的机器类型ID

        .name    = "SMDK2440",                   //开发板名称

        .phys_io    = S3C2410_PA_UART,              //起始IO物理地址

        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

        .boot_params    = S3C2410_SDRAM_PA + 0x100, //内核启动参数的地址

        .init_irq   = s3c24xx_init_irq,         //中断初始化函数

        .map_io     = smdk2440_map_io,          //IO映射函数(在这里修改时钟频率)

        .init_machine   = smdk2440_machine_init,

        .timer      = &s3c24xx_timer,    

    };

    MACH_TYPE_S3C2440可以看作是系统平台号,它包含在include/asm- arm/mach-types.h头文件中,不过这个头文件是在配置内核或编译内核时自动生成的,所以不能更改。。真正系统平台号

    的定义位置在arch/arm/tools/mach-types文件中。

    # machine_is_xxx        CONFIG_xxxx      MACH_TYPE_xxx       number

    s3c2440          ARCH_S3C2440           S3C2440          362

    arch/arm/tools/mach-types中每一行定义一个系统平台号。 "machine_is_xxx"是用来判断当前的平台号是否正确的函数; "CONFIG_xxxx"是在内核配置时生成的; "MACH_TYPE_xxx"

    是系统平台号的定义; "number"是系统平台的值。 __mach_desc_S3C2440结构体中的函数将在内核启动过程中,完成系统平台的初始化工作

       对于具有相同处理器的系统平台,并不需要对每一个平台都编写一个BSP,如果他们的外围接口电路基本相同,也许只需修改一些数据的定义,修改几个函数的参数就可以了。

       

       

    2linux设计了一个通用的数据结构resource来描述各种I/O资源(比如,IO端口,DMA,中断等)

    include/linux/ioport.h

    struct resource

    {
     resource_size_t start;
     resource_size_t end;
     const char *name;
     unsigned long flags;
     struct resource *parent, *sibling, *child;
    };

    flags:资源标记,用于标识各种资源,例如IORESOURCE_MEM表示内存资源,IORESOURCE_IRQ表示中断资源

    对于内存资源,start表示内存起始物理地址,end:表示内存末尾物理地址

    对于中断资源,start表示起始中断号,end表示最后一个中断号

    常用资源数组来表示一个设备所拥有的各类资源,比如s3c2440的片内LCD控制器拥有的资源如下

    static struct resource s3c_lcd_resource[]=

    {

    [0]={

        .start=S3C24XX_PA_LCD,

        .end=S3C24XX_PA_LCD+S3C24XX_SZ_LCD-1,

        .flags=IORESOURCE_MEM,

    }

    [1]={

        .start=IRQ_LCD,

        .end=IRQ_LCD,

        .flags=IORESOURCE_IRQ,

        }

    };

    其中S3C24XX_PA_LCD被定义为0x4D000000S3C24XX_SZ_LCD被定义为1M。所以,在这里给LCD控制器分配的物理地址空间范围为0x4D0000000x4D0FFFFF,这些是LCD控制器各寄存器使用的地址,但实际上LCD控制器的寄存器地址的范围为0x4D000000~0x4D000060,使用0x4D0000000x4D000060给他们赋值也应该是可以的。IRQ_LCD算得是32,它会将GPG4引脚设为LCD_PWREN功能,因为GPG4LCD_PWREN/EINT12复用。

       

    3)在内核文件include/linux/platform_device.h中,定义了两个数据结构来表示设备和驱动程序:platform_device结构用来描述设备的名称、ID、所占用的资源(比如内存地址/大小、中断号)等;platform_driver结构用来描述各种操作函数,比如枚举函数、移除设备函数、驱动名称等。

       

       

    //平台设备

    struct platform_device     

    {

        const char * name;         //设备名

        int     id;

        struct device   dev;

        u32     num_resources;      // 设备所使用的各类资源数量

        struct resource * resource; // 设备的资源数组

        struct platform_device_id   *id_entry;

        struct pdev_archdata    archdata;

    };

    //平台驱动

    struct platform_driver     

    {

        int (*probe)(struct platform_device *);     //探测

        int (*remove)(struct platform_device *);        //移除

        void (*shutdown)(struct platform_device *); //关闭

        int (*suspend)(struct platform_device *, pm_message_t state);//挂起

        int (*resume)(struct platform_device *);        //恢复

        //描述驱动的名称(name)和属主(owner)等信息

        struct device_driver driver;                   

        struct platform_device_id *id_table;

    };

    内核启动后,首先构造链表将描述设备的platform_device构造组织起来,得到一个设备的列表;当加载某个驱动程序的platform_driver结构时,使用一些匹配函数来检查驱动程序能否支持这些设备,常用的检查方法很简单:比较驱动程序和设备的名称。

    以S3C2440开发板为例,在arch/arm/mach-s3c2440/mach-smdk2440.c中定义了如下设备:

    static struct platform_device *smdk2440_devices[] __initdata =

    {

        &s3c_device_usb,        //USB控制器

        &s3c_device_lcd,        //LCD控制器

        &s3c_device_wdt,        //看门狗

        &s3c_device_i2c,       

        &s3c_device_iis,       

    };

    在arch/arm/plat-s3c24xx/common-smdk.c中定义了如下设备:

    static struct platform_device __initdata *smdk_devs[] =

    {

        &s3c_device_nand,   //NAND FLASH

        &smdk_led4,

        &smdk_led5,

        &smdk_led6,

        &smdk_led7,

    };

  • 相关阅读:
    搞明白这八个问题,Linux系统就好学多了
    Fedora 25 Alpha版本今天发布啦
    Linux新手应掌握的10个基本命令
    PC-BSD 换名 TrueOS
    JPA+Springboot实现分页效果
    陈亮
    押尾光太郎
    岸部真明
    面试必备-网络的七层协议
    JavaScript中的快速排序
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/3280209.html
Copyright © 2011-2022 走看看