0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

描述u-boot驅(qū)動(dòng)模型的數(shù)據(jù)結(jié)構(gòu)

電子工程師 ? 來源:嵌入式小生 ? 作者:iriczhao ? 2022-08-08 14:52 ? 次閱讀


一、描述u-boot驅(qū)動(dòng)模型的數(shù)據(jù)結(jié)構(gòu)

u-boot有一個(gè)功能強(qiáng)大的驅(qū)動(dòng)模型,這一點(diǎn)與linux內(nèi)核一致。驅(qū)動(dòng)模型對(duì)設(shè)備驅(qū)動(dòng)相關(guān)操作做了一個(gè)抽象:使用uclass來描述設(shè)備類,使用driver來描述驅(qū)動(dòng),使用udevice來描述設(shè)備。

(1-1)uclass

uclass表示以相同特征方式運(yùn)行的一組device。uclass提供一種以相同接口方式訪問組內(nèi)單個(gè)設(shè)備的方式。例如:GPIO類提供了get/set值的操作。一個(gè)I2C類可能有10個(gè)I2C端口,其中4個(gè)用于一個(gè)驅(qū)動(dòng)程序,6個(gè)用于另一個(gè)驅(qū)動(dòng)程序。

該結(jié)構(gòu)由struct uclass表示(/include/dm/uclass.h):

structuclass{
void*priv;//這個(gè)類的私有數(shù)據(jù)
structuclass_driver*uc_drv;//類本身的驅(qū)動(dòng)程序,不要與struct driver混淆。
structlist_headdev_head;//該類中的設(shè)備列表(當(dāng)設(shè)備的綁定方法被調(diào)用時(shí),它們會(huì)被附加到它們的類上)。
structlist_headsibling_node;//類鏈表中的下一個(gè)類。
};

(1-2)driver

用于提供與外設(shè)交互的高級(jí)接口。本文將分析這一點(diǎn)。

(1-3)udevice

與特定端口或外圍設(shè)備綁定的驅(qū)動(dòng)程序?qū)嵗?/p>

二、聲明驅(qū)動(dòng)

通過分析u-boot的/drivers目錄下的文件可以得出u-boot驅(qū)動(dòng)程序具有共同的特征,驅(qū)動(dòng)程序聲明一般具有如下類似的結(jié)構(gòu)(參見drivers/demo/demo-shape.c):

staticconststructdemo_opsshape_ops={
.hello=shape_hello,
.status=shape_status,
};

U_BOOT_DRIVER(demo_shape_drv)={
.name="demo_shape_drv",
.id=UCLASS_DEMO,
.ops=&shape_ops,
.priv_data_size=sizeof(structshape_data),
};

例如上述代碼所示,首先會(huì)創(chuàng)建一個(gè)xxx_ops結(jié)構(gòu),該結(jié)構(gòu)與具體的設(shè)備驅(qū)動(dòng)相關(guān)。然后使用U_BOOT_DRIVER宏將其聲明為u-boot驅(qū)動(dòng)。

在U_BOOT_DRIVER中,還可以指定用于綁定和解綁定的方法,這些方法會(huì)在適當(dāng)?shù)臅r(shí)候被調(diào)用。對(duì)于大多數(shù)驅(qū)動(dòng)程序來說,一般只會(huì)使用到“probe”和“remove”方法。

設(shè)備驅(qū)動(dòng)可以提供的方法記錄在device.h頭文件中:

