1d8da8665SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0
2a12ab9e1SAlexandre Belloni /*
3d8da8665SAlexandre Belloni * Real Time Clock Driver Test Program
4a12ab9e1SAlexandre Belloni *
5d8da8665SAlexandre Belloni * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com>
6a12ab9e1SAlexandre Belloni */
7a12ab9e1SAlexandre Belloni
8d8da8665SAlexandre Belloni #include <errno.h>
9d8da8665SAlexandre Belloni #include <fcntl.h>
10a12ab9e1SAlexandre Belloni #include <linux/rtc.h>
11d8da8665SAlexandre Belloni #include <stdio.h>
12d8da8665SAlexandre Belloni #include <stdlib.h>
13a12ab9e1SAlexandre Belloni #include <sys/ioctl.h>
14a12ab9e1SAlexandre Belloni #include <sys/time.h>
15a12ab9e1SAlexandre Belloni #include <sys/types.h>
16d8da8665SAlexandre Belloni #include <time.h>
17a12ab9e1SAlexandre Belloni #include <unistd.h>
18a12ab9e1SAlexandre Belloni
19d8da8665SAlexandre Belloni #include "../kselftest_harness.h"
20a12ab9e1SAlexandre Belloni
21d8da8665SAlexandre Belloni #define NUM_UIE 3
22d8da8665SAlexandre Belloni #define ALARM_DELTA 3
232aaa36e9SMateusz Jończyk #define READ_LOOP_DURATION_SEC 30
242aaa36e9SMateusz Jończyk #define READ_LOOP_SLEEP_MS 11
25a12ab9e1SAlexandre Belloni
26d8da8665SAlexandre Belloni static char *rtc_file = "/dev/rtc0";
27d8da8665SAlexandre Belloni
FIXTURE(rtc)28d8da8665SAlexandre Belloni FIXTURE(rtc) {
29d8da8665SAlexandre Belloni int fd;
30a12ab9e1SAlexandre Belloni };
31a12ab9e1SAlexandre Belloni
FIXTURE_SETUP(rtc)32d8da8665SAlexandre Belloni FIXTURE_SETUP(rtc) {
33d8da8665SAlexandre Belloni self->fd = open(rtc_file, O_RDONLY);
34d8da8665SAlexandre Belloni }
35a12ab9e1SAlexandre Belloni
FIXTURE_TEARDOWN(rtc)36d8da8665SAlexandre Belloni FIXTURE_TEARDOWN(rtc) {
37d8da8665SAlexandre Belloni close(self->fd);
38d8da8665SAlexandre Belloni }
39d8da8665SAlexandre Belloni
TEST_F(rtc,date_read)40d8da8665SAlexandre Belloni TEST_F(rtc, date_read) {
41d8da8665SAlexandre Belloni int rc;
42d8da8665SAlexandre Belloni struct rtc_time rtc_tm;
43d8da8665SAlexandre Belloni
44*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
45*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
46*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
47*35eee9a3SAlexandre Belloni
48d8da8665SAlexandre Belloni /* Read the RTC time/date */
49d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
50d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
51d8da8665SAlexandre Belloni
52d8da8665SAlexandre Belloni TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
53d8da8665SAlexandre Belloni rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
54d8da8665SAlexandre Belloni rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
55d8da8665SAlexandre Belloni }
56d8da8665SAlexandre Belloni
rtc_time_to_timestamp(struct rtc_time * rtc_time)572aaa36e9SMateusz Jończyk static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
582aaa36e9SMateusz Jończyk {
592aaa36e9SMateusz Jończyk struct tm tm_time = {
602aaa36e9SMateusz Jończyk .tm_sec = rtc_time->tm_sec,
612aaa36e9SMateusz Jończyk .tm_min = rtc_time->tm_min,
622aaa36e9SMateusz Jończyk .tm_hour = rtc_time->tm_hour,
632aaa36e9SMateusz Jończyk .tm_mday = rtc_time->tm_mday,
642aaa36e9SMateusz Jończyk .tm_mon = rtc_time->tm_mon,
652aaa36e9SMateusz Jończyk .tm_year = rtc_time->tm_year,
662aaa36e9SMateusz Jończyk };
672aaa36e9SMateusz Jończyk
682aaa36e9SMateusz Jończyk return mktime(&tm_time);
692aaa36e9SMateusz Jończyk }
702aaa36e9SMateusz Jończyk
nanosleep_with_retries(long ns)712aaa36e9SMateusz Jończyk static void nanosleep_with_retries(long ns)
722aaa36e9SMateusz Jończyk {
732aaa36e9SMateusz Jończyk struct timespec req = {
742aaa36e9SMateusz Jończyk .tv_sec = 0,
752aaa36e9SMateusz Jończyk .tv_nsec = ns,
762aaa36e9SMateusz Jończyk };
772aaa36e9SMateusz Jończyk struct timespec rem;
782aaa36e9SMateusz Jończyk
792aaa36e9SMateusz Jończyk while (nanosleep(&req, &rem) != 0) {
802aaa36e9SMateusz Jończyk req.tv_sec = rem.tv_sec;
812aaa36e9SMateusz Jończyk req.tv_nsec = rem.tv_nsec;
822aaa36e9SMateusz Jończyk }
832aaa36e9SMateusz Jończyk }
842aaa36e9SMateusz Jończyk
852aaa36e9SMateusz Jończyk TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
862aaa36e9SMateusz Jończyk int rc;
872aaa36e9SMateusz Jończyk long iter_count = 0;
882aaa36e9SMateusz Jończyk struct rtc_time rtc_tm;
892aaa36e9SMateusz Jończyk time_t start_rtc_read, prev_rtc_read;
902aaa36e9SMateusz Jończyk
91*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
92*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
93*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
94*35eee9a3SAlexandre Belloni
952aaa36e9SMateusz Jończyk TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
962aaa36e9SMateusz Jończyk READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
972aaa36e9SMateusz Jończyk
982aaa36e9SMateusz Jończyk rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
992aaa36e9SMateusz Jończyk ASSERT_NE(-1, rc);
1002aaa36e9SMateusz Jończyk start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
1012aaa36e9SMateusz Jończyk prev_rtc_read = start_rtc_read;
1022aaa36e9SMateusz Jończyk
1032aaa36e9SMateusz Jończyk do {
1042aaa36e9SMateusz Jończyk time_t rtc_read;
1052aaa36e9SMateusz Jończyk
1062aaa36e9SMateusz Jończyk rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
1072aaa36e9SMateusz Jończyk ASSERT_NE(-1, rc);
1082aaa36e9SMateusz Jończyk
1092aaa36e9SMateusz Jończyk rtc_read = rtc_time_to_timestamp(&rtc_tm);
1102aaa36e9SMateusz Jończyk /* Time should not go backwards */
1112aaa36e9SMateusz Jończyk ASSERT_LE(prev_rtc_read, rtc_read);
1122aaa36e9SMateusz Jończyk /* Time should not increase more then 1s at a time */
1132aaa36e9SMateusz Jończyk ASSERT_GE(prev_rtc_read + 1, rtc_read);
1142aaa36e9SMateusz Jończyk
1152aaa36e9SMateusz Jończyk /* Sleep 11ms to avoid killing / overheating the RTC */
1162aaa36e9SMateusz Jończyk nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
1172aaa36e9SMateusz Jończyk
1182aaa36e9SMateusz Jończyk prev_rtc_read = rtc_read;
1192aaa36e9SMateusz Jończyk iter_count++;
1202aaa36e9SMateusz Jończyk } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
1212aaa36e9SMateusz Jończyk
1222aaa36e9SMateusz Jończyk TH_LOG("Performed %ld RTC time reads.", iter_count);
1232aaa36e9SMateusz Jończyk }
1242aaa36e9SMateusz Jończyk
125eff82a26SAlexandre Belloni TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
126d8da8665SAlexandre Belloni int i, rc, irq = 0;
127d8da8665SAlexandre Belloni unsigned long data;
128d8da8665SAlexandre Belloni
129*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
130*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
131*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
132*35eee9a3SAlexandre Belloni
133d8da8665SAlexandre Belloni /* Turn on update interrupts */
134d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_ON, 0);
135d8da8665SAlexandre Belloni if (rc == -1) {
136d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno);
137d8da8665SAlexandre Belloni TH_LOG("skip update IRQs not supported.");
138d8da8665SAlexandre Belloni return;
139d8da8665SAlexandre Belloni }
140d8da8665SAlexandre Belloni
141d8da8665SAlexandre Belloni for (i = 0; i < NUM_UIE; i++) {
142d8da8665SAlexandre Belloni /* This read will block */
143d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(data));
144d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
145d8da8665SAlexandre Belloni irq++;
146d8da8665SAlexandre Belloni }
147d8da8665SAlexandre Belloni
148d8da8665SAlexandre Belloni EXPECT_EQ(NUM_UIE, irq);
149d8da8665SAlexandre Belloni
150d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_OFF, 0);
151d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
152d8da8665SAlexandre Belloni }
153d8da8665SAlexandre Belloni
TEST_F(rtc,uie_select)154d8da8665SAlexandre Belloni TEST_F(rtc, uie_select) {
155d8da8665SAlexandre Belloni int i, rc, irq = 0;
156d8da8665SAlexandre Belloni unsigned long data;
157d8da8665SAlexandre Belloni
158*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
159*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
160*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
161*35eee9a3SAlexandre Belloni
162d8da8665SAlexandre Belloni /* Turn on update interrupts */
163d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_ON, 0);
164d8da8665SAlexandre Belloni if (rc == -1) {
165d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno);
166d8da8665SAlexandre Belloni TH_LOG("skip update IRQs not supported.");
167d8da8665SAlexandre Belloni return;
168d8da8665SAlexandre Belloni }
169d8da8665SAlexandre Belloni
170d8da8665SAlexandre Belloni for (i = 0; i < NUM_UIE; i++) {
171d8da8665SAlexandre Belloni struct timeval tv = { .tv_sec = 2 };
172d8da8665SAlexandre Belloni fd_set readfds;
173d8da8665SAlexandre Belloni
174d8da8665SAlexandre Belloni FD_ZERO(&readfds);
175d8da8665SAlexandre Belloni FD_SET(self->fd, &readfds);
176d8da8665SAlexandre Belloni /* The select will wait until an RTC interrupt happens. */
177d8da8665SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
178d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
179d8da8665SAlexandre Belloni ASSERT_NE(0, rc);
180d8da8665SAlexandre Belloni
181d8da8665SAlexandre Belloni /* This read won't block */
182d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long));
183d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
184d8da8665SAlexandre Belloni irq++;
185d8da8665SAlexandre Belloni }
186d8da8665SAlexandre Belloni
187d8da8665SAlexandre Belloni EXPECT_EQ(NUM_UIE, irq);
188d8da8665SAlexandre Belloni
189d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_OFF, 0);
190d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
191d8da8665SAlexandre Belloni }
192d8da8665SAlexandre Belloni
TEST_F(rtc,alarm_alm_set)193d8da8665SAlexandre Belloni TEST_F(rtc, alarm_alm_set) {
194d8da8665SAlexandre Belloni struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
195d8da8665SAlexandre Belloni unsigned long data;
196d8da8665SAlexandre Belloni struct rtc_time tm;
197d8da8665SAlexandre Belloni fd_set readfds;
198d8da8665SAlexandre Belloni time_t secs, new;
199d8da8665SAlexandre Belloni int rc;
200d8da8665SAlexandre Belloni
201*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
202*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
203*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
204*35eee9a3SAlexandre Belloni
205d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm);
206d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
207d8da8665SAlexandre Belloni
208d8da8665SAlexandre Belloni secs = timegm((struct tm *)&tm) + ALARM_DELTA;
209d8da8665SAlexandre Belloni gmtime_r(&secs, (struct tm *)&tm);
210d8da8665SAlexandre Belloni
211d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_SET, &tm);
212d8da8665SAlexandre Belloni if (rc == -1) {
213d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno);
214d8da8665SAlexandre Belloni TH_LOG("skip alarms are not supported.");
215d8da8665SAlexandre Belloni return;
216d8da8665SAlexandre Belloni }
217d8da8665SAlexandre Belloni
218d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_READ, &tm);
219d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
220d8da8665SAlexandre Belloni
221d8da8665SAlexandre Belloni TH_LOG("Alarm time now set to %02d:%02d:%02d.",
222d8da8665SAlexandre Belloni tm.tm_hour, tm.tm_min, tm.tm_sec);
223d8da8665SAlexandre Belloni
224d8da8665SAlexandre Belloni /* Enable alarm interrupts */
225d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_ON, 0);
226d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
227d8da8665SAlexandre Belloni
228d8da8665SAlexandre Belloni FD_ZERO(&readfds);
229d8da8665SAlexandre Belloni FD_SET(self->fd, &readfds);
230d8da8665SAlexandre Belloni
231d8da8665SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
232d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
233fdac9448SAlexandre Belloni ASSERT_NE(0, rc);
234d8da8665SAlexandre Belloni
235d8da8665SAlexandre Belloni /* Disable alarm interrupts */
236d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_OFF, 0);
237d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
238d8da8665SAlexandre Belloni
239d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long));
240d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
241d8da8665SAlexandre Belloni TH_LOG("data: %lx", data);
242d8da8665SAlexandre Belloni
243d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm);
244d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
245d8da8665SAlexandre Belloni
246d8da8665SAlexandre Belloni new = timegm((struct tm *)&tm);
247d8da8665SAlexandre Belloni ASSERT_EQ(new, secs);
248d8da8665SAlexandre Belloni }
249d8da8665SAlexandre Belloni
TEST_F(rtc,alarm_wkalm_set)250d8da8665SAlexandre Belloni TEST_F(rtc, alarm_wkalm_set) {
251d8da8665SAlexandre Belloni struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
252d8da8665SAlexandre Belloni struct rtc_wkalrm alarm = { 0 };
253d8da8665SAlexandre Belloni struct rtc_time tm;
254d8da8665SAlexandre Belloni unsigned long data;
255d8da8665SAlexandre Belloni fd_set readfds;
256d8da8665SAlexandre Belloni time_t secs, new;
257d8da8665SAlexandre Belloni int rc;
258d8da8665SAlexandre Belloni
259*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
260*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
261*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
262*35eee9a3SAlexandre Belloni
263d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
264d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
265d8da8665SAlexandre Belloni
266d8da8665SAlexandre Belloni secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
267d8da8665SAlexandre Belloni gmtime_r(&secs, (struct tm *)&alarm.time);
268d8da8665SAlexandre Belloni
269d8da8665SAlexandre Belloni alarm.enabled = 1;
270d8da8665SAlexandre Belloni
271d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
272d8da8665SAlexandre Belloni if (rc == -1) {
273d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno);
274d8da8665SAlexandre Belloni TH_LOG("skip alarms are not supported.");
275d8da8665SAlexandre Belloni return;
276d8da8665SAlexandre Belloni }
277d8da8665SAlexandre Belloni
278d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
279d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
280d8da8665SAlexandre Belloni
281d8da8665SAlexandre Belloni TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
282d8da8665SAlexandre Belloni alarm.time.tm_mday, alarm.time.tm_mon + 1,
283d8da8665SAlexandre Belloni alarm.time.tm_year + 1900, alarm.time.tm_hour,
284d8da8665SAlexandre Belloni alarm.time.tm_min, alarm.time.tm_sec);
285d8da8665SAlexandre Belloni
286d8da8665SAlexandre Belloni FD_ZERO(&readfds);
287d8da8665SAlexandre Belloni FD_SET(self->fd, &readfds);
288d8da8665SAlexandre Belloni
289d8da8665SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
290d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
291fdac9448SAlexandre Belloni ASSERT_NE(0, rc);
292d8da8665SAlexandre Belloni
293d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long));
294d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
295d8da8665SAlexandre Belloni
296d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm);
297d8da8665SAlexandre Belloni ASSERT_NE(-1, rc);
298d8da8665SAlexandre Belloni
299d8da8665SAlexandre Belloni new = timegm((struct tm *)&tm);
300d8da8665SAlexandre Belloni ASSERT_EQ(new, secs);
301d8da8665SAlexandre Belloni }
302d8da8665SAlexandre Belloni
303eff82a26SAlexandre Belloni TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
3047b302772SAlexandre Belloni struct timeval tv = { .tv_sec = 62 };
3057b302772SAlexandre Belloni unsigned long data;
3067b302772SAlexandre Belloni struct rtc_time tm;
3077b302772SAlexandre Belloni fd_set readfds;
3087b302772SAlexandre Belloni time_t secs, new;
3097b302772SAlexandre Belloni int rc;
3107b302772SAlexandre Belloni
311*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
312*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
313*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
314*35eee9a3SAlexandre Belloni
3157b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm);
3167b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3177b302772SAlexandre Belloni
3187b302772SAlexandre Belloni secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
3197b302772SAlexandre Belloni gmtime_r(&secs, (struct tm *)&tm);
3207b302772SAlexandre Belloni
3217b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_SET, &tm);
3227b302772SAlexandre Belloni if (rc == -1) {
3237b302772SAlexandre Belloni ASSERT_EQ(EINVAL, errno);
3247b302772SAlexandre Belloni TH_LOG("skip alarms are not supported.");
3257b302772SAlexandre Belloni return;
3267b302772SAlexandre Belloni }
3277b302772SAlexandre Belloni
3287b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_READ, &tm);
3297b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3307b302772SAlexandre Belloni
3317b302772SAlexandre Belloni TH_LOG("Alarm time now set to %02d:%02d:%02d.",
3327b302772SAlexandre Belloni tm.tm_hour, tm.tm_min, tm.tm_sec);
3337b302772SAlexandre Belloni
3347b302772SAlexandre Belloni /* Enable alarm interrupts */
3357b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_ON, 0);
3367b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3377b302772SAlexandre Belloni
3387b302772SAlexandre Belloni FD_ZERO(&readfds);
3397b302772SAlexandre Belloni FD_SET(self->fd, &readfds);
3407b302772SAlexandre Belloni
3417b302772SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
3427b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3437b302772SAlexandre Belloni ASSERT_NE(0, rc);
3447b302772SAlexandre Belloni
3457b302772SAlexandre Belloni /* Disable alarm interrupts */
3467b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_OFF, 0);
3477b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3487b302772SAlexandre Belloni
3497b302772SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long));
3507b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3517b302772SAlexandre Belloni TH_LOG("data: %lx", data);
3527b302772SAlexandre Belloni
3537b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm);
3547b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3557b302772SAlexandre Belloni
3567b302772SAlexandre Belloni new = timegm((struct tm *)&tm);
3577b302772SAlexandre Belloni ASSERT_EQ(new, secs);
3587b302772SAlexandre Belloni }
3597b302772SAlexandre Belloni
360eff82a26SAlexandre Belloni TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
3617b302772SAlexandre Belloni struct timeval tv = { .tv_sec = 62 };
3627b302772SAlexandre Belloni struct rtc_wkalrm alarm = { 0 };
3637b302772SAlexandre Belloni struct rtc_time tm;
3647b302772SAlexandre Belloni unsigned long data;
3657b302772SAlexandre Belloni fd_set readfds;
3667b302772SAlexandre Belloni time_t secs, new;
3677b302772SAlexandre Belloni int rc;
3687b302772SAlexandre Belloni
369*35eee9a3SAlexandre Belloni if (self->fd == -1 && errno == ENOENT)
370*35eee9a3SAlexandre Belloni SKIP(return, "Skipping test since %s does not exist", rtc_file);
371*35eee9a3SAlexandre Belloni ASSERT_NE(-1, self->fd);
372*35eee9a3SAlexandre Belloni
3737b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
3747b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3757b302772SAlexandre Belloni
3767b302772SAlexandre Belloni secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
3777b302772SAlexandre Belloni gmtime_r(&secs, (struct tm *)&alarm.time);
3787b302772SAlexandre Belloni
3797b302772SAlexandre Belloni alarm.enabled = 1;
3807b302772SAlexandre Belloni
3817b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
3827b302772SAlexandre Belloni if (rc == -1) {
3837b302772SAlexandre Belloni ASSERT_EQ(EINVAL, errno);
3847b302772SAlexandre Belloni TH_LOG("skip alarms are not supported.");
3857b302772SAlexandre Belloni return;
3867b302772SAlexandre Belloni }
3877b302772SAlexandre Belloni
3887b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
3897b302772SAlexandre Belloni ASSERT_NE(-1, rc);
3907b302772SAlexandre Belloni
3917b302772SAlexandre Belloni TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
3927b302772SAlexandre Belloni alarm.time.tm_mday, alarm.time.tm_mon + 1,
3937b302772SAlexandre Belloni alarm.time.tm_year + 1900, alarm.time.tm_hour,
3947b302772SAlexandre Belloni alarm.time.tm_min, alarm.time.tm_sec);
3957b302772SAlexandre Belloni
3967b302772SAlexandre Belloni FD_ZERO(&readfds);
3977b302772SAlexandre Belloni FD_SET(self->fd, &readfds);
3987b302772SAlexandre Belloni
3997b302772SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
4007b302772SAlexandre Belloni ASSERT_NE(-1, rc);
4017b302772SAlexandre Belloni ASSERT_NE(0, rc);
4027b302772SAlexandre Belloni
4037b302772SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long));
4047b302772SAlexandre Belloni ASSERT_NE(-1, rc);
4057b302772SAlexandre Belloni
4067b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm);
4077b302772SAlexandre Belloni ASSERT_NE(-1, rc);
4087b302772SAlexandre Belloni
4097b302772SAlexandre Belloni new = timegm((struct tm *)&tm);
4107b302772SAlexandre Belloni ASSERT_EQ(new, secs);
4117b302772SAlexandre Belloni }
4127b302772SAlexandre Belloni
413d8da8665SAlexandre Belloni static void __attribute__((constructor))
__constructor_order_last(void)414d8da8665SAlexandre Belloni __constructor_order_last(void)
415d8da8665SAlexandre Belloni {
416d8da8665SAlexandre Belloni if (!__constructor_order)
417d8da8665SAlexandre Belloni __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
418a12ab9e1SAlexandre Belloni }
419a12ab9e1SAlexandre Belloni
main(int argc,char ** argv)420a12ab9e1SAlexandre Belloni int main(int argc, char **argv)
421a12ab9e1SAlexandre Belloni {
422a12ab9e1SAlexandre Belloni switch (argc) {
423a12ab9e1SAlexandre Belloni case 2:
424d8da8665SAlexandre Belloni rtc_file = argv[1];
425a12ab9e1SAlexandre Belloni /* FALLTHROUGH */
426a12ab9e1SAlexandre Belloni case 1:
427a12ab9e1SAlexandre Belloni break;
428a12ab9e1SAlexandre Belloni default:
429d8da8665SAlexandre Belloni fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
430a12ab9e1SAlexandre Belloni return 1;
431a12ab9e1SAlexandre Belloni }
432a12ab9e1SAlexandre Belloni
433d8da8665SAlexandre Belloni return test_harness_run(argc, argv);
434a12ab9e1SAlexandre Belloni }
435