uboot的驅動模型理解

来源:https://www.cnblogs.com/djw316/archive/2019/01/07/10235492.html
-Advertisement-
Play Games

uboot的驅動模型,簡稱dm, 具體細節建議參考./doc/driver-model/README.txt 關於dm的三個概念: uboot的驅動模型,簡稱dm, 具體細節建議參考./doc/driver-model/README.txt 關於dm的三個概念: uclass:一組同類型的devic ...


uboot的驅動模型,簡稱dm, 具體細節建議參考./doc/driver-model/README.txt 關於dm的三個概念: uclass:一組同類型的devices,uclass為同一個group的device,提供一個相同的介面。比如:I2C、GPIO等 driver:上層的介面,英文原文解釋是“some code which talks to a peripheral and presents a higher-level     interface to it.” device:driver的一個實例,綁定到一個具體的埠或者外設。(driver和device是不是可以類比於程式與進程,進程是程式的一個實例)   每一類uclass,需要在代碼中用下麵的方式來定義,以spi-uclass為例:  
UCLASS_DRIVER(spi) = {
    .id        = UCLASS_SPI,
    .name        = "spi",
    .flags        = DM_UC_FLAG_SEQ_ALIAS,
    .post_bind    = spi_post_bind,
    .post_probe    = spi_post_probe,
    .child_pre_probe = spi_child_pre_probe,
    .per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
    .per_child_auto_alloc_size = sizeof(struct spi_slave),
    .per_child_platdata_auto_alloc_size =
            sizeof(struct dm_spi_slave_platdata),
    .child_post_bind = spi_child_post_bind,
};

 

通過對巨集定義UCLASS_DRIVER的展開
/* 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_spi 並且存在 .u_boot_list_2_uclass_2_spi段。 但是我們如何通過ID UCLASS_SPI來找到對應的uclass結構體呢?
struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
{
// 會根據.u_boot_list_2_uclass_1的段地址來得到uclass_driver table的地址
    struct uclass_driver *uclass =
        ll_entry_start(struct uclass_driver, uclass);
 
// 獲得uclass_driver table的長度
    const int n_ents = ll_entry_count(struct uclass_driver, uclass);
    struct uclass_driver *entry;
 
    for (entry = uclass; entry != uclass + n_ents; entry++) {
        if (entry->id == id)
            return entry;
    }
 
    return NULL;
}
可以通過函數lists_uclass_lookup(enum uclass_id id)來查找。   另外,driver也是類似
/* 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)))
 
U_BOOT_DRIVER(tegra114_spi) = {
    .name    = "tegra114_spi",
    .id    = UCLASS_SPI,
    .of_match = tegra114_spi_ids,
    .ops    = &tegra114_spi_ops,
    .ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
    .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
    .priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
    .probe    = tegra114_spi_probe,
};
這樣我們就能得到一個結構體,
ll_entry_declare(struct driver, tegra114_spi, driver)
 
struct driver _u_boot_list_2_driver_2_tegra114_spi
                             __aligned(4)        \
            __attribute__((unused,                \
            section(".u_boot_list_2_driver_2_tegra114_spi")))

 

存儲在段,.u_boot_list_2_driver_2_tegra114_spi 但是這些段,在uboot實際載入的時候,又是如何載入到鏈表中去的呢!   首先,還是初始化列表init_sequence_f里的函數initf_dm
static int initf_dm(void)
{
#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
    int ret;
 
    ret = dm_init_and_scan(true);
    if (ret)
        return ret;
#endif
#ifdef CONFIG_TIMER_EARLY
    ret = dm_timer_init();
    if (ret)
        return ret;
#endif
 
    return 0;
}
dm_init_and_scan(),代碼分析如下
int dm_init_and_scan(bool pre_reloc_only)
{
    int ret;
 
    /*創建udevice和uclass空鏈表,創建根設備(root device)*/
    ret = dm_init();
    if (ret) {
        debug("dm_init() failed: %d\n", ret);
        return ret;
    }
    /*掃描U_BOOT_DEVICE定義的設備,與U_BOOT_DRIVER定義的driver進行查找,並綁定相應driver*/
    ret = dm_scan_platdata(pre_reloc_only);
    if (ret) {
        debug("dm_scan_platdata() failed: %d\n", ret);
        return ret;
    }
 
    if (CONFIG_IS_ENABLED(OF_CONTROL)) {
        /*掃描由FDT設備樹文件定義的設備,與U_BOOT_DRIVER定義的driver進行查找,並綁定相應driver*/
        ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
        if (ret) {
            debug("dm_scan_fdt() failed: %d\n", ret);
            return ret;
        }
    }
    ret = dm_scan_other(pre_reloc_only);
    if (ret)
        return ret;
 
    return 0;
}
分三個部分: dm_init():創建udevice和uclass空鏈表,創建根設備(root device) dm_scan_platdata():調用函數lists_bind_drivers,掃描U_BOOT_DEVICE定義的設備,與U_BOOT_DRIVER定義的driver進行查找,創建udevice,並綁定相應driver。 dm_scan_fdt():掃描由FDT設備樹文件定義的設備,與U_BOOT_DRIVER定義的driver進行查找,創建udevice,並綁定相應driver。
int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
{
    /*從分段,.u_boot_list_2_driver_info中來查找*/
    struct driver_info *info =
        ll_entry_start(struct driver_info, driver_info);
 
    const int n_ents = ll_entry_count(struct driver_info, driver_info);
    struct driver_info *entry;
    struct udevice *dev;
    int result = 0;
    int ret;
 
    for (entry = info; entry != info + n_ents; entry++) {
        /*將driver_info列表裡面的name,依次與driver列表裡面的名字,進行匹配查找,然後進行綁定*/
        ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
        if (ret && ret != -EPERM) {
            dm_warn("No match for driver '%s'\n", entry->name);
            if (!result || ret != -ENOENT)
                result = ret;
        }
    }
 
    return result;
}
 
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
            const struct driver_info *info, struct udevice **devp)
{
    struct driver *drv;
 
    /*從driver list中查找info的名字*/
    drv = lists_driver_lookup_name(info->name);
    if (!drv)
        return -ENOENT;
    if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
        return -EPERM;
    
    /*創建udevice,綁定*/
    return device_bind(parent, drv, info->name, (void *)info->platdata,
               -1, devp);
}
U_BOOT_DEVICE的巨集定義,註意與U_BOOT_DRIVER的區別:
 