structdriver{
char*name;//設(shè)備名稱。
enumuclass_idid;//指示該驅(qū)動(dòng)屬于哪個(gè)uclass。
conststructudevice_id*of_match;//要匹配的兼容字符串列表,以及每個(gè)字符串的標(biāo)識(shí)數(shù)據(jù)。
int(*bind)(structudevice*dev);//調(diào)用該函數(shù)將設(shè)備綁定到其驅(qū)動(dòng)程序。
int(*probe)(structudevice*dev);//用于探測(cè)設(shè)備,即激活設(shè)備。
int(*remove)(structudevice*dev);//調(diào)用該函數(shù)來移除一個(gè)設(shè)備。
int(*unbind)(structudevice*dev);//調(diào)用該函數(shù)來解除設(shè)備與驅(qū)動(dòng)程序的綁定。
int(*ofdata_to_platdata)(structudevice*dev);//在probe之前調(diào)用該函數(shù)以解碼設(shè)備樹數(shù)據(jù)。
int(*child_post_bind)(structudevice*dev);//在一個(gè)新子設(shè)備被綁后調(diào)用。
int(*child_pre_probe)(structudevice*dev);//在probe子設(shè)備之前調(diào)用。設(shè)備已經(jīng)分配了內(nèi)存,但還沒有被probe到。
int(*child_post_remove)(structudevice*dev);//在子設(shè)備被移除后調(diào)用。設(shè)備已經(jīng)分配了內(nèi)存,但是它的device remove()方法已經(jīng)被調(diào)用。
intpriv_auto_alloc_size;//如果非零,這是在設(shè)備的->priv指針中分配的私有數(shù)據(jù)的大小。如果為零,則驅(qū)動(dòng)負(fù)責(zé)分配所需的數(shù)據(jù)。

//如果非零,這是在設(shè)備的->platdata中分配的平臺(tái)數(shù)據(jù)的大小。這通常只對(duì)設(shè)備樹驅(qū)動(dòng)有用(那些有of_match的驅(qū)動(dòng)),因?yàn)槭褂闷脚_(tái)數(shù)據(jù)的驅(qū)動(dòng)會(huì)在U_BOOT_DEVICE()實(shí)例化中提供數(shù)據(jù)。
intplatdata_auto_alloc_size;

//每個(gè)設(shè)備都可以保存其父設(shè)備擁有的私有數(shù)據(jù)。如果這個(gè)值非零,這個(gè)將被自動(dòng)分配。
intper_child_auto_alloc_size;

//bus存儲(chǔ)關(guān)于它的子設(shè)備的信息。如果非零,該數(shù)值則是數(shù)據(jù)的大小,將分配在子進(jìn)程的parent_platdata指針指向的區(qū)域中。
intper_child_platdata_auto_alloc_size;

//驅(qū)動(dòng)特殊操作。這通常是一個(gè)由驅(qū)動(dòng)定義的函數(shù)指針列表,用于實(shí)現(xiàn)類(uclass)所需要的驅(qū)動(dòng)函數(shù)。
constvoid*ops;

//驅(qū)動(dòng)標(biāo)志。
uint32_tflags;
};

在u-boot中,讓一個(gè)設(shè)備工作的順序是:

a1fd7346-16bf-11ed-ba43-dac502259ad0.png

U_BOOT_DRIVER宏創(chuàng)建了一個(gè)可從C訪問的數(shù)據(jù)結(jié)構(gòu),因此驅(qū)動(dòng)模型可以找到可用的驅(qū)動(dòng)程序。下文將分析該宏的具體實(shí)現(xiàn)。

三、U_BOOT_DRIVER宏分析

U_BOOT_DRIVER宏定義在/include/dm/device.h文件中:

/*DeclareanewU-Bootdriver*/
#defineU_BOOT_DRIVER(__name)
ll_entry_declare(structdriver,__name,driver)

ll_entry_declare同樣是一個(gè)宏定義,用于聲明鏈接器生成的數(shù)組項(xiàng),定義在/include/linker_lists.h中:

