Skip to content

Commit 4e7ed84

Browse files
committed
Add userspace programs for /dev/rtc?
rtc_alarm.c: The newly modified Linux configuration enables the procfs interface for the /dev/rtc? real-time clock device. This example demonstrates how to interact with the RTC device step by step. The program: 1. Opens the /dev/rtc? device. 2. Reads and displays its current status via the procfs interface. 3. Sets an alarm to trigger 5 seconds later. 4. Enables the alarm interrupt. 5. Reads the status again. 6. Waits for the alarm to trigger. 7. Finally reads the status once more and disables the alarm interrupt. During this process, will observe the alarm_IRQ field transition from no -> yes -> no, indicating that the RTC interrupt has been successfully asserted and then handled by the emulated real time clock. rtc_settime.c: A simple user-space tool to test the RTC_SET_TIME ioctl on /dev/rtc?. It sets the RTC to the current UTC system time by default or to a custom year provided via command-line arguments. This helps verify that the real time clock driver correctly handles time updates. The buildroot.config is also modified to enable them by default. The example packages are stored in the tests/system/br_pkgs/ .
1 parent 0ae1bb2 commit 4e7ed84

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed

assets/system/configs/buildroot.config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ BR2_PACKAGE_COREMARK=y
4747
BR2_PACKAGE_DHRYSTONE=y
4848
BR2_PACKAGE_UTIL_LINUX=y
4949
BR2_PACKAGE_UTIL_LINUX_HWCLOCK=y
50+
51+
BR2_PACKAGE_RTC_ALARM=y
52+
BR2_PACKAGE_RTC_SETTIME=y
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include <errno.h>
2+
#include <fcntl.h>
3+
#include <linux/rtc.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <sys/ioctl.h>
8+
#include <unistd.h>
9+
10+
#define PROC_RTC_PATH "/proc/driver/rtc"
11+
12+
/* Helper function to dump /proc/driver/rtc */
13+
void read_proc_rtc(const char *msg)
14+
{
15+
FILE *fp = fopen(PROC_RTC_PATH, "r");
16+
if (!fp) {
17+
perror("Failed to open /proc/driver/rtc");
18+
return;
19+
}
20+
21+
printf("\n=== %s ===\n", msg);
22+
char line[256];
23+
while (fgets(line, sizeof(line), fp)) {
24+
printf("%s", line);
25+
}
26+
printf("===========================\n\n");
27+
28+
fclose(fp);
29+
}
30+
31+
int main()
32+
{
33+
int fd;
34+
struct rtc_time rtc_tm;
35+
unsigned long data;
36+
37+
printf("Opening /dev/rtc0...\n");
38+
fd = open("/dev/rtc0", O_RDONLY);
39+
if (fd == -1) {
40+
perror("Failed to open /dev/rtc0");
41+
return 1;
42+
}
43+
44+
/* Step 1. Read /proc/driver/rtc before setting alarm */
45+
read_proc_rtc("Initial /proc/driver/rtc");
46+
47+
/* Step 2. Read current RTC time via ioctl */
48+
if (ioctl(fd, RTC_RD_TIME, &rtc_tm) == -1) {
49+
perror("RTC_RD_TIME ioctl failed");
50+
close(fd);
51+
return 1;
52+
}
53+
54+
printf("Current RTC time: %04d-%02d-%02d %02d:%02d:%02d (UTC)\n",
55+
rtc_tm.tm_year + 1900, rtc_tm.tm_mon + 1, rtc_tm.tm_mday,
56+
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
57+
58+
/* Step 3. Set alarm 5 seconds from now */
59+
int delay = 5;
60+
rtc_tm.tm_sec += delay;
61+
if (rtc_tm.tm_sec >= 60) {
62+
rtc_tm.tm_sec -= 60;
63+
rtc_tm.tm_min++;
64+
if (rtc_tm.tm_min >= 60) {
65+
rtc_tm.tm_min = 0;
66+
rtc_tm.tm_hour = (rtc_tm.tm_hour + 1) % 24;
67+
}
68+
}
69+
70+
printf("Setting alarm for %d seconds later...\n", delay);
71+
if (ioctl(fd, RTC_ALM_SET, &rtc_tm) == -1) {
72+
perror("RTC_ALM_SET ioctl failed");
73+
close(fd);
74+
return 1;
75+
}
76+
77+
/* Step 4. Enable alarm interrupt */
78+
if (ioctl(fd, RTC_AIE_ON, 0) == -1) {
79+
perror("RTC_AIE_ON ioctl failed");
80+
close(fd);
81+
return 1;
82+
}
83+
84+
/* Step 5. Read /proc/driver/rtc right after enabling alarm */
85+
read_proc_rtc("After enabling alarm");
86+
87+
printf("Alarm enabled. Waiting for it to fire...\n");
88+
89+
/* Step 6. Block until the alarm interrupt occurs */
90+
if (read(fd, &data, sizeof(unsigned long)) == -1) {
91+
perror("read() failed");
92+
close(fd);
93+
return 1;
94+
}
95+
96+
printf(">>> Alarm Fired! <<<\n");
97+
98+
/* Step 7. Read /proc/driver/rtc after alarm fired */
99+
read_proc_rtc("After alarm fired");
100+
101+
/* Step 8. Disable the alarm interrupt */
102+
if (ioctl(fd, RTC_AIE_OFF, 0) == -1) {
103+
perror("RTC_AIE_OFF ioctl failed");
104+
close(fd);
105+
return 1;
106+
}
107+
108+
close(fd);
109+
return 0;
110+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#include <errno.h>
2+
#include <fcntl.h>
3+
#include <linux/rtc.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <sys/ioctl.h>
8+
#include <time.h>
9+
#include <unistd.h>
10+
11+
int main(int argc, char *argv[])
12+
{
13+
int fd;
14+
struct rtc_time new_time;
15+
int year = 0;
16+
17+
/* TODO: support month and date */
18+
/* Handle CLI argument */
19+
if (argc == 2) {
20+
year = atoi(argv[1]);
21+
} else if (argc > 2) {
22+
fprintf(stderr, "Usage: %s [year]\n", argv[0]);
23+
fprintf(stderr, "Example: %s 1972\n", argv[0]);
24+
return 1;
25+
}
26+
27+
printf("Opening /dev/rtc0...\n");
28+
fd = open("/dev/rtc0", O_RDWR);
29+
if (fd == -1) {
30+
perror("Failed to open /dev/rtc0");
31+
return 1;
32+
}
33+
34+
if (year > 0) {
35+
/* Manually set RTC to <year>-01-01 00:00:00 */
36+
new_time.tm_sec = 0;
37+
new_time.tm_min = 0;
38+
new_time.tm_hour = 0;
39+
new_time.tm_mday = 1;
40+
new_time.tm_mon = 0; /* January = 0 */
41+
new_time.tm_year = year - 1900; /* tm_year is years since 1900 */
42+
new_time.tm_wday = 0;
43+
new_time.tm_yday = 0;
44+
new_time.tm_isdst = 0;
45+
46+
printf("Setting RTC time to: %04d-01-01 00:00:00 (UTC)\n", year);
47+
} else {
48+
/* No year provided, set RTC to current UTC time */
49+
time_t now = time(NULL);
50+
struct tm *utc_tm = gmtime(&now);
51+
52+
new_time.tm_sec = utc_tm->tm_sec;
53+
new_time.tm_min = utc_tm->tm_min;
54+
new_time.tm_hour = utc_tm->tm_hour;
55+
new_time.tm_mday = utc_tm->tm_mday;
56+
new_time.tm_mon = utc_tm->tm_mon; /* 0-11 */
57+
new_time.tm_year = utc_tm->tm_year; /* years since 1900 */
58+
new_time.tm_wday = utc_tm->tm_wday;
59+
new_time.tm_yday = utc_tm->tm_yday;
60+
new_time.tm_isdst = 0;
61+
62+
printf(
63+
"Setting RTC time to current UTC: %04d-%02d-%02d %02d:%02d:%02d\n",
64+
new_time.tm_year + 1900, new_time.tm_mon + 1, new_time.tm_mday,
65+
new_time.tm_hour, new_time.tm_min, new_time.tm_sec);
66+
}
67+
68+
/* Trigger the goldfish_rtc_set_time kernel driver */
69+
if (ioctl(fd, RTC_SET_TIME, &new_time) == -1) {
70+
perror("RTC_SET_TIME ioctl failed");
71+
close(fd);
72+
return 1;
73+
}
74+
75+
printf("RTC time successfully updated!\n\n");
76+
close(fd);
77+
78+
/* Immediately read and print /proc/driver/rtc */
79+
printf("Reading /proc/driver/rtc to verify...\n\n");
80+
FILE *proc_file = fopen("/proc/driver/rtc", "r");
81+
if (!proc_file) {
82+
perror("Failed to open /proc/driver/rtc");
83+
return 1;
84+
}
85+
86+
char buffer[256];
87+
while (fgets(buffer, sizeof(buffer), proc_file)) {
88+
printf("%s", buffer);
89+
}
90+
91+
fclose(proc_file);
92+
return 0;
93+
}

0 commit comments

Comments
 (0)