將舊的看門狗驅動程式轉換為看門狗框架

作者:Wolfram Sang <wsa@kernel.org>

在看門狗框架進入核心之前,每個驅動程式都必須自行實現其 API。現在,由於該框架提取出了通用元件,這些驅動程式可以得到簡化,成為框架的使用者。本文件將指導您完成此任務。其中描述了必要的步驟以及需要注意的事項。

移除 file_operations 結構體

舊的驅動程式會為 open()、write() 等操作定義自己的 file_operations……這些現在由框架處理,只在需要時呼叫驅動程式。因此,一般來說,`file_operations` 結構體和相關函式可以移除。只有極少數驅動程式特定的細節需要移動到其他函式中。下面是函式和可能需要的操作的概述:

  • open:所有與資源管理相關的內容(檔案開啟檢查、魔術關閉準備)都可以直接移除。裝置特定的內容需要移至驅動程式特定的啟動函式。請注意,對於某些驅動程式,啟動函式也兼作心跳函式。如果出現這種情況,並且您需要啟動/停止功能平衡(例如時鐘!),最好重構一個單獨的啟動函式。

  • close:與 open 相同的提示也適用。

  • write:可以簡單移除,所有已定義的行為都由框架處理,即寫入時進行心跳操作和魔術字元('V')處理。

  • ioctl:雖然驅動程式允許對 IOCTL 介面進行擴充套件,但最常見的操作由框架處理,並得到驅動程式的一些協助

    WDIOC_GETSUPPORT

    返回驅動程式中強制性的 watchdog_info 結構體

    WDIOC_GETSTATUS

    需要定義 status-callback,否則返回 0

    WDIOC_GETBOOTSTATUS

    需要正確設定 bootstatus 成員。如果您沒有進一步的支援,請確保它為 0!

    WDIOC_SETOPTIONS

    無需準備

    WDIOC_KEEPALIVE

    如果需要,watchdog_info 中的選項需要設定 WDIOF_KEEPALIVEPING

    WDIOC_SETTIMEOUT

    watchdog_info 中的選項需要設定 WDIOF_SETTIMEOUT,並且必須定義 set_timeout 回撥。如果看門狗裝置中設定了 min_timeout 和 max_timeout,核心也會進行限制檢查。所有這些都是可選的。

    WDIOC_GETTIMEOUT

    無需準備

    WDIOC_GETTIMELEFT

    需要定義 get_timeleft() 回撥。否則將返回 EOPNOTSUPP

    其他 IOCTLs 可以使用 ioctl 回撥來處理。請注意,這主要用於移植舊驅動程式;新驅動程式不應發明私有 IOCTLs。私有 IOCTLs 會首先處理。當回撥返回 -ENOIOCTLCMD 時,框架的 IOCTLs 也會被嘗試。任何其他錯誤將直接返回給使用者。

轉換示例

-static const struct file_operations s3c2410wdt_fops = {
-       .owner          = THIS_MODULE,
-       .write          = s3c2410wdt_write,
-       .unlocked_ioctl = s3c2410wdt_ioctl,
-       .open           = s3c2410wdt_open,
-       .release        = s3c2410wdt_release,
-};

檢查函式中是否有裝置特定的內容並保留它們以供後續重構。其餘的可以移除。

移除 miscdevice

由於 file_operations 已被移除,您也可以移除 `struct miscdevice`。框架將在 watchdog_register_device() 呼叫 watchdog_dev_register() 時建立它。

-static struct miscdevice s3c2410wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &s3c2410wdt_fops,
-};

移除廢棄的標頭檔案和定義

由於簡化,現在可能有一些定義不再使用。請移除它們。標頭檔案也可以移除。例如

- #include <linux/fs.h>
- #include <linux/miscdevice.h> (if MODULE_ALIAS_MISCDEV is not used)
- #include <linux/uaccess.h> (if no custom IOCTLs are used)

新增看門狗操作

所有可能的回撥都在 `struct watchdog_ops` 中定義。您可以在此目錄中的《Linux 看門狗定時器驅動程式核心核心 API》中找到其解釋。start() 和 owner 必須設定,其餘可選。您將在舊驅動程式中輕鬆找到相應的函式。請注意,現在您將獲得一個指向 watchdog_device 的指標作為這些函式的引數,因此您可能需要更改函式頭。其他更改很可能不需要,因為這裡只是直接進行硬體訪問。如果您在上述步驟中留下了裝置特定的程式碼,則應將其重構到這些回撥中。

這是一個簡單的例子

+static struct watchdog_ops s3c2410wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = s3c2410wdt_start,
+       .stop = s3c2410wdt_stop,
+       .ping = s3c2410wdt_keepalive,
+       .set_timeout = s3c2410wdt_set_heartbeat,
+};

典型的函式頭更改如下所示:

-static void s3c2410wdt_keepalive(void)
+static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
 {
...
+
+       return 0;
 }

...

-       s3c2410wdt_keepalive();
+       s3c2410wdt_keepalive(&s3c2410_wdd);

新增看門狗裝置

現在我們需要建立一個 `struct watchdog_device` 並用框架所需的資訊填充它。該結構體也在此目錄中的《Linux 看門狗定時器驅動程式核心核心 API》中詳細解釋。我們向它傳遞強制性的 watchdog_info 結構體和新建立的 watchdog_ops。通常,舊驅動程式使用靜態變數來記錄啟動狀態和超時等資訊。這些必須轉換為使用 watchdog_device 中的成員。請注意,超時值是無符號整數。有些驅動程式使用有符號整數,因此也必須進行轉換。

這是一個簡單的看門狗裝置示例

+static struct watchdog_device s3c2410_wdd = {
+       .info = &s3c2410_wdt_ident,
+       .ops = &s3c2410wdt_ops,
+};

處理 'nowayout' 功能

少數驅動程式靜態使用 nowayout,即沒有模組引數來控制它,只有 CONFIG_WATCHDOG_NOWAYOUT 決定是否使用該功能。這需要透過如下方式初始化 watchdog_device 的狀態變數來進行轉換:

.status = WATCHDOG_NOWAYOUT_INIT_STATUS,

然而,大多數驅動程式也允許在執行時配置 nowayout,通常是透過新增模組引數。這方面的轉換會是這樣的:

watchdog_set_nowayout(&s3c2410_wdd, nowayout);

模組引數本身需要保留,但所有其他與 nowayout 相關的內容都可以移除。這可能是一些在 open()、close() 或 write() 中的程式碼。

註冊看門狗裝置

將 misc_register(&miscdev) 替換為 watchdog_register_device(&watchdog_dev)。確保檢查返回值,並且錯誤訊息(如果存在)仍然適用。同時轉換登出情況。

-       ret = misc_register(&s3c2410wdt_miscdev);
+       ret = watchdog_register_device(&s3c2410_wdd);

...

-       misc_deregister(&s3c2410wdt_miscdev);
+       watchdog_unregister_device(&s3c2410_wdd);

更新 Kconfig 條目

現在驅動程式的條目需要選擇 WATCHDOG_CORE

  • select WATCHDOG_CORE

建立補丁並將其傳送到上游

確保您已理解提交補丁:將程式碼引入核心的基本指南並將您的補丁傳送到linux-watchdog@vger.kernel.org。我們期待您的貢獻 :)