#definell_entry_declare(_type,_name,_list)
_type_u_boot_list_2_##_list##_2_##_name__aligned(4)
__attribute__((unused,
section(".u_boot_list_2_"#_list"_2_"#_name)))

  • _type:條目的數(shù)據(jù)類型。

  • _name:條目的名稱。

  • _list:列表名稱。只包含在C變量中允許的字符。

ll_entry_declare宏聲明了一個(gè)變量,該變量被放置在鏈接器生成的數(shù)組中。使用此宏聲明的變量必須在編譯時(shí)初始化。

此處以/drivers/led目錄下的led_gpio.c驅(qū)動(dòng)為例,在該文件的末尾使用U_BOOT_DRIVER進(jìn)行了驅(qū)動(dòng)聲明:a217bb2a-16bf-11ed-ba43-dac502259ad0.png

那么將98行宏定義展開則是:

structdriver_u_boot_list_2_driver_2_led_gpio__aligned(4)
__attribute__((unused,
section(".u_boot_list_2_driver_2_led_gpio")))={
.name="gpio_led",
.id=UCLASS_LED,
.of_match=led_gpio_ids,
.ops=&gpio_led_ops,
.priv_auto_alloc_size=sizeof(structled_gpio_priv),
.bind=led_gpio_bind,
.probe=led_gpio_probe,
.remove=led_gpio_remove,
}

從上述代碼片段可知,宏定義展開后本質(zhì)則是定義一個(gè)struct driver的驅(qū)動(dòng)結(jié)構(gòu)變量,并初始化結(jié)構(gòu)變量中的元素。然后將其放到.u_boot_list_2_driver_2_led_gpio節(jié)段中。在u-boot源碼/drivers目錄下存在大量使用U_BOOT_DRIVER聲明的驅(qū)動(dòng),這些驅(qū)動(dòng)會(huì)形成一張表(本質(zhì)為數(shù)組)。

至此,分析完U_BOOT_DRIVER這個(gè)宏定義,則有一個(gè)疑問產(chǎn)生了?u-boot是如何使用這張表的呢?

我們繼續(xù)查看/include/linker_lists.h文件,該文件中以宏定義的方式提供了訪問這張表的首元素和尾元素和數(shù)組總數(shù)的接口:

(1)指向連接器生成數(shù)組的第一個(gè)條目:

#definell_entry_start(_type,_list)
({
staticcharstart[0]__aligned(4)__attribute__((unused,
section(".u_boot_list_2_"#_list"_1")));
(_type*)&start;
})

(2)指向在連接器生成的數(shù)組的最后一個(gè)條目的后面:

#definell_entry_end(_type,_list)
({
staticcharend[0]__aligned(4)__attribute__((unused,
section(".u_boot_list_2_"#_list"_3")));
(_type*)&end;
})

(3)返回鏈接器生成數(shù)組中條目的數(shù)量:

#definell_entry_count(_type,_list)
({
_type*start=ll_entry_start(_type,_list);
_type*end=ll_entry_end(_type,_list);
unsignedint_ll_result=end-start;
_ll_result;
})

綜上,終于撥開迷霧,實(shí)則這張表開始的表項(xiàng)則是:u_boot_list_2_drivers_1,表尾項(xiàng)則是:u_boot_list_2_drivers_3,大量的驅(qū)動(dòng)則在這兩者之間。三者關(guān)系如下圖所示:

a245b6e2-16bf-11ed-ba43-dac502259ad0.png

在u-boot源碼中,當(dāng)需要操作這張表的時(shí)候,則會(huì)使用到這三個(gè)宏定義來完成這張表的循環(huán)遍歷操作。

四、總結(jié)

本文描述了u-boot驅(qū)動(dòng)模型的大致組成,重點(diǎn)描述在驅(qū)動(dòng)程序中U_BOOT_DRIVER宏定義的使用以及背后的實(shí)現(xiàn)機(jī)制。

下回會(huì)接著分析u-boot驅(qū)動(dòng)模型是如何起來的,如何“雄霸一方”。

審核編輯:湯梓紅


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • u-boot
    +關(guān)注

    關(guān)注

    0

    文章

    120

    瀏覽量

    38162
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    569

    瀏覽量

    40063
  • 驅(qū)動(dòng)模型
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    7396
  • 宏定義
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    8981

原文標(biāo)題:扒一扒u-boot的驅(qū)動(dòng)模型(第一回)

文章出處:【微信號(hào):嵌入式小生,微信公眾號(hào):嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    U-boot的基本介紹

    從本文開始,將陸續(xù)推送“手把手教你移植U-boot”系列文章,目標(biāo)是由淺入深地講解U-boot的工作流程、原理、配置方法和移植方法,手把手教你完成U-boot的移植工作,默認(rèn)硬件開發(fā)平臺(tái)為ARM,操作系統(tǒng)為L(zhǎng)inux。
    發(fā)表于 07-14 16:52 ?2648次閱讀
    <b class='flag-5'>U-boot</b>的基本介紹

    U-boot的執(zhí)行流程

    本文主要講述了U-boot的執(zhí)行流程。
    發(fā)表于 07-14 16:58 ?622次閱讀
    <b class='flag-5'>U-boot</b>的執(zhí)行流程

    淺析U-Boot NAND FLASH驅(qū)動(dòng)

    。mtd_info結(jié)構(gòu)體中的*priv指向設(shè)備對(duì)應(yīng)的nand_chip結(jié)構(gòu)體。如圖3.1所示。圖3.1 U-Boot中NAND FLASH數(shù)據(jù)結(jié)構(gòu)控制NAND FLASH時(shí),通過
    發(fā)表于 07-08 03:56

    Porting U-Boot to the Control

    In this paper, the way of porting U-Boot to Control Computer Based MPC8349 will beintroduced
    發(fā)表于 01-25 15:45 ?13次下載

    u-boot的Makefile分析

    u-boot的Makefile分析 U-BOOT是一個(gè)LINUX下的工程,在編譯之前必須已經(jīng)安裝對(duì)應(yīng)體系結(jié)構(gòu)的交叉編譯環(huán)境,這里只針對(duì)ARM,編譯器系列軟件為arm-linux-*。 U-
    發(fā)表于 05-17 09:16 ?2040次閱讀

    U-Boot結(jié)構(gòu)功能介紹

      U-Boot,全稱 Universal Boot Loader,是遵循GPL條款的開放源碼項(xiàng)目。從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來。其源碼目錄、編譯形式與Linux內(nèi)核很相似,事實(shí)上,不少U-Boot
    發(fā)表于 07-30 09:17 ?1162次閱讀
    <b class='flag-5'>U-Boot</b><b class='flag-5'>結(jié)構(gòu)</b>功能介紹

    u-boot簡(jiǎn)介

    演化而來。其源碼目錄、編譯形式與Linux內(nèi)核很相似,事實(shí)上,不少U-Boot源碼就是根據(jù)相應(yīng)的Linux內(nèi)核源程序進(jìn)行簡(jiǎn)化而形成的,尤其是一些設(shè)備的驅(qū)動(dòng)程序,這從U-Boot源碼的注釋中能體現(xiàn)這一點(diǎn)
    發(fā)表于 10-14 11:17 ?3518次閱讀

    你了解u-boot與linux內(nèi)核間的參數(shù)傳遞過程?

    U-boot把要傳遞給kernel的東西保存在struct tag數(shù)據(jù)結(jié)構(gòu)中,啟動(dòng)kernel時(shí),把這個(gè)結(jié)構(gòu)體的物理地址傳給kernel;
    發(fā)表于 05-13 10:00 ?1655次閱讀
    你了解<b class='flag-5'>u-boot</b>與linux內(nèi)核間的參數(shù)傳遞過程?

    深度解析U-Boot網(wǎng)絡(luò)實(shí)現(xiàn)

    對(duì)于U-Boot而言,并沒有完整的實(shí)現(xiàn)上述模型,u-boot需要控制固件的尺寸,所以根據(jù)需要做了一些簡(jiǎn)化,其拓?fù)淇蚣苋缦聢D所示:
    發(fā)表于 02-07 11:53 ?2次下載
    深度解析<b class='flag-5'>U-Boot</b>網(wǎng)絡(luò)實(shí)現(xiàn)

    U-Boot架構(gòu)淺析

    導(dǎo)讀:嵌入式Linux系統(tǒng)搭建,bootloader是必不可少的一環(huán),而U-Boot已成嵌入式Linux事實(shí)標(biāo)準(zhǔn)。所以較為深入的分析U-Boot的設(shè)計(jì),對(duì)于更...
    發(fā)表于 02-07 11:56 ?7次下載
    <b class='flag-5'>U-Boot</b>架構(gòu)淺析

    Linux U-Boot開發(fā)指南

    介紹 U-Boot 的編譯打包、基本配置、常用命令的使用、基本調(diào)試方法等, 為 U-BOOT 的移植及應(yīng)用開發(fā)提供了基礎(chǔ)。
    的頭像 發(fā)表于 03-06 10:28 ?1221次閱讀
    Linux <b class='flag-5'>U-Boot</b>開發(fā)指南

    U-boot的QSPI驅(qū)動(dòng)移植方法及驗(yàn)證方法

    本文主要講述了U-boot的QSPI驅(qū)動(dòng)移植方法及驗(yàn)證方法。在產(chǎn)品調(diào)試階段,U-boot的driver子系統(tǒng)包含了豐富的外設(shè)驅(qū)動(dòng),方便外設(shè)功能驗(yàn)證與調(diào)試。
    的頭像 發(fā)表于 04-14 10:21 ?2726次閱讀
    <b class='flag-5'>U-boot</b>的QSPI<b class='flag-5'>驅(qū)動(dòng)</b>移植方法及驗(yàn)證方法

    U-boot的MMC DM框架驅(qū)動(dòng)的移植方法

    本文主要講述了U-boot的MMC DM框架驅(qū)動(dòng)的移植方法。DM是Driver Model的簡(jiǎn)稱,是U-boot的基本驅(qū)動(dòng)框架。常見的MMC設(shè)備包括SD卡、eMMC存儲(chǔ)器等。本文討論遵
    的頭像 發(fā)表于 04-14 10:22 ?2713次閱讀
    <b class='flag-5'>U-boot</b>的MMC DM框架<b class='flag-5'>驅(qū)動(dòng)</b>的移植方法

    U-boot的DPU驅(qū)動(dòng)移植方法

    本文以ARM Mali系列顯示處理器驅(qū)動(dòng)為例,講述了U-boot的DPU驅(qū)動(dòng)移植方法。
    的頭像 發(fā)表于 04-14 10:25 ?1257次閱讀
    <b class='flag-5'>U-boot</b>的DPU<b class='flag-5'>驅(qū)動(dòng)</b>移植方法

    U-boot驅(qū)動(dòng)SPLASH_SCREEN驅(qū)動(dòng)移植方法

    U-boot集成了SPLASH_SCREEN驅(qū)動(dòng)源碼,當(dāng)使能和配置SPLASH_SCREEN驅(qū)動(dòng)后,可以將啟動(dòng)畫面使用的圖片文件轉(zhuǎn)換為位圖數(shù)據(jù)數(shù)組
    的頭像 發(fā)表于 06-09 14:39 ?1156次閱讀
    <b class='flag-5'>U-boot</b><b class='flag-5'>驅(qū)動(dòng)</b>SPLASH_SCREEN<b class='flag-5'>驅(qū)動(dòng)</b>移植方法