1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker * Real Time Clock Driver Test Program
4*053f45beSAndroid Build Coastguard Worker *
5*053f45beSAndroid Build Coastguard Worker * Copyright (c) 2018 Alexandre Belloni <[email protected]>
6*053f45beSAndroid Build Coastguard Worker */
7*053f45beSAndroid Build Coastguard Worker
8*053f45beSAndroid Build Coastguard Worker #include <errno.h>
9*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
10*053f45beSAndroid Build Coastguard Worker #include <linux/rtc.h>
11*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
12*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
13*053f45beSAndroid Build Coastguard Worker #include <sys/ioctl.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/time.h>
15*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
16*053f45beSAndroid Build Coastguard Worker #include <time.h>
17*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
18*053f45beSAndroid Build Coastguard Worker
19*053f45beSAndroid Build Coastguard Worker #include "../kselftest_harness.h"
20*053f45beSAndroid Build Coastguard Worker
21*053f45beSAndroid Build Coastguard Worker #define NUM_UIE 3
22*053f45beSAndroid Build Coastguard Worker #define ALARM_DELTA 3
23*053f45beSAndroid Build Coastguard Worker #define READ_LOOP_DURATION_SEC 30
24*053f45beSAndroid Build Coastguard Worker #define READ_LOOP_SLEEP_MS 11
25*053f45beSAndroid Build Coastguard Worker
26*053f45beSAndroid Build Coastguard Worker static char *rtc_file = "/dev/rtc0";
27*053f45beSAndroid Build Coastguard Worker
FIXTURE(rtc)28*053f45beSAndroid Build Coastguard Worker FIXTURE(rtc) {
29*053f45beSAndroid Build Coastguard Worker int fd;
30*053f45beSAndroid Build Coastguard Worker };
31*053f45beSAndroid Build Coastguard Worker
FIXTURE_SETUP(rtc)32*053f45beSAndroid Build Coastguard Worker FIXTURE_SETUP(rtc) {
33*053f45beSAndroid Build Coastguard Worker self->fd = open(rtc_file, O_RDONLY);
34*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, self->fd);
35*053f45beSAndroid Build Coastguard Worker }
36*053f45beSAndroid Build Coastguard Worker
FIXTURE_TEARDOWN(rtc)37*053f45beSAndroid Build Coastguard Worker FIXTURE_TEARDOWN(rtc) {
38*053f45beSAndroid Build Coastguard Worker close(self->fd);
39*053f45beSAndroid Build Coastguard Worker }
40*053f45beSAndroid Build Coastguard Worker
TEST_F(rtc,date_read)41*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, date_read) {
42*053f45beSAndroid Build Coastguard Worker int rc;
43*053f45beSAndroid Build Coastguard Worker struct rtc_time rtc_tm;
44*053f45beSAndroid Build Coastguard Worker
45*053f45beSAndroid Build Coastguard Worker /* Read the RTC time/date */
46*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
47*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
48*053f45beSAndroid Build Coastguard Worker
49*053f45beSAndroid Build Coastguard Worker TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
50*053f45beSAndroid Build Coastguard Worker rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
51*053f45beSAndroid Build Coastguard Worker rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
52*053f45beSAndroid Build Coastguard Worker }
53*053f45beSAndroid Build Coastguard Worker
rtc_time_to_timestamp(struct rtc_time * rtc_time)54*053f45beSAndroid Build Coastguard Worker static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
55*053f45beSAndroid Build Coastguard Worker {
56*053f45beSAndroid Build Coastguard Worker struct tm tm_time = {
57*053f45beSAndroid Build Coastguard Worker .tm_sec = rtc_time->tm_sec,
58*053f45beSAndroid Build Coastguard Worker .tm_min = rtc_time->tm_min,
59*053f45beSAndroid Build Coastguard Worker .tm_hour = rtc_time->tm_hour,
60*053f45beSAndroid Build Coastguard Worker .tm_mday = rtc_time->tm_mday,
61*053f45beSAndroid Build Coastguard Worker .tm_mon = rtc_time->tm_mon,
62*053f45beSAndroid Build Coastguard Worker .tm_year = rtc_time->tm_year,
63*053f45beSAndroid Build Coastguard Worker };
64*053f45beSAndroid Build Coastguard Worker
65*053f45beSAndroid Build Coastguard Worker return mktime(&tm_time);
66*053f45beSAndroid Build Coastguard Worker }
67*053f45beSAndroid Build Coastguard Worker
nanosleep_with_retries(long ns)68*053f45beSAndroid Build Coastguard Worker static void nanosleep_with_retries(long ns)
69*053f45beSAndroid Build Coastguard Worker {
70*053f45beSAndroid Build Coastguard Worker struct timespec req = {
71*053f45beSAndroid Build Coastguard Worker .tv_sec = 0,
72*053f45beSAndroid Build Coastguard Worker .tv_nsec = ns,
73*053f45beSAndroid Build Coastguard Worker };
74*053f45beSAndroid Build Coastguard Worker struct timespec rem;
75*053f45beSAndroid Build Coastguard Worker
76*053f45beSAndroid Build Coastguard Worker while (nanosleep(&req, &rem) != 0) {
77*053f45beSAndroid Build Coastguard Worker req.tv_sec = rem.tv_sec;
78*053f45beSAndroid Build Coastguard Worker req.tv_nsec = rem.tv_nsec;
79*053f45beSAndroid Build Coastguard Worker }
80*053f45beSAndroid Build Coastguard Worker }
81*053f45beSAndroid Build Coastguard Worker
82*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
83*053f45beSAndroid Build Coastguard Worker int rc;
84*053f45beSAndroid Build Coastguard Worker long iter_count = 0;
85*053f45beSAndroid Build Coastguard Worker struct rtc_time rtc_tm;
86*053f45beSAndroid Build Coastguard Worker time_t start_rtc_read, prev_rtc_read;
87*053f45beSAndroid Build Coastguard Worker
88*053f45beSAndroid Build Coastguard Worker TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
89*053f45beSAndroid Build Coastguard Worker READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
90*053f45beSAndroid Build Coastguard Worker
91*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
92*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
93*053f45beSAndroid Build Coastguard Worker start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
94*053f45beSAndroid Build Coastguard Worker prev_rtc_read = start_rtc_read;
95*053f45beSAndroid Build Coastguard Worker
96*053f45beSAndroid Build Coastguard Worker do {
97*053f45beSAndroid Build Coastguard Worker time_t rtc_read;
98*053f45beSAndroid Build Coastguard Worker
99*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
100*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
101*053f45beSAndroid Build Coastguard Worker
102*053f45beSAndroid Build Coastguard Worker rtc_read = rtc_time_to_timestamp(&rtc_tm);
103*053f45beSAndroid Build Coastguard Worker /* Time should not go backwards */
104*053f45beSAndroid Build Coastguard Worker ASSERT_LE(prev_rtc_read, rtc_read);
105*053f45beSAndroid Build Coastguard Worker /* Time should not increase more then 1s at a time */
106*053f45beSAndroid Build Coastguard Worker ASSERT_GE(prev_rtc_read + 1, rtc_read);
107*053f45beSAndroid Build Coastguard Worker
108*053f45beSAndroid Build Coastguard Worker /* Sleep 11ms to avoid killing / overheating the RTC */
109*053f45beSAndroid Build Coastguard Worker nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
110*053f45beSAndroid Build Coastguard Worker
111*053f45beSAndroid Build Coastguard Worker prev_rtc_read = rtc_read;
112*053f45beSAndroid Build Coastguard Worker iter_count++;
113*053f45beSAndroid Build Coastguard Worker } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
114*053f45beSAndroid Build Coastguard Worker
115*053f45beSAndroid Build Coastguard Worker TH_LOG("Performed %ld RTC time reads.", iter_count);
116*053f45beSAndroid Build Coastguard Worker }
117*053f45beSAndroid Build Coastguard Worker
118*053f45beSAndroid Build Coastguard Worker #ifndef __ANDROID__ // b/31578457
119*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
120*053f45beSAndroid Build Coastguard Worker int i, rc, irq = 0;
121*053f45beSAndroid Build Coastguard Worker unsigned long data;
122*053f45beSAndroid Build Coastguard Worker
123*053f45beSAndroid Build Coastguard Worker /* Turn on update interrupts */
124*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_UIE_ON, 0);
125*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
126*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(EINVAL, errno);
127*053f45beSAndroid Build Coastguard Worker TH_LOG("skip update IRQs not supported.");
128*053f45beSAndroid Build Coastguard Worker return;
129*053f45beSAndroid Build Coastguard Worker }
130*053f45beSAndroid Build Coastguard Worker
131*053f45beSAndroid Build Coastguard Worker for (i = 0; i < NUM_UIE; i++) {
132*053f45beSAndroid Build Coastguard Worker /* This read will block */
133*053f45beSAndroid Build Coastguard Worker rc = read(self->fd, &data, sizeof(data));
134*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
135*053f45beSAndroid Build Coastguard Worker irq++;
136*053f45beSAndroid Build Coastguard Worker }
137*053f45beSAndroid Build Coastguard Worker
138*053f45beSAndroid Build Coastguard Worker EXPECT_EQ(NUM_UIE, irq);
139*053f45beSAndroid Build Coastguard Worker
140*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_UIE_OFF, 0);
141*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
142*053f45beSAndroid Build Coastguard Worker }
143*053f45beSAndroid Build Coastguard Worker
TEST_F(rtc,uie_select)144*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, uie_select) {
145*053f45beSAndroid Build Coastguard Worker int i, rc, irq = 0;
146*053f45beSAndroid Build Coastguard Worker unsigned long data;
147*053f45beSAndroid Build Coastguard Worker
148*053f45beSAndroid Build Coastguard Worker /* Turn on update interrupts */
149*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_UIE_ON, 0);
150*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
151*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(EINVAL, errno);
152*053f45beSAndroid Build Coastguard Worker TH_LOG("skip update IRQs not supported.");
153*053f45beSAndroid Build Coastguard Worker return;
154*053f45beSAndroid Build Coastguard Worker }
155*053f45beSAndroid Build Coastguard Worker
156*053f45beSAndroid Build Coastguard Worker for (i = 0; i < NUM_UIE; i++) {
157*053f45beSAndroid Build Coastguard Worker struct timeval tv = { .tv_sec = 2 };
158*053f45beSAndroid Build Coastguard Worker fd_set readfds;
159*053f45beSAndroid Build Coastguard Worker
160*053f45beSAndroid Build Coastguard Worker FD_ZERO(&readfds);
161*053f45beSAndroid Build Coastguard Worker FD_SET(self->fd, &readfds);
162*053f45beSAndroid Build Coastguard Worker /* The select will wait until an RTC interrupt happens. */
163*053f45beSAndroid Build Coastguard Worker rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
164*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
165*053f45beSAndroid Build Coastguard Worker ASSERT_NE(0, rc);
166*053f45beSAndroid Build Coastguard Worker
167*053f45beSAndroid Build Coastguard Worker /* This read won't block */
168*053f45beSAndroid Build Coastguard Worker rc = read(self->fd, &data, sizeof(unsigned long));
169*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
170*053f45beSAndroid Build Coastguard Worker irq++;
171*053f45beSAndroid Build Coastguard Worker }
172*053f45beSAndroid Build Coastguard Worker
173*053f45beSAndroid Build Coastguard Worker EXPECT_EQ(NUM_UIE, irq);
174*053f45beSAndroid Build Coastguard Worker
175*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_UIE_OFF, 0);
176*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
177*053f45beSAndroid Build Coastguard Worker }
178*053f45beSAndroid Build Coastguard Worker
TEST_F(rtc,alarm_alm_set)179*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, alarm_alm_set) {
180*053f45beSAndroid Build Coastguard Worker struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
181*053f45beSAndroid Build Coastguard Worker unsigned long data;
182*053f45beSAndroid Build Coastguard Worker struct rtc_time tm;
183*053f45beSAndroid Build Coastguard Worker fd_set readfds;
184*053f45beSAndroid Build Coastguard Worker time_t secs, new;
185*053f45beSAndroid Build Coastguard Worker int rc;
186*053f45beSAndroid Build Coastguard Worker
187*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &tm);
188*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
189*053f45beSAndroid Build Coastguard Worker
190*053f45beSAndroid Build Coastguard Worker secs = timegm((struct tm *)&tm) + ALARM_DELTA;
191*053f45beSAndroid Build Coastguard Worker gmtime_r(&secs, (struct tm *)&tm);
192*053f45beSAndroid Build Coastguard Worker
193*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_ALM_SET, &tm);
194*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
195*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(EINVAL, errno);
196*053f45beSAndroid Build Coastguard Worker TH_LOG("skip alarms are not supported.");
197*053f45beSAndroid Build Coastguard Worker return;
198*053f45beSAndroid Build Coastguard Worker }
199*053f45beSAndroid Build Coastguard Worker
200*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_ALM_READ, &tm);
201*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
202*053f45beSAndroid Build Coastguard Worker
203*053f45beSAndroid Build Coastguard Worker TH_LOG("Alarm time now set to %02d:%02d:%02d.",
204*053f45beSAndroid Build Coastguard Worker tm.tm_hour, tm.tm_min, tm.tm_sec);
205*053f45beSAndroid Build Coastguard Worker
206*053f45beSAndroid Build Coastguard Worker /* Enable alarm interrupts */
207*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_AIE_ON, 0);
208*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
209*053f45beSAndroid Build Coastguard Worker
210*053f45beSAndroid Build Coastguard Worker FD_ZERO(&readfds);
211*053f45beSAndroid Build Coastguard Worker FD_SET(self->fd, &readfds);
212*053f45beSAndroid Build Coastguard Worker
213*053f45beSAndroid Build Coastguard Worker rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
214*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
215*053f45beSAndroid Build Coastguard Worker ASSERT_NE(0, rc);
216*053f45beSAndroid Build Coastguard Worker
217*053f45beSAndroid Build Coastguard Worker /* Disable alarm interrupts */
218*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_AIE_OFF, 0);
219*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
220*053f45beSAndroid Build Coastguard Worker
221*053f45beSAndroid Build Coastguard Worker rc = read(self->fd, &data, sizeof(unsigned long));
222*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
223*053f45beSAndroid Build Coastguard Worker TH_LOG("data: %lx", data);
224*053f45beSAndroid Build Coastguard Worker
225*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &tm);
226*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
227*053f45beSAndroid Build Coastguard Worker
228*053f45beSAndroid Build Coastguard Worker new = timegm((struct tm *)&tm);
229*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(new, secs);
230*053f45beSAndroid Build Coastguard Worker }
231*053f45beSAndroid Build Coastguard Worker
TEST_F(rtc,alarm_wkalm_set)232*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, alarm_wkalm_set) {
233*053f45beSAndroid Build Coastguard Worker struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
234*053f45beSAndroid Build Coastguard Worker struct rtc_wkalrm alarm = { 0 };
235*053f45beSAndroid Build Coastguard Worker struct rtc_time tm;
236*053f45beSAndroid Build Coastguard Worker unsigned long data;
237*053f45beSAndroid Build Coastguard Worker fd_set readfds;
238*053f45beSAndroid Build Coastguard Worker time_t secs, new;
239*053f45beSAndroid Build Coastguard Worker int rc;
240*053f45beSAndroid Build Coastguard Worker
241*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
242*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
243*053f45beSAndroid Build Coastguard Worker
244*053f45beSAndroid Build Coastguard Worker secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
245*053f45beSAndroid Build Coastguard Worker gmtime_r(&secs, (struct tm *)&alarm.time);
246*053f45beSAndroid Build Coastguard Worker
247*053f45beSAndroid Build Coastguard Worker alarm.enabled = 1;
248*053f45beSAndroid Build Coastguard Worker
249*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
250*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
251*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(EINVAL, errno);
252*053f45beSAndroid Build Coastguard Worker TH_LOG("skip alarms are not supported.");
253*053f45beSAndroid Build Coastguard Worker return;
254*053f45beSAndroid Build Coastguard Worker }
255*053f45beSAndroid Build Coastguard Worker
256*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
257*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
258*053f45beSAndroid Build Coastguard Worker
259*053f45beSAndroid Build Coastguard Worker TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
260*053f45beSAndroid Build Coastguard Worker alarm.time.tm_mday, alarm.time.tm_mon + 1,
261*053f45beSAndroid Build Coastguard Worker alarm.time.tm_year + 1900, alarm.time.tm_hour,
262*053f45beSAndroid Build Coastguard Worker alarm.time.tm_min, alarm.time.tm_sec);
263*053f45beSAndroid Build Coastguard Worker
264*053f45beSAndroid Build Coastguard Worker FD_ZERO(&readfds);
265*053f45beSAndroid Build Coastguard Worker FD_SET(self->fd, &readfds);
266*053f45beSAndroid Build Coastguard Worker
267*053f45beSAndroid Build Coastguard Worker rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
268*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
269*053f45beSAndroid Build Coastguard Worker ASSERT_NE(0, rc);
270*053f45beSAndroid Build Coastguard Worker
271*053f45beSAndroid Build Coastguard Worker rc = read(self->fd, &data, sizeof(unsigned long));
272*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
273*053f45beSAndroid Build Coastguard Worker
274*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &tm);
275*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
276*053f45beSAndroid Build Coastguard Worker
277*053f45beSAndroid Build Coastguard Worker new = timegm((struct tm *)&tm);
278*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(new, secs);
279*053f45beSAndroid Build Coastguard Worker }
280*053f45beSAndroid Build Coastguard Worker
281*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
282*053f45beSAndroid Build Coastguard Worker struct timeval tv = { .tv_sec = 62 };
283*053f45beSAndroid Build Coastguard Worker unsigned long data;
284*053f45beSAndroid Build Coastguard Worker struct rtc_time tm;
285*053f45beSAndroid Build Coastguard Worker fd_set readfds;
286*053f45beSAndroid Build Coastguard Worker time_t secs, new;
287*053f45beSAndroid Build Coastguard Worker int rc;
288*053f45beSAndroid Build Coastguard Worker
289*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &tm);
290*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
291*053f45beSAndroid Build Coastguard Worker
292*053f45beSAndroid Build Coastguard Worker secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
293*053f45beSAndroid Build Coastguard Worker gmtime_r(&secs, (struct tm *)&tm);
294*053f45beSAndroid Build Coastguard Worker
295*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_ALM_SET, &tm);
296*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
297*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(EINVAL, errno);
298*053f45beSAndroid Build Coastguard Worker TH_LOG("skip alarms are not supported.");
299*053f45beSAndroid Build Coastguard Worker return;
300*053f45beSAndroid Build Coastguard Worker }
301*053f45beSAndroid Build Coastguard Worker
302*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_ALM_READ, &tm);
303*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
304*053f45beSAndroid Build Coastguard Worker
305*053f45beSAndroid Build Coastguard Worker TH_LOG("Alarm time now set to %02d:%02d:%02d.",
306*053f45beSAndroid Build Coastguard Worker tm.tm_hour, tm.tm_min, tm.tm_sec);
307*053f45beSAndroid Build Coastguard Worker
308*053f45beSAndroid Build Coastguard Worker /* Enable alarm interrupts */
309*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_AIE_ON, 0);
310*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
311*053f45beSAndroid Build Coastguard Worker
312*053f45beSAndroid Build Coastguard Worker FD_ZERO(&readfds);
313*053f45beSAndroid Build Coastguard Worker FD_SET(self->fd, &readfds);
314*053f45beSAndroid Build Coastguard Worker
315*053f45beSAndroid Build Coastguard Worker rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
316*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
317*053f45beSAndroid Build Coastguard Worker ASSERT_NE(0, rc);
318*053f45beSAndroid Build Coastguard Worker
319*053f45beSAndroid Build Coastguard Worker /* Disable alarm interrupts */
320*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_AIE_OFF, 0);
321*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
322*053f45beSAndroid Build Coastguard Worker
323*053f45beSAndroid Build Coastguard Worker rc = read(self->fd, &data, sizeof(unsigned long));
324*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
325*053f45beSAndroid Build Coastguard Worker TH_LOG("data: %lx", data);
326*053f45beSAndroid Build Coastguard Worker
327*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &tm);
328*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
329*053f45beSAndroid Build Coastguard Worker
330*053f45beSAndroid Build Coastguard Worker new = timegm((struct tm *)&tm);
331*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(new, secs);
332*053f45beSAndroid Build Coastguard Worker }
333*053f45beSAndroid Build Coastguard Worker
334*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
335*053f45beSAndroid Build Coastguard Worker struct timeval tv = { .tv_sec = 62 };
336*053f45beSAndroid Build Coastguard Worker struct rtc_wkalrm alarm = { 0 };
337*053f45beSAndroid Build Coastguard Worker struct rtc_time tm;
338*053f45beSAndroid Build Coastguard Worker unsigned long data;
339*053f45beSAndroid Build Coastguard Worker fd_set readfds;
340*053f45beSAndroid Build Coastguard Worker time_t secs, new;
341*053f45beSAndroid Build Coastguard Worker int rc;
342*053f45beSAndroid Build Coastguard Worker
343*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
344*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
345*053f45beSAndroid Build Coastguard Worker
346*053f45beSAndroid Build Coastguard Worker secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
347*053f45beSAndroid Build Coastguard Worker gmtime_r(&secs, (struct tm *)&alarm.time);
348*053f45beSAndroid Build Coastguard Worker
349*053f45beSAndroid Build Coastguard Worker alarm.enabled = 1;
350*053f45beSAndroid Build Coastguard Worker
351*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
352*053f45beSAndroid Build Coastguard Worker if (rc == -1) {
353*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(EINVAL, errno);
354*053f45beSAndroid Build Coastguard Worker TH_LOG("skip alarms are not supported.");
355*053f45beSAndroid Build Coastguard Worker return;
356*053f45beSAndroid Build Coastguard Worker }
357*053f45beSAndroid Build Coastguard Worker
358*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
359*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
360*053f45beSAndroid Build Coastguard Worker
361*053f45beSAndroid Build Coastguard Worker TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
362*053f45beSAndroid Build Coastguard Worker alarm.time.tm_mday, alarm.time.tm_mon + 1,
363*053f45beSAndroid Build Coastguard Worker alarm.time.tm_year + 1900, alarm.time.tm_hour,
364*053f45beSAndroid Build Coastguard Worker alarm.time.tm_min, alarm.time.tm_sec);
365*053f45beSAndroid Build Coastguard Worker
366*053f45beSAndroid Build Coastguard Worker FD_ZERO(&readfds);
367*053f45beSAndroid Build Coastguard Worker FD_SET(self->fd, &readfds);
368*053f45beSAndroid Build Coastguard Worker
369*053f45beSAndroid Build Coastguard Worker rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
370*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
371*053f45beSAndroid Build Coastguard Worker ASSERT_NE(0, rc);
372*053f45beSAndroid Build Coastguard Worker
373*053f45beSAndroid Build Coastguard Worker rc = read(self->fd, &data, sizeof(unsigned long));
374*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
375*053f45beSAndroid Build Coastguard Worker
376*053f45beSAndroid Build Coastguard Worker rc = ioctl(self->fd, RTC_RD_TIME, &tm);
377*053f45beSAndroid Build Coastguard Worker ASSERT_NE(-1, rc);
378*053f45beSAndroid Build Coastguard Worker
379*053f45beSAndroid Build Coastguard Worker new = timegm((struct tm *)&tm);
380*053f45beSAndroid Build Coastguard Worker ASSERT_EQ(new, secs);
381*053f45beSAndroid Build Coastguard Worker }
382*053f45beSAndroid Build Coastguard Worker #endif
383*053f45beSAndroid Build Coastguard Worker
384*053f45beSAndroid Build Coastguard Worker static void __attribute__((constructor))
__constructor_order_last(void)385*053f45beSAndroid Build Coastguard Worker __constructor_order_last(void)
386*053f45beSAndroid Build Coastguard Worker {
387*053f45beSAndroid Build Coastguard Worker if (!__constructor_order)
388*053f45beSAndroid Build Coastguard Worker __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
389*053f45beSAndroid Build Coastguard Worker }
390*053f45beSAndroid Build Coastguard Worker
main(int argc,char ** argv)391*053f45beSAndroid Build Coastguard Worker int main(int argc, char **argv)
392*053f45beSAndroid Build Coastguard Worker {
393*053f45beSAndroid Build Coastguard Worker switch (argc) {
394*053f45beSAndroid Build Coastguard Worker case 2:
395*053f45beSAndroid Build Coastguard Worker rtc_file = argv[1];
396*053f45beSAndroid Build Coastguard Worker /* FALLTHROUGH */
397*053f45beSAndroid Build Coastguard Worker case 1:
398*053f45beSAndroid Build Coastguard Worker break;
399*053f45beSAndroid Build Coastguard Worker default:
400*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
401*053f45beSAndroid Build Coastguard Worker return 1;
402*053f45beSAndroid Build Coastguard Worker }
403*053f45beSAndroid Build Coastguard Worker
404*053f45beSAndroid Build Coastguard Worker return test_harness_run(argc, argv);
405*053f45beSAndroid Build Coastguard Worker }
406