在全志平台里,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