將舊的看門狗驅動程式轉換為看門狗框架¶
作者: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。我們期待您的貢獻 :)