#define U_BOOT_DEVICE(__name)                        \
    ll_entry_declare(struct driver_info, __name, driver_info)

 

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 通過 ASP.NET Core,開發者可輕鬆配置和管理其應用的安全性。 ASP.NET Core 中包含管理身份驗證、授權、數據保護、SSL 強制、應用機密、請求防偽保護及 CORS 管理等等安全方面的處理。 通過這些安全功能,可以生成安全可靠的 ASP.NET Core 應用。而我們這一章就來說道 ...
  • asp.net core參數保護之自定義要保護的參數類型 Intro 為了實現 asp.net core 下的參數保護,擴展了asp.net core 中 DataProtection,可以自動化的保護某些敏感參數,上次推出之後有一些小伙伴反饋希望能保護 返回的參數,本文主要以 為例介紹如何註冊自定 ...
  • 藉助表達式樹感受不一樣的CRUD Intro 最近有個想法,想不寫 sql 語句,做一個類似於 ORM 的東西,自己解析表達式樹,生成要執行的 sql 語句,最後再執行 sql 語句,返回相應結果。 思路解析 常用的 sql 語句基本都有一定的模式,就是 /`DELETE Update SELECT ...
  • 寫在最前:控制台輸出中文亂碼,完全是跟win10操作系統有關,跟VS基本無關,所以網上大量的用VS下載安裝更新的解決辦法是事倍功半的(而且不一定成功),本文的方法只需幾個簡單的步驟,就能解決中文亂碼問題,簡單明快。 本文參照此網友blog:https://blog.csdn.net/C_Khalid ...
  • 一. 依賴註入概述 在軟體設計的通用原則中,SOLID是非常流行的縮略語,它由5個設計原則的首字母構成:單一原則(S)、開放封閉原則(O)、里氏替換原則(L)、介面分離原則(I)、依賴反轉原則(D)。本篇介紹依賴反轉原則以及在ASP.NET Core中的實現。 直接依賴是指:當一個類需要另一個類協作 ...
  • 一、前言 在項目開發中,日誌系統是系統的一個重要組成模塊,通過在程式中記錄運行日誌、錯誤日誌,可以讓我們對於系統的運行情況做到很好的掌控。同時,收集日誌不僅僅可以用於診斷排查錯誤,由於日誌同樣也是大量的數據,通過對這些數據進行集中分析,可以產生極大的價值。 在微服務的系統架構中,由於一個系統會被拆成 ...
  • 1、基於功能變數名稱的虛擬主機: 絕大多數企業對外提供服務的網站使用的都是基於功能變數名稱的主機,通過不同的功能變數名稱區分不同的虛擬主機。 首先我們進入安裝nginxd的目錄下:/application/nginx-1.6.3/conf 我們去除掉預設配置文件里的註釋和空行並重定向到nginx.conf文件里,同時我們需 ...
  • 參考騰訊雲實驗室 Hadoop分佈環境搭建步驟: 1.軟硬體環境 CentOS 7.2 64 位 JDK- 1.8 Hadoo p- 2.7.4 2.安裝SSH sudo yum install openssh-clients openssh-server 測試: ssh localhost 測試完 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...