Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 裝置驅動模型探討:probe 函數調用時機與總線匹配機制深度解析

編輯:Linux 教學

前言

Linux 裝置驅動模型以「總線-裝置-驅動」三元架構為核心。驅動註冊後,其 probe() 何時被調用?關鍵在於總線的 match() 函數。本文從 driver_register() 入手,逐層追蹤原始碼路徑,揭示 probe() 被調用的完整呼叫鏈與判斷邏輯。

一、驅動註冊入口:driver_register()

int driver_register(struct device_driver *drv) {
    klist_init(&drv->klist_devices, ...);
    init_completion(&drv->unloaded);
    return bus_add_driver(drv);   // 關鍵轉向總線層
}

二、總線層掛載驅動:bus_add_driver()

  • 建立驅動的 kobject、sysfs 節點。
  • 調用 driver_attach(drv) → 遍歷總線上所有裝置嘗試匹配。

三、遍歷匹配:driver_attach() → __driver_attach()

void driver_attach(struct device_driver *drv) {
    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

static int __driver_attach(struct device *dev, void *data) {
    struct device_driver *drv = data;
    if (!dev->driver)               // 裝置尚未綁定驅動
        driver_probe_device(drv, dev);
    return 0;
}

四、核心匹配與 Probe:driver_probe_device()


int driver_probe_device(struct device_driver *drv, struct device *dev) {
    // 1. 總線 match 函數判斷是否匹配
    if (drv->bus->match && !drv->bus->match(dev, drv))
        return -ENODEV;   // 不匹配,直接返回

    // 2. 匹配成功,真正調用 probe
    if (drv->probe) {
        int ret = drv->probe(dev);
        if (ret) {
            dev->driver = NULL;
            return ret;   // probe 失敗
        }
        dev->driver = drv;   // 綁定成功
    }
    return 0;
}

五、關鍵點:總線 match() 決定生死

  • 只有 drv->bus->match(dev, drv) 返回 1,probe() 才會被調用。
  • 不同總線實作不同 match():

PCI 總線範例


static int pci_bus_match(struct device *dev, struct device_driver *drv) {
    struct pci_dev *pdev = to_pci_dev(dev);
    struct pci_driver *pdrv = to_pci_driver(drv);
    return pci_match_device(pdrv, pdev) ? 1 : 0;   // 比對 id_table
}

PCI 驅動在 struct pci_driver 中定義 id_table,核心自動比對廠商/裝置 ID。

Platform 總線範例


static int platform_match(struct device *dev, struct device_driver *drv) {
    return strncmp(dev_name(dev), drv->name, strlen(drv->name)) == 0;  // 名稱比對
}

Platform 裝置與驅動透過名稱字串比對綁定(常見於 SoC 內建外設)。

六、另一條路徑:really_probe()(新版核心)

新版核心(如 5.x)在 driver_probe_device() 內部委派給 really_probe():


static int really_probe(struct device *dev, struct device_driver *drv) {
    // 1. 總線層 probe(少用)
    if (dev->bus->probe) {
        ret = dev->bus->probe(dev);
        if (ret) goto probe_failed;
    }
    // 2. 驅動層 probe(主流)
    else if (drv->probe) {
        ret = drv->probe(dev);
        if (ret) goto probe_failed;
    }
    // 成功綁定
    dev->driver = drv;
    return 0;
probe_failed:
    dev->driver = NULL;
    return ret;
}

七、總結流程圖


driver_register()
   └─ bus_add_driver()
        └─ driver_attach()
             └─ bus_for_each_dev() → __driver_attach()
                  └─ driver_probe_device()
                       ├─ bus->match(dev, drv) ?  → NO → 結束
                       └─ YES → drv->probe(dev)  → 成功 → dev->driver = drv

八、實務啟示

  1. 驅動不會被 probe → 檢查 bus->match 邏輯(id_table、名稱、of_match_table 等)。
  2. Platform 驅動:確保 .name 與 DTS/板級註冊的裝置名稱完全一致。
  3. PCI 驅動:id_table 需包含目標裝置的 Vendor/Device ID,且 PCI_DEVICE() 巨集正確展開。
  4. Device Tree 綁定:of_match_table 配合 compatible 屬性,由 of_driver_match_device() 在 match 階段比對。
Copyright © Windows教程網 All Rights Reserved