38 全志平台的script.bin在linux内核里的应用分析

在全志平台里,script.bin用于指定SOC控制器和GPIO等相关的配置. script.bin是由script.fex用工具转换得来.

在uboot启动系统时, uboot的环境变量bootcmd为:

  bootcmd=ext4load mmc 0:1 0x43000000 /script.bin; ext4load mmc 0:1 0x42000000 /uImage; bootm 0x42000000

也就是说script.bin在内核启动前需要放在内存地址0x43000000.
在内核源码”arch/arm/mach-sunxi/sys_config.c”里对script.bin进行处理.


505 int __init script_init(void)
506 {
507     int     i, j, count;
508 
509     script_origin_head_t        *script_hdr = __va(SYS_CONFIG_MEMBASE); //SYS_CONFIG_MEMBASE就是内存地址0x43000000
510 
511     script_origin_main_key_t    *origin_main;
512     script_origin_sub_key_t     *origin_sub;
513 
514     script_main_key_t           *main_key;
515     script_sub_key_t            *sub_key, *tmp_sub, swap_sub;
    ...

script_init函数是在内核启动时,在源码”arch/arm/kernel/setup.c”调用的:

1088 #ifdef CONFIG_ARCH_SUNXI
1089     /* init sys_config script parse */
1090     script_init();
1091 #endif

//
通过阅读sys_config.c里的源码可得知,script.bin其实也是一个文本文件而已,里面的内容是按结构体类型进行存放.

在script.bin文件里:
先存放文件头, 接着存放所有的主键项, 每个主键项的子键又集中存放在一块区域里, 每个子键项的内容又存放在另一个地方.

用到的类型:

#pragma pack(1)

typedef struct
{
    char name[32]; //名字
    int  offset; //以4字节为单位, 此子键的值与头地址的偏移.如果此键是关于gpio, 子键的值的地址还需减32字节
    struct {
        u32 cnt : 16;  // 以4字节为单位,表示子键的值的长度
        u32 type: 16;  //type of sub key, int(1) / string(2) / gpio(4/5)
    }pattern;
} script_origin_sub_key_t; //子键的类型


typedef struct
{
    char name[32]; //主键的名字
    int  sub_cnt; //在此主键下有多少个子键
    int  offset; // 以4字节为单位,表示此主键的子键开始内容与script.bin的开始地址的偏移 
} script_origin_main_key_t; //主键的类型


typedef struct
{
    unsigned int main_cnt; //主键的个数
    unsigned int length; //值为0, 不明
    unsigned int version[2]; //版本
    script_origin_main_key_t    main_key; //第一个主键,主键就是在script.fex里如:[product]
} script_origin_head_t;  //script.bin的文件头 


// sprite_gpio0 = port:PL10<1><default><default><default>
typedef struct {
    char    gpio_name[32]; // 没用
    int     port; // PL
    int     port_num; // 10
    int     mul_sel; // 1
    int     pull; 
    int     drv_level;
    int     data;
} script_origin_gpio_t;  //当子键是一个关于IO口的项时,它的值就是这种类型


#pragma pack()

/
script.bin里的文件排列:

文件头

[主键结构体]
[主键结构体]
[主键结构体]
[主键结构体]
...

[子键结构体]
[子键结构体]
[子键结构体]
[子键结构体]
...

[子键的值]
[子键的值]
[子键的值]
[子键的值]


在主键结构体里都有offset成员来记录它的第1个子键与文件头的偏移, 在子键结构体由成员offset成员记录它的值与文件头偏移的位置.
文件头里有记录主键的个数,每个主键结构体里由成员sub_cnt记录属于此主键有多少个子键.

获取script.bin里所有主键,子键及其值的测试代码:
app.c

int main(void)
{
    int fd;
    script_origin_head_t *head;

    fd = open("./script.bin", O_RDONLY);
    if (fd < 0)
    {
        perror("open script.bin");
        return 1;
    }

    struct stat sbuf;
    fstat(fd, &sbuf);
    head = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if (MAP_FAILED == head)
    {
        perror("mmap");
        return 2;
    } 

    ////////////////
    script_origin_main_key_t *main = &head->main_key;
    script_origin_sub_key_t  *sub;
    script_origin_gpio_t *gpio;
    int i, j;

    for (i = 0; i < head->main_cnt; i++)
    {
        printf("[%s]:\n", main[i].name);    
        sub = (char *)head + main[i].offset * 4; //sub指针指向每个主键的第1个子键结构体
        for (j = 0; j < main[i].sub_cnt; j++)
        {
            printf("%s = ", sub[j].name);
            if (sub[j].pattern.type >= 4) //子键是关于gpio的
            {
                gpio = (char *)head + sub[j].offset * 4-32;
                printf("%d, %d, %d, %d, %d\n", gpio->port, gpio->port_num, gpio->mul_sel, gpio->pull, gpio->drv_level);
            }
            if (1 == sub[j].pattern.type) //子键的值是int
                printf("%d\n", *(int *)((char *)head+sub[j].offset*4));
            if (2 == sub[j].pattern.type) //子键的值是字符串
                printf("%s\n", (char *)head+sub[j].offset*4);

        }
        printf("\n");
    }   

    ///////////////
    munmap(head, sbuf.st_size);
    close(fd);
    return 0;
}


在linux内核源码”sys_config.c”里, 遍历script.bin的内容处理后,用哈希表存放起来.

struct gpio_config {
    u32 gpio;       /* gpio global index, must be unique */
    u32     mul_sel;    /* multi sel val: 0 - input, 1 - output... */
    u32     pull;       /* pull val: 0 - pull up/down disable, 1 - pull up... */
    u32     drv_level;  /* driver level val: 0 - level 0, 1 - level 1... */
    u32 data;       /* data val: 0 - low, 1 - high, only vaild when mul_sel is input/output */
};

typedef union {
    int                 val;
    char                *str;
    struct gpio_config  gpio;
} script_item_u; //每个子键的值只会是三种类型中的一种. int,  string, gpio

typedef struct {
    char                        name[SCRIPT_NAME_SIZE_MAX]; //子键名
    script_item_u               *value;  //子键的值
    script_item_value_type_e    type;   //子键值的类型
    int                         hash;  //子键的哈希值
    void                        *next;  
} script_sub_key_t; //用于存放处理过后的子键的项,挂载到主键哈希表的元素里。每个元素就是一个主键.

typedef struct {
    char                name[SCRIPT_NAME_SIZE_MAX];
    script_sub_key_t    *subkey;
    script_item_u       *subkey_val;
    script_item_u       *gpio;
    int                 gpio_cnt;
    int                 hash;
    void                *next;
} script_main_key_t; //用于存放处理过后的主键的哈希表

static script_main_key_t   *g_script; //哈希表, 在驱动代码就可以通过哈希表查找相应的主键或子键的值

//
同时, “sys_config.c”里也提供了导出函数,供设备驱动代码里获取script.bin里相应项的配置值.

script_item_value_type_e
script_get_item(char *main_key, char *sub_key, script_item_u *item)
{
    ...
}
EXPORT_SYMBOL(script_get_item);

//用法:  script_get_item("target", "boot_clock", &item);

int script_get_pio_list(char *main_key, script_item_u **list) //用于获取一个主键下所有关于gpio项的值
{
    ...
}
EXPORT_SYMBOL(script_get_pio_list);

//用法: script_get_pio_list("gpio_para", &list);

///

"sys_config.c"里还提供了用户调用的接口:

1)   //读取一个主键下所有子键的接口
    echo "gpio_para" > /sys/class/script/dump
    cat /sys/class/script/dump


2)  //指定读取一个主键下的一个子键的值(字符串有乱码)
    echo "spi_board0 modalias" > /sys/class/script/get_item
    cat /sys/class/scripit/get_item
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值