在全志平台裡,script.bin用于指定SOC控制器和GPIO等相關的配置. script.bin是由script.fex用工具轉換得來.
在uboot啟動系統時, uboot的環境變量bootcmd為:
也就是說script.bin在核心啟動前需要放在記憶體位址0x43000000.
在核心源碼”arch/arm/mach-sunxi/sys_config.c”裡對script.bin進行處理.
int __init script_init(void)
{
int i, j, count;
script_origin_head_t *script_hdr = __va(SYS_CONFIG_MEMBASE); //SYS_CONFIG_MEMBASE就是記憶體位址
script_origin_main_key_t *origin_main;
script_origin_sub_key_t *origin_sub;
script_main_key_t *main_key;
script_sub_key_t *sub_key, *tmp_sub, swap_sub;
...
script_init函數是在核心啟動時,在源碼”arch/arm/kernel/setup.c”調用的:
#ifdef CONFIG_ARCH_SUNXI
/* init sys_config script parse */
script_init();
#endif
//
通過閱讀sys_config.c裡的源碼可得知,script.bin其實也是一個文本檔案而已,裡面的内容是按結構體類型進行存放.
在script.bin檔案裡:
先存放檔案頭, 接着存放所有的主鍵項, 每個主鍵項的子鍵又集中存放在一塊區域裡, 每個子鍵項的内容又存放在另一個地方.
用到的類型:
#pragma pack(1)
typedef struct
{
char name[]; //名字
int offset; //以4位元組為機關, 此子鍵的值與頭位址的偏移.如果此鍵是關于gpio, 子鍵的值的位址還需減32位元組
struct {
u32 cnt : ; // 以4位元組為機關,表示子鍵的值的長度
u32 type: ; //type of sub key, int(1) / string(2) / gpio(4/5)
}pattern;
} script_origin_sub_key_t; //子鍵的類型
typedef struct
{
char name[]; //主鍵的名字
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[]; //版本
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[]; // 沒用
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 < )
{
perror("open script.bin");
return ;
}
struct stat sbuf;
fstat(fd, &sbuf);
head = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, );
if (MAP_FAILED == head)
{
perror("mmap");
return ;
}
////////////////
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 = ; 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 ( == sub[j].pattern.type) //子鍵的值是int
printf("%d\n", *(int *)((char *)head+sub[j].offset*4));
if ( == 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"裡還提供了使用者調用的接口:
) //讀取一個主鍵下所有子鍵的接口
echo "gpio_para" > /sys/class/script/dump
cat /sys/class/script/dump
) //指定讀取一個主鍵下的一個子鍵的值(字元串有亂碼)
echo "spi_board0 modalias" > /sys/class/script/get_item
cat /sys/class/scripit/get_item