Linux 的即時時鐘 (RTC) 驅動程式¶
當 Linux 開發人員談論“即時時鐘”時,他們通常指的是跟蹤掛鐘時間並有電池支援的裝置,即使系統斷電也能工作。這種時鐘通常不會跟蹤本地時區或夏令時 -- 除非它們與 MS-Windows 雙啟動 -- 而是會被設定為協調世界時 (UTC,以前稱為“格林威治標準時間”)。
最新的非 PC 硬體傾向於只計算秒數,就像 time(2) 系統呼叫報告的那樣,但 RTC 也非常普遍地使用公曆和 24 小時制來表示時間,如 gmtime(3) 報告的那樣。
Linux 有兩個基本相容的使用者空間 RTC API 系列,您可能需要了解
/dev/rtc ... 是 PC 相容系統提供的 RTC,因此它不適合移植到非 x86 系統。
/dev/rtc0, /dev/rtc1 ... 是一個框架的一部分,該框架受到所有系統上的各種 RTC 晶片的支援。
程式設計師需要理解 PC/AT 功能並非總是可用,並且某些系統可以做更多的事情。也就是說,RTC 在兩個 RTC 框架中都使用相同的 API 來發出請求(當然,使用不同的檔名),但硬體可能不提供相同的功能。例如,並非每個 RTC 都連線到 IRQ,因此它們無法發出警報;並且標準 PC RTC 只能發出最多 24 小時後的警報,而其他硬體可能能夠在未來一個世紀內的任何時間安排一個警報。
舊的 PC/AT 相容驅動程式:/dev/rtc¶
所有 PC(甚至 Alpha 機器)都內建了即時時鐘。通常它們內建在計算機的晶片組中,但有些可能實際上在電路板上有一個 Motorola MC146818(或克隆)。這是在您的計算機關閉時保持日期和時間的時鐘。
ACPI 已經標準化了 MC146818 功能,並在某些方面對其進行了擴充套件(啟用更長的警報週期,以及從休眠狀態喚醒)。該功能未在舊驅動程式中公開。
但是,它也可以用於生成從慢速 2Hz 到相對快速的 8192Hz 的訊號,以 2 的冪遞增。這些訊號由中斷號 8 報告。(哦!所以這就是 IRQ 8 的用途...)它也可以用作 24 小時警報,在警報響起時發出 IRQ 8。警報也可以被程式設計為僅檢查三個可程式設計值中的任何子集,這意味著可以將其設定為在每個小時的第 30 分鐘的第 30 秒響起,例如。時鐘也可以設定為在每次時鐘更新時生成中斷,從而生成 1Hz 訊號。
中斷透過 /dev/rtc(主裝置號 10,次裝置號 135,只讀字元裝置)以 unsigned long 的形式報告。低位元組包含引發的中斷型別(更新完成、警報已響或週期性),其餘位元組包含自上次讀取以來的中斷數。如果啟用了 /proc 檔案系統,則透過偽檔案 /proc/driver/rtc 報告狀態資訊。該驅動程式內建鎖定,因此一次只允許一個程序開啟 /dev/rtc 介面。
使用者程序可以透過對 /dev/rtc 執行 read(2) 或 select(2) 來監視這些中斷 -- 它們都會阻塞/停止使用者程序,直到收到下一個中斷。這對於諸如相當高頻率的資料採集之類的任務非常有用,在這種情況下,人們不想透過輪詢 gettimeofday 等等來消耗 100% 的 CPU。
在高頻率或高負載下,使用者程序應檢查自上次讀取以來收到的中斷數,以確定是否存在任何中斷“堆積”。僅供參考,在 /dev/rtc 上執行緊密讀取迴圈的典型 486-33 將開始在高於 1024Hz 的頻率下偶爾出現中斷堆積(即,自上次讀取以來 > 1 個 IRQ 事件)。因此,您確實應該檢查您讀取的值的高位元組,尤其是在高於正常定時器中斷的頻率(即 100Hz)時。
只有 root 才能程式設計和/或啟用大於 64Hz 的中斷頻率。這可能有點保守,但我們不希望邪惡的使用者在慢速 386sx-16 上生成大量 IRQ,這可能會對效能產生負面影響。可以透過將不同的值寫入 /proc/sys/dev/rtc/max-user-freq 來更改此 64Hz 限制。請注意,中斷處理程式只有幾行程式碼,以儘量減少這種影響的可能性。
此外,如果核心時間與外部源同步,核心將每 11 分鐘將時間寫回 CMOS 時鐘。在執行此操作的過程中,核心會短暫關閉 RTC 週期性中斷,因此如果您正在進行認真的工作,請注意這一點。如果您不將核心時間與外部源(透過 ntp 或其他方式)同步,那麼核心將不會干預 RTC,允許您獨佔訪問該裝置以用於您的應用程式。
警報和/或中斷頻率透過 ./include/linux/rtc.h 中列出的各種 ioctl(2) 呼叫程式設計到 RTC 中。與其寫 50 頁描述 ioctl() 等等,不如包含一個小的測試程式,演示如何使用它們,並演示驅動程式的功能,這可能更有用。對於那些有興趣編寫將使用此驅動程式的應用程式的人來說,這可能更有用。請參閱本文件末尾的程式碼。
(最初的 /dev/rtc 驅動程式由 Paul Gortmaker 編寫。)
新的可移植 “RTC 類” 驅動程式:/dev/rtcN¶
由於 Linux 支援許多非 ACPI 和非 PC 平臺,其中一些平臺具有多個 RTC 樣式的時鐘,因此它需要一個比期望每個系統上都有一個電池支援的 MC146818 克隆更具可移植性的解決方案。因此,已經定義了一個新的“RTC 類”框架。它提供了三個不同的使用者空間介面
/dev/rtcN ... 與舊的 /dev/rtc 介面非常相似
/sys/class/rtc/rtcN ... sysfs 屬性支援對某些 RTC 屬性的只讀訪問。
/proc/driver/rtc ... 系統時鐘 RTC 可能會使用 procfs 介面公開自身。如果沒有系統時鐘的 RTC,則預設使用 rtc0。此處顯示的資訊(目前)比透過 sysfs 顯示的資訊更多。
RTC 類框架支援各種 RTC,從整合到可嵌入片上系統 (SOC) 處理器中的 RTC 到使用 I2C、SPI 或其他匯流排與主機 CPU 通訊的離散晶片。甚至還支援 PC 樣式的 RTC ... 包括透過 ACPI 在較新的 PC 上公開的功能。
新的框架還消除了“每個系統一個 RTC”的限制。例如,低功耗電池支援的 RTC 可能是一個離散的 I2C 晶片,但高功能 RTC 整合到 SOC 中。該系統可能會從離散 RTC 讀取系統時鐘,但由於其更高的功能,將其用於所有其他任務。
檢視 tools/testing/selftests/rtc/rtctest.c 以獲取 ioctl 介面的使用示例。