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

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

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

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

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


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

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

(1-1)uclass

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

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

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

(1-2)driver

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

(1-3)udevice

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

二、聲明驅(qū)動

通過分析u-boot的/drivers目錄下的文件可以得出u-boot驅(qū)動程序具有共同的特征,驅(qū)動程序聲明一般具有如下類似的結(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),
};

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

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

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

structdriver{
char*name;//設(shè)備名稱。
enumuclass_idid;//指示該驅(qū)動屬于哪個uclass。
conststructudevice_id*of_match;//要匹配的兼容字符串列表,以及每個字符串的標識數(shù)據(jù)。
int(*bind)(structudevice*dev);//調(diào)用該函數(shù)將設(shè)備綁定到其驅(qū)動程序。
int(*probe)(structudevice*dev);//用于探測設(shè)備,即激活設(shè)備。
int(*remove)(structudevice*dev);//調(diào)用該函數(shù)來移除一個設(shè)備。
int(*unbind)(structudevice*dev);//調(diào)用該函數(shù)來解除設(shè)備與驅(qū)動程序的綁定。
int(*ofdata_to_platdata)(structudevice*dev);//在probe之前調(diào)用該函數(shù)以解碼設(shè)備樹數(shù)據(jù)。
int(*child_post_bind)(structudevice*dev);//在一個新子設(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ū)動負責(zé)分配所需的數(shù)據(jù)。

//如果非零,這是在設(shè)備的->platdata中分配的平臺數(shù)據(jù)的大小。這通常只對設(shè)備樹驅(qū)動有用(那些有of_match的驅(qū)動),因為使用平臺數(shù)據(jù)的驅(qū)動會在U_BOOT_DEVICE()實例化中提供數(shù)據(jù)。
intplatdata_auto_alloc_size;

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

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

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

//驅(qū)動標志。
uint32_tflags;
};

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

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

U_BOOT_DRIVER宏創(chuàng)建了一個可從C訪問的數(shù)據(jù)結(jié)構(gòu),因此驅(qū)動模型可以找到可用的驅(qū)動程序。下文將分析該宏的具體實現(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同樣是一個宏定義,用于聲明鏈接器生成的數(shù)組項,定義在/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宏聲明了一個變量,該變量被放置在鏈接器生成的數(shù)組中。使用此宏聲明的變量必須在編譯時初始化。

此處以/drivers/led目錄下的led_gpio.c驅(qū)動為例,在該文件的末尾使用U_BOOT_DRIVER進行了驅(qū)動聲明: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ì)則是定義一個struct driver的驅(qū)動結(jié)構(gòu)變量,并初始化結(jié)構(gòu)變量中的元素。然后將其放到.u_boot_list_2_driver_2_led_gpio節(jié)段中。在u-boot源碼/drivers目錄下存在大量使用U_BOOT_DRIVER聲明的驅(qū)動,這些驅(qū)動會形成一張表(本質(zhì)為數(shù)組)。

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

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

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

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

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

#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;
})

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

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

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

四、總結(jié)

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

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

審核編輯:湯梓紅


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

    關(guān)注

    0

    文章

    120

    瀏覽量

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

    關(guān)注

    3

    文章

    569

    瀏覽量

    40072
  • 驅(qū)動模型
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

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

    關(guān)注

    0

    文章

    50

    瀏覽量

    8996

原文標題:扒一扒u-boot的驅(qū)動模型(第一回)

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

收藏 人收藏

    評論

    相關(guān)推薦

    U-boot的基本介紹

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

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

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

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

    。mtd_info結(jié)構(gòu)體中的*priv指向設(shè)備對應(yīng)的nand_chip結(jié)構(gòu)體。如圖3.1所示。圖3.1 U-Boot中NAND FLASH數(shù)據(jù)結(jié)構(gòu)控制NAND FLASH時,通過
    發(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是一個LINUX下的工程,在編譯之前必須已經(jīng)安裝對應(yīng)體系結(jié)構(gòu)的交叉編譯環(huán)境,這里只針對ARM,編譯器系列軟件為arm-linux-*。 U-
    發(fā)表于 05-17 09:16 ?2053次閱讀

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

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

    u-boot簡介

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

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

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

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

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

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

    導(dǎo)讀:嵌入式Linux系統(tǒng)搭建,bootloader是必不可少的一環(huán),而U-Boot已成嵌入式Linux事實標準。所以較為深入的分析U-Boot的設(shè)計,對于更...
    發(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 ?1247次閱讀
    Linux <b class='flag-5'>U-Boot</b>開發(fā)指南

    U-boot的QSPI驅(qū)動移植方法及驗證方法

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

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

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

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

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

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

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