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 設備模型深度解析:Platform 驅動註冊全流程

編輯:Linux 教學

Linux 設備模型將裝置與驅動透過總線綁定。本文以 S3C2410 RTC 驅動為例,追蹤 platform_driver_register() 至 driver_register() 的完整呼叫鏈,揭示總線、驅動、裝置三者互動機制。

Platform 驅動定義範例

static struct platform_driver s3c2410_rtc_driver = {
    .probe   = s3c_rtc_probe,
    .remove  = __devexit_p(s3c_rtc_remove),
    .suspend = s3c_rtc_suspend,
    .resume  = s3c_rtc_resume,
    .driver  = {
        .name  = "s3c2410-rtc",
        .owner = THIS_MODULE,
    },
};

.name 將成為 /sys/bus/platform/drivers/s3c2410-rtc 目錄名,也是匹配裝置的關鍵鍵值。

註冊入口:platform_driver_register()

int platform_driver_register(struct platform_driver *drv) {
    drv->driver.bus = &platform_bus_type;          // 關鍵:綁定總線類型
    if (drv->probe)   drv->driver.probe   = platform_drv_probe;
    if (drv->remove)  drv->driver.remove  = platform_drv_remove;
    if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown;
    if (drv->suspend) drv->driver.suspend = platform_drv_suspend;
    if (drv->resume)  drv->driver.resume  = platform_drv_resume;
    return driver_register(&drv->driver);          // 轉入核心驅動註冊
}

關鍵點:將 platform_driver 專用回調包裝為通用 device_driver 回調,並指定 bus = &platform_bus_type。總線類型決定後續匹配規則(match() 回調)。

核心驅動註冊:driver_register()

int driver_register(struct device_driver *drv) {
    // 1. 相容性檢查:避免同時定義 bus->probe 與 drv->probe
    if ((drv->bus->probe && drv->probe) || ...)
        printk(KERN_WARNING "Driver '%s' needs updating...", drv->name);

    // 2. 重複註冊檢查
    struct device_driver *other = driver_find(drv->name, drv->bus);
    if (other) { put_driver(other); return -EEXIST; }

    // 3. 加入總線 kset,建立 sysfs 目錄與連結
    int ret = bus_add_driver(drv);
    if (ret) return ret;

    // 4. 處理 attribute groups(本例無)
    ret = driver_add_groups(drv, drv->groups);
    if (ret) bus_remove_driver(drv);
    return ret;
}

驅動查找機制:driver_find()

struct device_driver *driver_find(const char *name, struct bus_type *bus) {
    struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
    if (k) {
        struct driver_private *priv = to_driver(k);
        return priv->driver;
    }
    return NULL;
}

總線內部維護 drivers_kset(kobject 集合),透過 kobject 名稱索引驅動。kset_find_obj() 遍歷鏈表比對名稱。

關鍵資料結構關聯圖

  • platform_bus_type:定義 match()、uevent() 等總線行為。
  • device_driver:通用驅動物件,掛載於 bus->p->drivers_kset。
  • platform_driver:Platform 專用封裝,含 probe/remove/shutdown/suspend/resume。
  • driver_private:核心內部封裝,持有 struct device_driver *driver 並掛載 kobject。

實務啟示

  1. 命名唯一性:driver.name 必須在同總線下唯一,否則註冊失敗返回 -EEXIST。
  2. 回調包裝:Platform 層將裝置指標轉換為 struct platform_device * 再呼叫驅動原始回調,驅動開發者無需感知總線細節。
  3. sysfs 映射:註冊成功自動建立 /sys/bus/platform/drivers/<name>,可透過 bind/unbind 手動控制綁定。

理解此流程,有助於除錯驅動未被 Probe、總線匹配失敗、sysfs 節點異常等問題。

Copyright © Windows教程網 All Rights Reserved