RM新时代网站-首页

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

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

3天內不再提示

描述u-boot驅動模型的數據結構

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


一、描述u-boot驅動模型的數據結構

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

(1-1)uclass

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

該結構由struct uclass表示(/include/dm/uclass.h):

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

(1-2)driver

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

(1-3)udevice

與特定端口或外圍設備綁定的驅動程序實例

二、聲明驅動

通過分析u-boot的/drivers目錄下的文件可以得出u-boot驅動程序具有共同的特征,驅動程序聲明一般具有如下類似的結構(參見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結構,該結構與具體的設備驅動相關。然后使用U_BOOT_DRIVER宏將其聲明為u-boot驅動。

在U_BOOT_DRIVER中,還可以指定用于綁定和解綁定的方法,這些方法會在適當的時候被調用。對于大多數驅動程序來說,一般只會使用到“probe”和“remove”方法。

設備驅動可以提供的方法記錄在device.h頭文件中:

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

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

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

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

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

//驅動標志。
uint32_tflags;
};

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

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

U_BOOT_DRIVER宏創(chuàng)建了一個可從C訪問的數據結構,因此驅動模型可以找到可用的驅動程序。下文將分析該宏的具體實現。

三、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同樣是一個宏定義,用于聲明鏈接器生成的數組項,定義在/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:條目的數據類型。

  • _name:條目的名稱。

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

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

此處以/drivers/led目錄下的led_gpio.c驅動為例,在該文件的末尾使用U_BOOT_DRIVER進行了驅動聲明: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,
}

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

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

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

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

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

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

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

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

#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,大量的驅動則在這兩者之間。三者關系如下圖所示:

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

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

四、總結

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

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

審核編輯:湯梓紅


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

    關注

    0

    文章

    121

    瀏覽量

    38222
  • 數據結構
    +關注

    關注

    3

    文章

    573

    瀏覽量

    40123
  • 驅動模型
    +關注

    關注

    0

    文章

    5

    瀏覽量

    7397
  • 宏定義
    +關注

    關注

    0

    文章

    50

    瀏覽量

    9005

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

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

收藏 人收藏

    評論

    相關推薦

    U-boot的基本介紹

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

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

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

    淺析U-Boot NAND FLASH驅動

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

    U-Boot結構功能介紹

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

    u-boot簡介

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

    你了解u-boot與linux內核間的參數傳遞過程?

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

    深度解析U-Boot網絡實現

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

    U-Boot架構淺析

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

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

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

    U-boot的QSPI驅動移植方法及驗證方法

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

    U-boot的MMC DM框架驅動的移植方法

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

    U-boot的DPU驅動移植方法

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

    U-boot驅動SPLASH_SCREEN驅動移植方法

    U-boot集成了SPLASH_SCREEN驅動源碼,當使能和配置SPLASH_SCREEN驅動后,可以將啟動畫面使用的圖片文件轉換為位圖數據數組
    的頭像 發(fā)表于 06-09 14:39 ?1238次閱讀
    <b class='flag-5'>U-boot</b><b class='flag-5'>驅動</b>SPLASH_SCREEN<b class='flag-5'>驅動</b>移植方法
    RM新时代网站-首页