platform_driver驅動及裝置驅動匹配識別符號

lethe1203發表於2024-03-25

一、裝置樹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 驅動匯流排的三種常見的匹配方式
  1. 基於driver.name屬性的匹配方式:透過driver.namedevice.name來進行對比匹配
  1. 基於 compatible 屬性的匹配方式: 裝置樹中的裝置節點通常會包含一個 compatible 屬性,用於描述裝置的相容性標識。platform 驅動匯流排透過比較裝置節點的 compatible 屬性與驅動程式中定義的 of_device_id 結構體陣列中的相容性標識,來進行匹配。具體示例可以參考前面提到的 of_match_device() 函式的用法。
  2. 基於 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_tableplatform_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);
函式接受兩個引數:
  1. matches:一個指向 of_device_id 結構體陣列的指標,包含了裝置驅動程式所支援的裝置相容性標識。
  2. 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 標頭檔案中宣告的。

相關文章