一、裝置樹platform_driver示例
裝置樹中需要定義一個裝置節點,包含裝置的相關資訊和屬性。例如,假設有一個名為 "my_device" 的裝置,其裝置樹節點可能如下所示:
/dts-v1/; / { compatible = "example,my_device"; my_device { compatible = "example,my_device"; reg = <0x12345678 0x1000>; interrupt-parent = <&gpio0>; interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; }; };
在上述示例中,該裝置節點具有
compatible
屬性來標識裝置的相容性,reg
屬性用於指定裝置的地址範圍,interrupt-parent
屬性指定中斷控制器的父節點,interrupts
屬性指定裝置的中斷號和觸發型別。在驅動程式中定義
platform_driver
結構體,並使用 of_match_ptr()
宏將裝置的相容性標識與驅動程式關聯起來。例如:#include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> static int my_driver_probe(struct platform_device *pdev) { // 在這裡執行裝置的初始化和操作 return 0; } static int my_driver_remove(struct platform_device *pdev) { // 在這裡執行裝置的清理和操作 return 0; } static const struct of_device_id my_driver_of_match[] = { { .compatible = "example,my_device" }, {}, }; MODULE_DEVICE_TABLE(of, my_driver_of_match); static struct platform_driver my_driver = { .driver = { .name = "my_device", .of_match_table = of_match_ptr(my_driver_of_match), }, .probe = my_driver_probe, .remove = my_driver_remove, }; module_platform_driver(my_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203");
二、platform驅動匯流排的匹配方式
首先看下platform_driver、device_driver和device_driver結構體的定義:
struct platform_driver
是Linux核心中用於表示平臺驅動程式的結構體。它包含了與平臺裝置驅動相關的屬性和操作,用於管理和控制平臺裝置。下面是
struct platform_driver
結構體的定義:struct platform_driver { int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); void (*shutdown)(struct platform_device *pdev); int (*suspend)(struct platform_device *pdev, pm_message_t state); int (*resume)(struct platform_device *pdev); struct device_driver driver; // device_driver結構體** const struct platform_device_id *id_table; // 匹配規則三 bool prevent_deferred_probe; };
struct platform_driver
結構體的主要欄位如下:probe
: 當匹配到某個平臺裝置時,呼叫該函式進行裝置的初始化。remove
: 在裝置被移除時,呼叫該函式進行裝置的清理和釋放資源操作。shutdown
: 可選欄位,在系統關機時呼叫該函式進行裝置的關機處理。suspend
: 可選欄位,在裝置進入掛起狀態時呼叫該函式進行裝置的掛起操作。resume
: 可選欄位,在裝置從掛起狀態恢復時呼叫該函式進行裝置的恢復操作。driver
: 包含了和裝置驅動相關的屬性,如名稱、owner等。id_table
: 可選欄位,用於指定平臺裝置的標識表,用於驅動程式的裝置匹配。prevent_deferred_probe
: 可選欄位,用於控制是否延遲裝置的探測。
struct device_driver
是 Linux 核心中用於表示裝置驅動程式的結構體。它包含了與裝置驅動相關的屬性和操作,用於管理和控制特定型別的裝置。下面是
struct device_driver
結構體的定義:struct device_driver { const char *name; // 匹配規則一 struct bus_type *bus; struct module *owner; const char *mod_name; bool suppress_bind_attrs; const struct of_device_id *of_match_table; // 匹配規則二 int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };
struct device_driver
結構體的主要欄位如下:name
: 裝置驅動程式的名稱。bus
: 指向裝置所屬的匯流排型別的指標。owner
: 指向擁有該裝置驅動程式的模組的指標。mod_name
: 擁有該裝置驅動程式的模組的名稱。suppress_bind_attrs
: 一個布林值,用於控制是否在 sysfs 中暴露 bind/unbind 相關的屬性。of_match_table
: 指向裝置樹匹配表的指標,用於匹配裝置樹節點。probe
: 當匹配到裝置時,呼叫該函式來初始化裝置。remove
: 在裝置被移除時,呼叫該函式來清理和釋放資源。shutdown
: 可選欄位,在系統關機時呼叫該函式進行裝置的關機處理。suspend
: 可選欄位,在裝置進入掛起狀態時呼叫該函式進行裝置的掛起操作。resume
: 可選欄位,在裝置從掛起狀態恢復時呼叫該函式進行裝置的恢復操作。groups
: 指向裝置驅動程式所屬的屬性組陣列的指標。pm
: 指向裝置的電源管理操作的指標。
struct platform_device
是 Linux 核心中用於表示平臺裝置的結構體。它用於描述與特定平臺相關的裝置,例如 SoC 上的外設或其他與硬體整合的裝置。下面是
struct platform_device
結構體的定義:struct platform_device { const char *name; // 匹配方式一 int id; struct device dev; u32 num_resources; struct resource *resource; const struct platform_device_id *id_entry; };
struct platform_device
結構體的主要欄位如下:name
: 裝置的名稱。該名稱通常與裝置驅動程式關聯。id
: 裝置的 ID。用於標識同一型別的多個裝置。dev
: 表示該平臺裝置的通用裝置結構體。它可以被裝置模型用於管理裝置物件。num_resources
: 裝置資源的數量。resource
: 指向裝置資源描述符的指標陣列。每個資源描述符包含了裝置在系統中所需的 I/O 地址、中斷等資訊。id_entry
: 指向平臺裝置標識表的指標,用於驅動程式的裝置匹配。
在 Linux 核心中,
platform
驅動匯流排使用裝置樹中的裝置節點來與驅動程式進行匹配。介紹 platform
驅動匯流排的三種常見的匹配方式。- 基於
driver.name
屬性的匹配方式:透過driver.name
和device.name
來進行對比匹配
- 基於
compatible
屬性的匹配方式: 裝置樹中的裝置節點通常會包含一個compatible
屬性,用於描述裝置的相容性標識。platform
驅動匯流排透過比較裝置節點的compatible
屬性與驅動程式中定義的of_device_id
結構體陣列中的相容性標識,來進行匹配。具體示例可以參考前面提到的of_match_device()
函式的用法。 - 基於
platform_device_id
的匹配方式: 驅動程式可以定義一個platform_device_id
結構體陣列,並透過MODULE_DEVICE_TABLE(platform, ...)
宏將其註冊為可供核心使用的裝置表。裝置節點在與驅動程式匹配時,會透過比較裝置節點的name
屬性與驅動程式中定義的platform_device_id
結構體陣列中的裝置名稱,來進行匹配。具體示例可以參考前面提到的platform_device_id
的用法。
需要注意的是,
platform
驅動匯流排的匹配方式是基於裝置樹的,因此要求裝置樹中正確地描述了裝置的配置資訊,包括裝置節點的相容性標識和其他屬性。具體的驅動可參考:
驅動——platform驅動匯流排三種匹配方式_platform匹配過程_犩未的部落格-CSDN部落格
三、of_match_ptr、of_match_device、platform_get_device_id
of_match_ptr
of_match_ptr()
是一個用於將 of_device_id
結構體陣列傳遞給 of_match_table
欄位的宏。它將 of_device_id
結構體陣列的指標轉換為 const struct of_device_id *
型別,以便在註冊 platform_driver
時使用。of_match_table
是 platform_driver
結構體中的一個欄位,用於指定裝置樹匹配表。透過傳遞 of_match_ptr()
宏轉換後的指標,可以將裝置樹匹配表與驅動程式關聯起來,實現裝置樹節點和驅動程式的匹配。示例程式碼中的這行程式碼:
.driver = { .name = "my_device", .of_match_table = of_match_ptr(my_driver_of_match), },
使用了
of_match_ptr()
宏將 my_driver_of_match
陣列的指標傳遞給了 of_match_table
欄位。這樣,當 platform_driver
註冊到核心時,核心就能根據裝置樹節點的相容性標識進行匹配,並呼叫相應的回撥函式。of_match_device
of_match_device()
函式用於在裝置樹中查詢與給定裝置匹配的裝置相容性標識(compatible)。以下是
of_match_device()
函式的原型:const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev);
函式接受兩個引數:
matches
:一個指向of_device_id
結構體陣列的指標,包含了裝置驅動程式所支援的裝置相容性標識。dev
:一個指向struct device
的指標,表示當前需要匹配的裝置。
函式返回一個指向匹配的
of_device_id
結構體的指標。如果找不到匹配項,則返回 NULL
。以下是一個示例用法:
static const struct of_device_id my_driver_dt_ids[] = { { .compatible = "device1" }, { .compatible = "device2" }, // 其他裝置相容性標識 }; static int my_driver_probe(struct platform_device *pdev) { const struct of_device_id *id; id = of_match_device(my_driver_dt_ids, &pdev->dev); if (!id) return -ENODEV; if (strcmp(id->compatible, "device1") == 0) { // 匹配到 device1 的處理邏輯 } else if (strcmp(id->compatible, "device2") == 0) { // 匹配到 device2 的處理邏輯 } return 0; }
在上述示例中,
my_driver_dt_ids
是一個包含裝置相容性標識的陣列。在驅動程式的 probe
函式中,使用 of_match_device()
函式來獲取與平臺裝置匹配的裝置相容性標識,並透過相應的操作來處理匹配到的裝置。platform_get_device_id
platform_get_device_id()
是一個函式,用於獲取與給定平臺裝置匹配的平臺裝置標識。函式原型如下:
const struct platform_device_id *platform_get_device_id(const struct platform_device *pdev);
引數
pdev
是一個指向 struct platform_device
的指標,表示要查詢的平臺裝置。函式返回值是一個指向
struct platform_device_id
的指標,表示與給定平臺裝置匹配的平臺裝置標識。如果找不到匹配的標識,則返回 NULL
。struct platform_device_id
結構體定義如下:struct platform_device_id { char name[PLATFORM_NAME_SIZE]; // 裝置名稱 kernel_ulong_t driver_data; // 驅動程式資料 };
platform_get_device_id()
函式透過遍歷平臺裝置驅動程式註冊的平臺裝置標識表(struct platform_device_id
陣列),與給定的平臺裝置的名稱進行匹配。如果找到匹配的標識,則返回該標識的指標;否則返回 NULL
。通常,在編寫平臺裝置驅動程式時,會在驅動程式中定義一個平臺裝置標識表,並將其註冊到核心中。當平臺裝置被建立時,驅動程式會根據裝置的名稱和其他屬性,匹配對應的標識,並執行相應的初始化操作。
注意:
platform_get_device_id()
函式是在 include/linux/platform_device.h
標頭檔案中宣告的。