pos機安裝驅動

 新聞資訊3  |   2023-08-28 16:01  |  投稿人:pos機之家

網上有很多關于pos機安裝驅動,Uboot驅動開發的知識,也有很多人為大家解答關于pos機安裝驅動的問題,今天pos機之家(www.www690aa.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!

本文目錄一覽:

1、pos機安裝驅動

pos機安裝驅動

#頭條創作挑戰賽#

全文耗時一周,精心匯總20000余字,希望對大家有所幫助,感覺可以的點贊,關注,不迷路,后續還有更多干貨!

看文章前,答應我,靜下心來,慢慢品!

文章目錄3.1、什么是Uboot驅動模型3.2、為什么要有驅動模型呢3.3、如何使用uboot的DM模型①:menuCONFIG配置全局DM模型②:指定某個驅動的DM模型3.4、DM模型數據結構① global_data② uclass③ uclass_driver④ uclass_id⑤ udevice⑥ driver3.5、DM驅動模型之上帝視角3.6、DM模型——Udevice與driver綁定① dm_init② lists_bind_fdt3.7、DM模型——probe探測函數的執行3.8、DM模型——uclass與uclass_driver綁定3.9參考文檔3.1、什么是Uboot驅動模型

學過Linux的朋友基本都知道Linux的設備驅動模型,Uboot根據Linux的驅動模型架構,也引入了Uboot的驅動模型(driver model :DM)。

這種驅動模型為驅動的定義和訪問接口提供了統一的方法。提高了驅動之間的兼容性以及訪問的標準型,uboot驅動模型和kernel中的設備驅動模型類似。

3.2、為什么要有驅動模型呢

無論是Linux還是Uboot,一個新對象的產生必定有其要解決的問題,驅動模型也不例外!

提高代碼的可重用性:為了能夠使代碼在不同硬件平臺,不同體系架構下運行,必須要最大限度的提高代碼的可重用性。高內聚,低耦合:分層的思想也是為了達到這一目標,低耦合體現在對外提供統一的抽象訪問接口,高內聚將相關度緊密的集中抽象實現。便于管理:在不斷發展過程中,硬件設備越來越多,驅動程序也越來越多,為了更好的管理驅動,也需要一套優秀的驅動架構!3.3、如何使用uboot的DM模型

DM模型的使用,可以通過menuconfig來配置。

make menuconfig

①:menuconfig配置全局DM模型

Device Drivers -> Generic Driver Options -> Enable Driver Model

通過上面的路徑來打開Driver Model模型,最終配置在.config文件中,CONFIG_DM=y

②:指定某個驅動的DM模型

全局的DM模型打開后,我們對于不通的驅動模塊,使能或者失能DM功能。如MMC驅動為例:

Device Drivers -> MMC Host controller Support -> Enable MMC controllers using Driver Model

最終反映在.config文件中的CONFIG_DM_MMC=y

在對應的驅動中,可以看到判斷#if !CONFIG_IS_ENABLED(DM_MMC),來判斷是否打開DM驅動模型。

在管理驅動的Makefile文件中,也能看到obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o,來判斷是否將驅動模型加入到編譯選項中。

總之,我們要打開DM模型,最后反映在幾個配置信息上:

CONFIG_DM=y,全局DM模型打開CONFIG_DM_XXX=y,某個驅動的DM模型的打開可以通過Kconifg、Makefile來查看對應宏的編譯情況3.4、DM模型數據結構

要想了解DM模型整套驅動框架,我們必須先了解它的一磚一瓦!也就是組成驅動框架的各個數據結構。

① global_data

typedef struct global_data {...#ifdef CONFIG_DMstruct udevice*dm_root;/* Root instance for Driver Model */struct udevice*dm_root_f;/* Pre-relocation root instance */struct list_head uclass_root;/* Head of core tree */#endif...}

global_data,管理著整個Uboot的全局變量,其中dm_root,dm_root_f,uclass_root用來管理整個DM模型。這幾個變量代表什么意思呢?

dm_root:DM模型的根設備dm_root_f:重定向前的根設備uclass_root:uclass鏈表的頭

這幾個變量,最終要的作用就是:管理整個模型中的udevice設備信息和uclass驅動類。

② uclass

我們首先看一下uclass這個結構體

/** * struct uclass - a U-Boot drive class, collecting together similar drivers * * A uclass provides an interface to a particular function, which is * implemented by one or more drivers. Every driver belongs to a uclass even * if it is the only driver in that uclass. An example uclass is GPIO, which * provides the ability to change read inputs, set and clear outputs, etc. * There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and * PMIC IO lines, all made available in a unified way through the uclass. * * @priv: Private data for this uclass * @uc_drv: The driver for the uclass itself, not to be confused with a * 'struct driver' * @dev_head: List of devices in this uclass (devices are attached to their * uclass when their bind method is called) * @sibling_node: Next uclass in the linked list of uclasses */struct uclass {void *priv;//uclass的私有數據struct uclass_driver *uc_drv;//uclass類的操作函數集合struct list_head dev_head;//該uclass的所有設備struct list_head sibling_node;//下一個uclass的節點};

根據注釋,我們就可以了解到,uclass相當于老師,管理著對應某一個類別下的所有的udevice。

例如:一個IIC驅動程序,其驅動程序框架是一致的,只有一種,但是IIC驅動的設備可以有很多,如EEPROM,MCU6050等;

所有在這里呢,dev_head鏈表就是用來管理該驅動類下的所有的設備。

總結:uclass,來管理該類型下的所有設備,并且有對應的uclass_driver驅動。

定義

uclass是uboot自動生成的,并且不是所有uclass都會生成,有對應uclass_driver并且有被udevice匹配到的uclass才會生成。

存放

所有生成的uclass都會被掛載gd->uclass_root鏈表上。

相關API

直接遍歷鏈表gd->uclass_root鏈表并且根據uclass_id來獲取到相應的uclass。

int uclass_get(enum uclass_id key, struct uclass **ucp);// 從gd->uclass_root鏈表獲取對應的ucla ss③ uclass_driver

正如上面,我們看到了uclass類所包含uclass_driver結構體,uclass_driver正如其名,它就是uclass的驅動程序。其主要作用是:為uclass提供統一管理的接口,結構體如下:

/** * struct uclass_driver - Driver for the uclass * * A uclass_driver provides a consistent interface to a set of related * drivers. */struct uclass_driver { const char *name; // 該uclass_driver的命令 enum uclass_id id; // 對應的uclass id/* 以下函數指針主要是調用時機的區別 */ int (*post_bind)(struct udevice *dev); // 在udevice被綁定到該uclass之后調用 int (*pre_unbind)(struct udevice *dev); // 在udevice被解綁出該uclass之前調用 int (*pre_probe)(struct udevice *dev); // 在該uclass的一個udevice進行probe之前調用 int (*post_probe)(struct udevice *dev); // 在該uclass的一個udevice進行probe之后調用 int (*pre_remove)(struct udevice *dev);// 在該uclass的一個udevice進行remove之前調用 int (*child_post_bind)(struct udevice *dev); // 在該uclass的一個udevice的一個子設備被綁定到該udevice之后調用 int (*child_pre_probe)(struct udevice *dev); // 在該uclass的一個udevice的一個子設備進行probe之前調用 int (*init)(struct uclass *class); // 安裝該uclass的時候調用 int (*destroy)(struct uclass *class); // 銷毀該uclass的時候調用 int priv_auto_alloc_size; // 需要為對應的uclass分配多少私有數據 int per_device_auto_alloc_size; // int per_device_platdata_auto_alloc_size; // int per_child_auto_alloc_size; // int per_child_platdata_auto_alloc_size; // const void *ops; //操作集合 uint32_t flags; // 標識為};定義

uclass_driver主要通過UCLASS_DRIVER來定義,這里就簡單說明一下底層代碼,耐心看哦!

下面以pinctrl為例

UCLASS_DRIVER(pinctrl) = {.id = UCLASS_PINCTRL,.post_bind = pinctrl_post_bind,.flags = DM_UC_FLAG_SEQ_ALIAS,.name = "pinctrl",};

/* Declare a new uclass_driver */#define UCLASS_DRIVER(__name)\\ll_entry_declare(struct uclass_driver, __name, uclass)#define ll_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)))

上面基本上就是我們的底層代碼了,稍微有點繞,但是也不難!我們只需要將宏進行替換就行了!

通過上面的定義,我們替換掉宏之后,最終得到的定義如下:

struct uclass_driver _u_boot_list_2_uclass_2_pinctrl = {.id = UCLASS_PINCTRL,.post_bind = pinctrl_post_bind,.flags = DM_UC_FLAG_SEQ_ALIAS,.name = "pinctrl",}//同時存放在段._u_boot_list_2_uclass_2_pinctrl中,也就是section段的內容存放

由上面結構體可得,其定義之后都被存放在了段._u_boot_list_2_uclass_2_pinctrl中,那么去哪里可以看到呢?

在u-boot.map文件中搜索,._u_boot_list_2_uclass_2_pinctrl,就可以查到程序中定義的所有驅動程序。

這里相信大家會有疑問,為什么是uclass_2呢?我們大概看一下,也會看到uclass_1和uclass_3,這兩個代表什么呢?往下看!

相關API

想要獲取uclass_driver需要先獲取uclass_driver table。

struct uclass_driver *uclass = ll_entry_start(struct uclass_driver, uclass); // 會根據.u_boot_list_2_uclass_1的段地址來得到uclass_driver table的地址 const int n_ents = ll_entry_count(struct uclass_driver, uclass);// 獲得uclass_driver table的長度struct uclass_driver *lists_uclass_lookup(enum uclass_id id)// 從uclass_driver table中獲取uclass id為id的uclass_driver。

正如注釋描述,上文中提到的uclass_1和uclass_3起到定位作用,用于計算uclass_2的長度!

上述的API,主要用于根據uclass_id來查找到對應的uclass_driver,進而操作對應的uclass下的udevice。

④ uclass_id

我們在uclass_driver中,看到一個uclass_id類型,這種類型與uclass有什么關系呢?

我們知道,uclass代表驅動的一個類別,uclass_driver是uclass的驅動程序,為uclass提供統一操作接口。而對于不同類型的驅動,就需要uclass_id來區分了!

事實上,每一種類型的設備``uclass都有唯一對應的uclass_id,貫穿設備模型,也是udevice與uclass`相關聯的關鍵之處。

enum uclass_id {/* These are used internally by driver model */UCLASS_ROOT = 0,UCLASS_DEMO,UCLASS_TEST,UCLASS_TEST_FDT,UCLASS_TEST_BUS,UCLASS_TEST_PROBE,....../* U-Boot uclasses start here - in alphabetical order */UCLASS_ACPI_PMC,/* (x86) Power-management controller (PMC) */UCLASS_ADC,/* Analog-to-digital converter */UCLASS_AHCI,/* SATA disk controller */UCLASS_AUDIO_CODEC,/* Audio codec with control and data path */UCLASS_AXI,/* AXI bus */UCLASS_BLK,/* Block device */UCLASS_BOARD,/* Device information from hardware */......};

在這里,我們就把他當作一個設備識別的標志即可!

最后,壓軸的兩個結構體出來了,也是DM模型最終操作的對象。

⑤ udevice

/** * struct udevice - An instance of a driver * * This holds information about a device, which is a driver bound to a * particular port or peripheral (essentially a driver instance). * */struct udevice {const struct driver *driver;//device 對應的driverconst char *name;//device 的名稱void *platdata;void *parent_platdata;void *uclass_platdata;ofnode node;//設備樹節點ulong driver_data;struct udevice *parent;//父設備void *priv;// 私有數據的指針struct uclass *uclass;//驅動所屬的uclassvoid *uclass_priv;void *parent_priv;struct list_head uclass_node;struct list_head child_head;struct list_head sibling_node;uint32_t flags;int req_seq;int seq;#ifdef CONFIG_DEVRESstruct list_head devres_head;#endif};定義**硬編碼:**代碼中調用U_BOOT_DEVICE宏來定義設備資源,實際為一個設備實例。**設備樹:**將設備描述信息寫在對應的DTS文件中,然后編譯成DTB,最終由uboot解析設備樹后動態生成的。傳參方式:通過命令行或者接口將設備資源信息傳遞進來,非常靈活。存放udevice是最基礎的一個設備單元,我們把它作為一個獨立的個體,上層所有的操作,最終都與該結構體有關。

我們創建一個設備后,為了服從統一的管理,該結構體會被連接到DM模型下,并入到機制中。那么udevice會被連接到哪里呢?

將udevice連接到對應的uclass中,uclass主要用來管理著同一類的驅動除此之外,有父子關系的udevice,還會連接到udevice->child_head鏈表下,方便調用

大概可以理解為下面這樣:

相關API

#define uclass_foreach_dev(pos, uc) \\ list_for_each_entry(pos, &uc->dev_head, uclass_node)#define uclass_foreach_dev_safe(pos, next, uc) \\ list_for_each_entry_safe(pos, next, &uc->dev_head, uclass_node)int uclass_get_device(enum uclass_id id, int index, struct udevice **devp); // 通過索引從uclass中獲取udeviceint uclass_get_device_by_name(enum uclass_id id, const char *name, // 通過設備名從uclass中獲取udevice struct udevice **devp);int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp);int uclass_get_device_by_of_offset(enum uclass_id id, int node, struct udevice **devp);int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, const char *name, struct udevice **devp);int uclass_first_device(enum uclass_id id, struct udevice **devp);int uclass_first_device_err(enum uclass_id id, struct udevice **devp);int uclass_next_device(struct udevice **devp);int uclass_resolve_seq(struct udevice *dev);

這些相關的API,主要作用就是根據uclass_id,查找對應的uclass,然后根據索引值或者名稱,來查找到對應的udevice

⑥ driver

struct driver {char *name;//驅動名稱enum uclass_id id;//驅動所對應的uclass_idconst struct udevice_id *of_match;//匹配函數int (*bind)(struct udevice *dev);//綁定函數int (*probe)(struct udevice *dev);//注冊函數int (*remove)(struct udevice *dev);int (*unbind)(struct udevice *dev);int (*ofdata_to_platdata)(struct udevice *dev);int (*child_post_bind)(struct udevice *dev);int (*child_pre_probe)(struct udevice *dev);int (*child_post_remove)(struct udevice *dev);int priv_auto_alloc_size;int platdata_auto_alloc_size;int per_child_auto_alloc_size;int per_child_platdata_auto_alloc_size;const void *ops;/* driver-specific operations */uint32_t flags;#if CONFIG_IS_ENABLED(ACPIGEN)struct acpi_ops *acpi_ops;#endif};定義

driver對象,主要通過U_BOOT_DRIVER來定義

以pinctrl來舉例

U_BOOT_DRIVER(xxx_pinctrl) = {.name= "xxx_pinctrl",.id= UCLASS_PINCTRL,.of_match= xxx_pinctrl_match,.priv_auto_alloc_size = sizeof(struct xxx_pinctrl),.ops= &xxx_pinctrl_ops,.probe= xxx_v2s_pinctrl_probe,.remove = xxx_v2s_pinctrl_remove,};

/* Declare a new U-Boot driver */#define U_BOOT_DRIVER(__name)\\ll_entry_declare(struct driver, __name, driver)#define ll_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)))

通過上面的定義,最終我們定義的結構體如下:

struct driver _u_boot_list_2_driver_2_xxx_pinctrl = {.name= "xxx_pinctrl",.id= UCLASS_PINCTRL,.of_match= xxxx_pinctrl_match,.priv_auto_alloc_size = sizeof(struct xxx_pinctrl),.ops= &xxxx_pinctrl_ops,.probe= xxxx_pinctrl_probe,.remove = xxxx_pinctrl_remove,}//同時存放在段._u_boot_list_2_driver_2_xxx_pinctrl中存放

由上面結構體可得,其定義之后都被存放在了段._u_boot_list_2_driver_2_xxx中,那么去哪里可以看到呢?

在u-boot.map文件中搜索,._u_boot_list_2_driver,就可以查到程序中定義的所有驅動程序。

最終,所有driver結構體以列表的形式被放在.u_boot_list_2_driver_1和.u_boot_list_2_driver_3的區間中。

相關API

/*先獲取driver table 表*/struct driver *drv = ll_entry_start(struct driver, driver);// 會根據.u_boot_list_2_driver_1的段地址來得到uclass_driver table的地址 const int n_ents = ll_entry_count(struct driver, driver);// 通過.u_boot_list_2_driver_3的段地址 減去 .u_boot_list_2_driver_1的段地址 獲得driver table的長度/*遍歷所有的driver*/struct driver *lists_driver_lookup_name(const char *name)// 從driver table中獲取名字為name的driver。

正如注釋描述,上文中提到的driver_1和driver_3起到定位作用,用于計算driver_2的長度!

上述的API,主要用于根據name來查找到對應的driver驅動程序。

綜上,DM模型相關的數據結構介紹完畢,整體設計的架構如下:

正如紅線部分,如何實現driver和udevice的綁定、uclass、uclass_driver的綁定呢?

要想真正搞懂這些,我們不得不去深入到DM的初始化流程。

3.5、DM驅動模型之上帝視角

對于DM模型,我們站在上帝視角來觀察整套模型框架是如何的!

對象設計的角度來看,Uboot的驅動模型可以分為靜態形式和動態形式

靜態模式:對象是離散的,和其他對象分隔開,減小對象復雜度,利于模塊化設計。動態模式:運行態表達形式的對象是把所有的靜態對象組合成層次視圖,有清晰的數據關聯視圖

在靜態模式下,驅動模型主要將對象分為udevice和driver,即設備和驅動程序,兩個就像火車的兩條軌道,永遠也不會產生交集,驅動和設備可以想注冊多少就注冊多少。

我們看一下udevice的描述:

/** * struct udevice - An instance of a driver * * This holds information about a device, which is a driver bound to a * particular port or peripheral (essentially a driver instance). * */

udevice是driver的一個實例,兩個不相交的鐵軌,終歸也是想要發生愛情的。那么如何讓其產生交集呢?這就是動態模式需要做的工作了!

**在動態模式下,**引入了uclass和uclass_driver兩個數據結構,實現了對udevice和driver的管理。

看一下uclass和uclass_driver兩個結構體的說明:

/** * struct uclass - a U-Boot drive class, collecting together similar drivers * *//** * struct uclass_driver - Driver for the uclass * * A uclass_driver provides a consistent interface to a set of related * drivers. * */uclass:設備組公共屬性對象,作為udevice的一個屬性,主要用來管理某個驅動類的所有的設備。uclass_driver:設備組公共行為對象,uclass的驅動程序,主要將uclass管理的設備和驅動實現綁定、注冊,移除等操作。

通過這兩個結構體的引入,可以將毫不相關的udevice是driver關聯起來!

udevice與driver的綁定:通過驅動的of_match和compatible屬性來配對,綁定。

udevice與uclass的綁定:udevice內的driver下的uclass_id,來與uclass對應的uclass_driver的uclass_id進行匹配。

uclass與uclass_driver的綁定:已知udevice內的driver下的uclass_id,創建uclass的同時,通過``uclass_id找到對應的uclass_driver對象,然后將uclass_driver綁定到uclass`上!

整體結構如下:

3.6、DM模型——Udevice與driver綁定

相信站在上帝視角看完DM的整體架構,大家都對DM框架有一定了解,下面我們來看看具體的實現細節!

DM的初始化分為兩個部分,一個是在relocate重定向之前的初始化:initf_dm,一個是在relocate重定向之后的初始化:initr_dm。

我們對比這兩個函數:

static int initf_dm(void){#if defined(CONFIG_DM) && CONFIG_VAL(SYS_MALLOC_F_LEN)int ret;bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f");ret = dm_init_and_scan(true);//這里為truebootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F);if (ret)return ret;#endif#ifdef CONFIG_TIMER_EARLYret = dm_timer_init();if (ret)return ret;#endifreturn 0;}static int initr_dm(void){int ret;/* Save the pre-reloc driver model and start a new one */gd->dm_root_f = gd->dm_root;gd->dm_root = NULL;#ifdef CONFIG_TIMERgd->timer = NULL;#endifbootstage_start(BOOTSTAGE_ID_ACCUM_DM_R, "dm_r");ret = dm_init_and_scan(false);//這里為falsebootstage_accum(BOOTSTAGE_ID_ACCUM_DM_R);if (ret)return ret;return 0;}

兩個均調用了dm_init_and_scan這個接口,這兩個的關鍵區別在于參數的不同。

首先說明一下dts節點中的“u-boot,dm-pre-reloc”屬性,當設置了這個屬性時,則表示這個設備在relocate之前就需要使用。當dm_init_and_scan的參數為true時,只會對帶有“u-boot,dm-pre-reloc”屬性的節點進行解析。而當參數為false的時候,則會對所有節點都進行解析。

DM初始化的大體步驟如下:

如上程序執行流程圖,下面我們詳細講解幾個函數。

① dm_init

int dm_init(bool of_live){int ret;if (gd->dm_root) {dm_warn("Virtual root driver already exists!\");return -EINVAL;}INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);#if defined(CONFIG_NEEDS_MANUAL_RELOC)fix_drivers();fix_uclass();fix_devices();#endifret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);//查找root_driver驅動,并綁定if (ret)return ret;#if CONFIG_IS_ENABLED(OF_CONTROL)# if CONFIG_IS_ENABLED(OF_LIVE)if (of_live)DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root);else#endifDM_ROOT_NON_CONST->node = offset_to_ofnode(0);#endifret = device_probe(DM_ROOT_NON_CONST);//probe激活root_driver驅動if (ret)return ret;return 0;}

dm_init這個函數,名字起的容易讓人誤導,這個函數主要做的就是初始化了根設備root_driver,根據這個跟設備,初始化了global_data中的dm_root、uclass_root。

② lists_bind_fdt

我們通常會使用設備樹來定義各種設備,所以這個函數才是主角。

這個函數主要用來查找子設備,并且根據查找到的子設備,進而查找對應驅動進行綁定!即:實現了driver和device的綁定。

int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, bool pre_reloc_only){struct driver *driver = ll_entry_start(struct driver, driver);//獲得驅動列表的起始地址const int n_ents = ll_entry_count(struct driver, driver);//獲得驅動列表的總數量const struct udevice_id *id;struct driver *entry;struct udevice *dev;bool found = false;const char *name, *compat_list, *compat;int compat_length, i;int result = 0;int ret = 0;if (devp)*devp = NULL;name = ofnode_get_name(node);log_debug("bind node %s\", name);compat_list = ofnode_get_property(node, "compatible", &compat_length);//得到compatible屬性,用于匹配driver驅動if (!compat_list) {if (compat_length == -FDT_ERR_NOTFOUND) {log_debug("Device '%s' has no compatible string\", name);return 0;}dm_warn("Device tree error at node '%s'\", name);return compat_length;}/* * Walk through the compatible string list, attempting to match each * compatible string in order such that we match in order of priority * from the first string to the last. */for (i = 0; i < compat_length; i += strlen(compat) + 1) {compat = compat_list + i;log_debug(" - attempt to match compatible string '%s'\", compat);for (entry = driver; entry != driver + n_ents; entry++) {//循環判斷所有驅動是否匹配ret = driver_check_compatible(entry->of_match, &id, compat);if (!ret)break;}if (entry == driver + n_ents)continue;if (pre_reloc_only) {if (!ofnode_pre_reloc(node) && !(entry->flags & DM_FLAG_PRE_RELOC)) {log_debug("Skipping device pre-relocation\");return 0;}}log_debug(" - found match at '%s': '%s' matches '%s'\", entry->name, entry->of_match->compatible, id->compatible);ret = device_bind_with_driver_data(parent, entry, name, id->data, node, &dev);//該函數,用于創建udevice對象,并與查找到的driver綁定if (ret == -ENODEV) {log_debug("Driver '%s' refuses to bind\", entry->name);continue;}if (ret) {dm_warn("Error binding driver '%s': %d\", entry->name,ret);return ret;} else {found = true;if (devp)*devp = dev;}break;}if (!found && !result && ret != -ENODEV)log_debug("No match for node '%s'\", name);return result;}

lists_bind_fdt這個函數,主要用來掃描設備樹中的各個節點;

根據掃描到的udevice設備信息,通過compatible來匹配compatible相同的driver,匹配成功后,就會創建對應的struct udevice結構體,它會同時指向設備資源和driver,這樣設備資源和driver就綁定在一起了。

3.7、DM模型——probe探測函數的執行

上述,完成了DM模型的初始化,但是我們只是建立了driver和udevice的綁定關系,那么何時調用到我們驅動中的probe探測函數呢?uclass與driver又何時匹配的呢?

上文呢,dm_init只是負責初始化并綁定了udevice和driver,那么probe探測函數的執行,當然是在該驅動初始化的時候嘍!

下文以mmc驅動為例!其初始化流程如下:

詳細代碼在這里就不展開來敘述了!

在MMC驅動初始化后,有沒有注意到mmc_probe這個函數,該函數就是間接調用了我們驅動編寫的probe函數。

執行流程在上面已經很清楚了:根據uclass_id,調用``uclass_get_device_by_seq來得到udevice,進而調用device_probe來找到對應驅動的probe`。

int device_probe(struct udevice *dev){const struct driver *drv;int ret;int seq;if (!dev)return -EINVAL;if (dev->flags & DM_FLAG_ACTIVATED)return 0;drv = dev->driver;//獲取driverassert(drv);ret = device_ofdata_to_platdata(dev);if (ret)goto fail;/* Ensure all parents are probed */if (dev->parent) {//父設備proberet = device_probe(dev->parent);if (ret)goto fail;/* * The device might have already been probed during * the call to device_probe() on its parent device * (e.g. PCI bridge devices). Test the flags again * so that we don't mess up the device. */if (dev->flags & DM_FLAG_ACTIVATED)return 0;}seq = uclass_resolve_seq(dev);if (seq < 0) {ret = seq;goto fail;}dev->seq = seq;dev->flags |= DM_FLAG_ACTIVATED;/* * Process pinctrl for everything except the root device, and * continue regardless of the result of pinctrl. Don't process pinctrl * settings for pinctrl devices since the device may not yet be * probed. */if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)pinctrl_select_state(dev, "default");if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent && (device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) && !(drv->flags & DM_FLAG_DEFAULT_PD_CTRL_OFF)) {ret = dev_power_domain_on(dev);if (ret)goto fail;}ret = uclass_pre_probe_device(dev);if (ret)goto fail;if (dev->parent && dev->parent->driver->child_pre_probe) {ret = dev->parent->driver->child_pre_probe(dev);if (ret)goto fail;}/* Only handle devices that have a valid ofnode */if (dev_of_valid(dev)) {/* * Process 'assigned-{clocks/clock-parents/clock-rates}' * properties */ret = clk_set_defaults(dev, 0);if (ret)goto fail;}if (drv->probe) {ret = drv->probe(dev);//調用驅動的probeif (ret)goto fail;}ret = uclass_post_probe_device(dev);if (ret)goto fail_uclass;if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)pinctrl_select_state(dev, "default");return 0;fail_uclass:if (device_remove(dev, DM_REMOVE_NORMAL)) {dm_warn("%s: Device '%s' failed to remove on error path\",__func__, dev->name);}fail:dev->flags &= ~DM_FLAG_ACTIVATED;dev->seq = -1;device_free(dev);return ret;}

主要工作歸納如下:

根據udevice獲取driver然后判斷是否父設備被probe對父設備進行probe調用driver的probe函數3.8、DM模型——uclass與uclass_driver綁定

上述完成了driver的probe函數調用,基本底層都已經準備好了,uclass何時與uclass_driver綁定,給上層提供統一的API呢?

uclass與uclass_driver綁定,也是在驅動probe之后,確保該驅動存在,設備存在,最后為該驅動綁定uclass與uclass_driver,為上層提供統一接口。

以根據MMC驅動為例

回到上文的驅動流程圖,看到mmc_do_preinit這個函數了嘛?里面調用了ret = uclass_get(UCLASS_MMC, &uc);,該函數才是真正的將uclass與uclass_driver綁定。

int uclass_get(enum uclass_id id, struct uclass **ucp){struct uclass *uc;*ucp = NULL;uc = uclass_find(id);if (!uc)return uclass_add(id, ucp);*ucp = uc;return 0;}

uclass_get主要實現了:根據uclass_id查找對應的uclass是否被添加到global_data->uclass_root鏈表中,如果沒有添加到,就調用uclass_add函數,實現uclass與uclass_driver的綁定,并將其添加到global_data->uclass_root鏈表中。

static int uclass_add(enum uclass_id id, struct uclass **ucp){struct uclass_driver *uc_drv;struct uclass *uc;int ret;*ucp = NULL;uc_drv = lists_uclass_lookup(id);//根據uclass_id查找到對應的driverif (!uc_drv) {debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\", id);/* * Use a strange error to make this case easier to find. When * a uclass is not available it can prevent driver model from * starting up and this failure is otherwise hard to debug. */return -EPFNOSUPPORT;}uc = calloc(1, sizeof(*uc));if (!uc)return -ENOMEM;if (uc_drv->priv_auto_alloc_size) {uc->priv = calloc(1, uc_drv->priv_auto_alloc_size);if (!uc->priv) {ret = -ENOMEM;goto fail_mem;}}uc->uc_drv = uc_drv;//uclass與uclass_driver綁定INIT_LIST_HEAD(&uc->sibling_node);INIT_LIST_HEAD(&uc->dev_head);list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST);//添加到global_data->uclass_root鏈表中if (uc_drv->init) {ret = uc_drv->init(uc);if (ret)goto fail;}*ucp = uc;return 0;fail:if (uc_drv->priv_auto_alloc_size) {free(uc->priv);uc->priv = NULL;}list_del(&uc->sibling_node);fail_mem:free(uc);return ret;}

好啦,到這里基本就把Uboot的DM模型全部理清楚啦,耗時一個周,總感覺想要自己去講明白,真的不是一件容易的事情呢!

如果對你們有幫助,記得點個贊哦!

更多文章,可以關注我的公~號:【嵌入式藝術】哦,一起討論嵌入式技術!

以上就是關于pos機安裝驅動,Uboot驅動開發的知識,后面我們會繼續為大家整理關于pos機安裝驅動的知識,希望能夠幫助到大家!

轉發請帶上網址:http://www.www690aa.com/newstwo/105180.html

你可能會喜歡:

版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 babsan@163.com 舉報,一經查實,本站將立刻刪除。