linux下(xia)的(de)rtc機制(zhi)
時間(jian):2014-10-18 來源:未知
Linux的(de)RTC驅動相對(dui)還是(shi)比(bi)較(jiao)(jiao)簡單的(de),可以將它作為(wei)一個普(pu)通(tong)的(de)字符型設備(bei),或者一個misc設備(bei),也可以是(shi)一個平臺設備(bei),這(zhe)都沒有關(guan)系,主(zhu)要(yao)(yao)還是(shi)對(dui)rtc_ops這(zhe)個文件操作結構體中的(de)成員(yuan)填充(chong),這(zhe)里(li)主(zhu)要(yao)(yao)涉(she)及到兩個方面比(bi)較(jiao)(jiao)重(zhong)要(yao)(yao):
1. 在Linux中有硬件(jian)時(shi)鐘(zhong)(zhong)(zhong)(zhong)與系(xi)統(tong)(tong)時(shi)鐘(zhong)(zhong)(zhong)(zhong)等兩(liang)種時(shi)鐘(zhong)(zhong)(zhong)(zhong)。硬件(jian)時(shi)鐘(zhong)(zhong)(zhong)(zhong)是(shi)(shi)指主機板上(shang)的(de)時(shi)鐘(zhong)(zhong)(zhong)(zhong)設(she)備(bei),也就(jiu)是(shi)(shi)通常可(ke)在BIOS畫面設(she)定(ding)的(de)時(shi)鐘(zhong)(zhong)(zhong)(zhong)。系(xi)統(tong)(tong)時(shi)鐘(zhong)(zhong)(zhong)(zhong)則是(shi)(shi)指kernel中的(de)時(shi)鐘(zhong)(zhong)(zhong)(zhong)。當Linux啟動時(shi),系(xi)統(tong)(tong)時(shi)鐘(zhong)(zhong)(zhong)(zhong)會去(qu)讀(du)取硬件(jian)時(shi)鐘(zhong)(zhong)(zhong)(zhong)的(de)設(she)定(ding),之后(hou)系(xi)統(tong)(tong)時(shi)鐘(zhong)(zhong)(zhong)(zhong)即(ji)獨(du)立運(yun)作。所有Linux相關(guan)指令與函(han)數都是(shi)(shi)讀(du)取系(xi)統(tong)(tong)時(shi)鐘(zhong)(zhong)(zhong)(zhong)的(de)設(she)定(ding)。
系統(tong)時(shi)鐘(zhong)(zhong)(zhong)的(de)(de)設定就(jiu)是(shi)我(wo)(wo)們(men)常(chang)用的(de)(de)date命(ming)令(ling)(ling),而我(wo)(wo)們(men)寫的(de)(de)RTC驅動(dong)(dong)就(jiu)是(shi)為硬件時(shi)鐘(zhong)(zhong)(zhong)服務的(de)(de),它有(you)屬于(yu)自己的(de)(de)命(ming)令(ling)(ling)hwclock,因此使(shi)用date命(ming)令(ling)(ling)是(shi)不可能調用到(dao)(dao)我(wo)(wo)們(men)的(de)(de)驅動(dong)(dong)的(de)(de)(在這點(dian)上開始把我(wo)(wo)郁悶到(dao)(dao)了,寫完驅動(dong)(dong)之后(hou),傻傻的(de)(de)用date指令(ling)(ling)來測(ce)試,當然結果(guo)是(shi)什么都沒有(you)),我(wo)(wo)們(men)可以(yi)通過hwclock的(de)(de)一些指令(ling)(ling)來實現更(geng)新(xin)rtc時(shi)鐘(zhong)(zhong)(zhong)——也就(jiu)是(shi)系統(tong)時(shi)鐘(zhong)(zhong)(zhong)和硬件時(shi)鐘(zhong)(zhong)(zhong)的(de)(de)交(jiao)互。
hwclock –r顯(xian)示硬件時鐘與(yu)日期
hwclock –s將系統時鐘調整為與目前(qian)的硬(ying)件時鐘一(yi)致(zhi)。
hwclock –w將(jiang)硬件時鐘(zhong)(zhong)調(diao)整為與(yu)目前的(de)系統時鐘(zhong)(zhong)一(yi)致。
用戶(hu)輸入 hwclck -s // 這個命(ming)令是 把(ba)硬件(jian)的(de)時鐘更新到系(xi)統中去
這個命令會調用busybox源碼中的hwclock.c,在(zai)目錄util-linux/hwclock.c 中的 ->int hwclock_main(int argc UNUSED_PARAM, char **argv)
后面的參數會以argv形式接收
opt = getopt32(argv, "lurswtf:", &rtcname);
會把argv的參數進行轉換 l -> 0x01
u -> 0x02
r -> 0x04
s -> 0x08
w -> 0x10
t -> 0x20
f -> 0x40
: -> 0x80
#define HWCLOCK_OPT_LOCALTIME 0x01
#define HWCLOCK_OPT_UTC 0x02
#define HWCLOCK_OPT_SHOW 0x04 // 等價 hwclock –r 顯示硬件的時間
#define HWCLOCK_OPT_HCTOSYS 0x08 // 等價 hwclock –s 硬件時間更新到系統時間
#define HWCLOCK_OPT_SYSTOHC 0x10 // 等價 hwclock –w 系統時間更新到硬件時間
#define HWCLOCK_OPT_SYSTZ 0x20
#define HWCLOCK_OPT_RTCFILE 0x40
if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) // 判斷是是否是 hwclock –l -u
utc = (opt & HWCLOCK_OPT_UTC);
if (opt & HWCLOCK_OPT_HCTOSYS) // 判斷是是否是 hwclock –s
to_sys_clock(&rtcname, utc);
else if (opt & HWCLOCK_OPT_SYSTOHC) // 判斷是是否是 hwclock –w
from_sys_clock(&rtcname, utc);
else
/* default HWCLOCK_OPT_SHOW */ // 默認是 hwclock –r
show_clock(&rtcname, utc);
hwclock –s ->to_sys_clock-> read_rtc(pp_rtcname, NULL, utc); // 讀rtc的時間
-> fd = rtc_xopen(pp_rtcname, O_RDONLY)
*default_rtc = "/dev/rtc";
rtc = open(*default_rtc, flags);
*default_rtc = "/dev/rtc0";
rtc = open(*default_rtc, flags);
*default_rtc = "/dev/misc/rtc";
// 會打開這幾個默認的文件
-> rtc_read_tm(&tm_time, fd);
-> xioctl(fd, RTC_RD_TIME, ptm);
// 讀系統的時間
-> settimeofday(&tv, &tz)) // 設置系統的時間
hwclock –w ->from_sys_clock(&rtcname, utc); -> rtc = rtc_xopen(pp_rtcname, O_WRONLY);
*default_rtc = "/dev/rtc";
rtc = open(*default_rtc, flags);
*default_rtc = "/dev/rtc0";
rtc = open(*default_rtc, flags);
*default_rtc = "/dev/misc/rtc";
// 會打開這幾個默認的文件
-> gettimeofday(&tv, NULL); // 獲得系統時間
-> xioctl(rtc, RTC_SET_TIME, &tm_time); // 設置系統時間
-> close(rtc) //
hwclock –r -> show_clock(const char **pp_rtcname, int utc)
-> time_t t = read_rtc(pp_rtcname, &sys_tv, utc);
->*default_rtc = "/dev/rtc";
rtc = open(*default_rtc, flags);
*default_rtc = "/dev/rtc0";
rtc = open(*default_rtc, flags);
*default_rtc = "/dev/misc/rtc";
// 會打開這幾個默認的文件
-> fd = rtc_xopen(pp_rtcname, O_RDONLY);
-> rtc_read_tm(&tm_time, fd);
-> xioctl(fd, RTC_RD_TIME, ptm);
以上可以知道(dao), 讀時間使(shi)用(yong)ioctl進(jin)行的(de),使(shi)用(yong)兩個命令(ling)
RTC_RD_TIME // 讀時間
RTC_SET_TIME // 設置時(shi)間
第二部(bu)分: rtc驅動(dong)架構(gou)分析
rtc的驅動架構是基于(yu)platform機(ji)制實現的,platform_device是由設備(bei)樹(shu)生成
rtc的(de)設(she)備樹如下:
rtc@10070000
{
compatible = "samsung,s3c6410-rtc";
reg = < 0x10070000 0x100>;
interrupts = < 0 44 0>, <0 45 0>;
clocks = < &clock 346>;
clock-names = "rtc";
status = "disabled";
};
這個(ge)設備樹會生成platform_device
驅動(dong)在driver /rtc/rtc-s3c.c 文件中定(ding)義
static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = s3c_rtc_remove,
.id_table = s3c_rtc_driver_ids,
.driver = {
.name = "s3c-rtc",
.owner = THIS_MODULE,
.pm = &s3c_rtc_pm_ops,
.of_match_table = of_match_ptr(s3c_rtc_dt_match),
},
};
module_platform_driver(s3c_rtc_driver);
實(shi)現了(le)platform_driver s3c_rtc_driver的注(zhu)冊
設備樹中的compatible = "samsung,s3c6410-rtc";和驅(qu)動中的 .compatible = "samsung,s3c6410-rtc",名稱一直時(shi),會執行(xing)驅(qu)動的probe函數-> s3c_rtc_probe
在probe函數中注冊(ce)一(yi)個(ge)字符設備驅(qu)動
rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
-> rtc = rtc_device_register(name, dev, ops, owner);
-> of_id = of_alias_get_id(dev->of_node, "rtc"); // 注冊一個rtc的類
-> rtc_dev_prepare(rtc);
-> cdev_init(&rtc->char_dev, &rtc_dev_fops);
-> rtc_dev_add_device(rtc);
-> if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
-> rtc_sysfs_add_device(rtc); // 等價于 mknod /dev/rtc c 254 0
-> s3c_rtc_gettime(NULL, &rtc_tm); // 獲(huo)得系統的時間
以上是一個(ge)字符(fu)設備的創建。
注冊了一個cdev結構體(ti)(ti)和file_operations結構體(ti)(ti)rtc_dev_fops
rtc_dev_fops實現如下:
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl = rtc_dev_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
};
由以上(shang)可知 : 應用程序調用ioctl 驅動也調用ioctl
hwclock –w -> xioctl(fd, RTC_RD_TIME, ptm); -> rtc_dev_ioctl(命令) (用戶空間) (內核空間)
-> case RTC_RD_TIME:rtc_read_time(rtc, &tm);
if (copy_to_user(uarg, &tm, sizeof(tm)))
由以上可知 : 應用程序(xu)調用ioctl 驅動(dong)也(ye)調用ioctl
hwclock –s -> xioctl(fd, RTC_SET_TIME, ptm); -> rtc_dev_ioctl(命令) (用戶空間) (內核空間)
-> case RTC_SET_TIME:
if (copy_from_user(&tm, uarg, sizeof(tm)))
return rtc_set_time(rtc, &tm);
hwclock –r -> xioctl(fd, RTC_RD_TIME , ptm); -> rtc_dev_ioctl(命令) (用戶空間) (內核空間)
-> case RTC_RD_TIME: rtc_read_time(rtc, &tm);
if (copy_to_user(uarg, &tm, sizeof(tm)))

