0001
0002
0003
0004
0005
0006
0007
0008 #include <errno.h>
0009 #include <fcntl.h>
0010 #include <linux/rtc.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <sys/ioctl.h>
0014 #include <sys/time.h>
0015 #include <sys/types.h>
0016 #include <time.h>
0017 #include <unistd.h>
0018
0019 #include "../kselftest_harness.h"
0020
0021 #define NUM_UIE 3
0022 #define ALARM_DELTA 3
0023 #define READ_LOOP_DURATION_SEC 30
0024 #define READ_LOOP_SLEEP_MS 11
0025
0026 static char *rtc_file = "/dev/rtc0";
0027
0028 FIXTURE(rtc) {
0029 int fd;
0030 };
0031
0032 FIXTURE_SETUP(rtc) {
0033 self->fd = open(rtc_file, O_RDONLY);
0034 ASSERT_NE(-1, self->fd);
0035 }
0036
0037 FIXTURE_TEARDOWN(rtc) {
0038 close(self->fd);
0039 }
0040
0041 TEST_F(rtc, date_read) {
0042 int rc;
0043 struct rtc_time rtc_tm;
0044
0045
0046 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
0047 ASSERT_NE(-1, rc);
0048
0049 TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
0050 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
0051 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
0052 }
0053
0054 static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
0055 {
0056 struct tm tm_time = {
0057 .tm_sec = rtc_time->tm_sec,
0058 .tm_min = rtc_time->tm_min,
0059 .tm_hour = rtc_time->tm_hour,
0060 .tm_mday = rtc_time->tm_mday,
0061 .tm_mon = rtc_time->tm_mon,
0062 .tm_year = rtc_time->tm_year,
0063 };
0064
0065 return mktime(&tm_time);
0066 }
0067
0068 static void nanosleep_with_retries(long ns)
0069 {
0070 struct timespec req = {
0071 .tv_sec = 0,
0072 .tv_nsec = ns,
0073 };
0074 struct timespec rem;
0075
0076 while (nanosleep(&req, &rem) != 0) {
0077 req.tv_sec = rem.tv_sec;
0078 req.tv_nsec = rem.tv_nsec;
0079 }
0080 }
0081
0082 TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
0083 int rc;
0084 long iter_count = 0;
0085 struct rtc_time rtc_tm;
0086 time_t start_rtc_read, prev_rtc_read;
0087
0088 TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
0089 READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
0090
0091 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
0092 ASSERT_NE(-1, rc);
0093 start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
0094 prev_rtc_read = start_rtc_read;
0095
0096 do {
0097 time_t rtc_read;
0098
0099 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
0100 ASSERT_NE(-1, rc);
0101
0102 rtc_read = rtc_time_to_timestamp(&rtc_tm);
0103
0104 ASSERT_LE(prev_rtc_read, rtc_read);
0105
0106 ASSERT_GE(prev_rtc_read + 1, rtc_read);
0107
0108
0109 nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
0110
0111 prev_rtc_read = rtc_read;
0112 iter_count++;
0113 } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
0114
0115 TH_LOG("Performed %ld RTC time reads.", iter_count);
0116 }
0117
0118 TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
0119 int i, rc, irq = 0;
0120 unsigned long data;
0121
0122
0123 rc = ioctl(self->fd, RTC_UIE_ON, 0);
0124 if (rc == -1) {
0125 ASSERT_EQ(EINVAL, errno);
0126 TH_LOG("skip update IRQs not supported.");
0127 return;
0128 }
0129
0130 for (i = 0; i < NUM_UIE; i++) {
0131
0132 rc = read(self->fd, &data, sizeof(data));
0133 ASSERT_NE(-1, rc);
0134 irq++;
0135 }
0136
0137 EXPECT_EQ(NUM_UIE, irq);
0138
0139 rc = ioctl(self->fd, RTC_UIE_OFF, 0);
0140 ASSERT_NE(-1, rc);
0141 }
0142
0143 TEST_F(rtc, uie_select) {
0144 int i, rc, irq = 0;
0145 unsigned long data;
0146
0147
0148 rc = ioctl(self->fd, RTC_UIE_ON, 0);
0149 if (rc == -1) {
0150 ASSERT_EQ(EINVAL, errno);
0151 TH_LOG("skip update IRQs not supported.");
0152 return;
0153 }
0154
0155 for (i = 0; i < NUM_UIE; i++) {
0156 struct timeval tv = { .tv_sec = 2 };
0157 fd_set readfds;
0158
0159 FD_ZERO(&readfds);
0160 FD_SET(self->fd, &readfds);
0161
0162 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0163 ASSERT_NE(-1, rc);
0164 ASSERT_NE(0, rc);
0165
0166
0167 rc = read(self->fd, &data, sizeof(unsigned long));
0168 ASSERT_NE(-1, rc);
0169 irq++;
0170 }
0171
0172 EXPECT_EQ(NUM_UIE, irq);
0173
0174 rc = ioctl(self->fd, RTC_UIE_OFF, 0);
0175 ASSERT_NE(-1, rc);
0176 }
0177
0178 TEST_F(rtc, alarm_alm_set) {
0179 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
0180 unsigned long data;
0181 struct rtc_time tm;
0182 fd_set readfds;
0183 time_t secs, new;
0184 int rc;
0185
0186 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0187 ASSERT_NE(-1, rc);
0188
0189 secs = timegm((struct tm *)&tm) + ALARM_DELTA;
0190 gmtime_r(&secs, (struct tm *)&tm);
0191
0192 rc = ioctl(self->fd, RTC_ALM_SET, &tm);
0193 if (rc == -1) {
0194 ASSERT_EQ(EINVAL, errno);
0195 TH_LOG("skip alarms are not supported.");
0196 return;
0197 }
0198
0199 rc = ioctl(self->fd, RTC_ALM_READ, &tm);
0200 ASSERT_NE(-1, rc);
0201
0202 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
0203 tm.tm_hour, tm.tm_min, tm.tm_sec);
0204
0205
0206 rc = ioctl(self->fd, RTC_AIE_ON, 0);
0207 ASSERT_NE(-1, rc);
0208
0209 FD_ZERO(&readfds);
0210 FD_SET(self->fd, &readfds);
0211
0212 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0213 ASSERT_NE(-1, rc);
0214 ASSERT_NE(0, rc);
0215
0216
0217 rc = ioctl(self->fd, RTC_AIE_OFF, 0);
0218 ASSERT_NE(-1, rc);
0219
0220 rc = read(self->fd, &data, sizeof(unsigned long));
0221 ASSERT_NE(-1, rc);
0222 TH_LOG("data: %lx", data);
0223
0224 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0225 ASSERT_NE(-1, rc);
0226
0227 new = timegm((struct tm *)&tm);
0228 ASSERT_EQ(new, secs);
0229 }
0230
0231 TEST_F(rtc, alarm_wkalm_set) {
0232 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
0233 struct rtc_wkalrm alarm = { 0 };
0234 struct rtc_time tm;
0235 unsigned long data;
0236 fd_set readfds;
0237 time_t secs, new;
0238 int rc;
0239
0240 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
0241 ASSERT_NE(-1, rc);
0242
0243 secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
0244 gmtime_r(&secs, (struct tm *)&alarm.time);
0245
0246 alarm.enabled = 1;
0247
0248 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
0249 if (rc == -1) {
0250 ASSERT_EQ(EINVAL, errno);
0251 TH_LOG("skip alarms are not supported.");
0252 return;
0253 }
0254
0255 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
0256 ASSERT_NE(-1, rc);
0257
0258 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
0259 alarm.time.tm_mday, alarm.time.tm_mon + 1,
0260 alarm.time.tm_year + 1900, alarm.time.tm_hour,
0261 alarm.time.tm_min, alarm.time.tm_sec);
0262
0263 FD_ZERO(&readfds);
0264 FD_SET(self->fd, &readfds);
0265
0266 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0267 ASSERT_NE(-1, rc);
0268 ASSERT_NE(0, rc);
0269
0270 rc = read(self->fd, &data, sizeof(unsigned long));
0271 ASSERT_NE(-1, rc);
0272
0273 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0274 ASSERT_NE(-1, rc);
0275
0276 new = timegm((struct tm *)&tm);
0277 ASSERT_EQ(new, secs);
0278 }
0279
0280 TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
0281 struct timeval tv = { .tv_sec = 62 };
0282 unsigned long data;
0283 struct rtc_time tm;
0284 fd_set readfds;
0285 time_t secs, new;
0286 int rc;
0287
0288 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0289 ASSERT_NE(-1, rc);
0290
0291 secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
0292 gmtime_r(&secs, (struct tm *)&tm);
0293
0294 rc = ioctl(self->fd, RTC_ALM_SET, &tm);
0295 if (rc == -1) {
0296 ASSERT_EQ(EINVAL, errno);
0297 TH_LOG("skip alarms are not supported.");
0298 return;
0299 }
0300
0301 rc = ioctl(self->fd, RTC_ALM_READ, &tm);
0302 ASSERT_NE(-1, rc);
0303
0304 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
0305 tm.tm_hour, tm.tm_min, tm.tm_sec);
0306
0307
0308 rc = ioctl(self->fd, RTC_AIE_ON, 0);
0309 ASSERT_NE(-1, rc);
0310
0311 FD_ZERO(&readfds);
0312 FD_SET(self->fd, &readfds);
0313
0314 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0315 ASSERT_NE(-1, rc);
0316 ASSERT_NE(0, rc);
0317
0318
0319 rc = ioctl(self->fd, RTC_AIE_OFF, 0);
0320 ASSERT_NE(-1, rc);
0321
0322 rc = read(self->fd, &data, sizeof(unsigned long));
0323 ASSERT_NE(-1, rc);
0324 TH_LOG("data: %lx", data);
0325
0326 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0327 ASSERT_NE(-1, rc);
0328
0329 new = timegm((struct tm *)&tm);
0330 ASSERT_EQ(new, secs);
0331 }
0332
0333 TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
0334 struct timeval tv = { .tv_sec = 62 };
0335 struct rtc_wkalrm alarm = { 0 };
0336 struct rtc_time tm;
0337 unsigned long data;
0338 fd_set readfds;
0339 time_t secs, new;
0340 int rc;
0341
0342 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
0343 ASSERT_NE(-1, rc);
0344
0345 secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
0346 gmtime_r(&secs, (struct tm *)&alarm.time);
0347
0348 alarm.enabled = 1;
0349
0350 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
0351 if (rc == -1) {
0352 ASSERT_EQ(EINVAL, errno);
0353 TH_LOG("skip alarms are not supported.");
0354 return;
0355 }
0356
0357 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
0358 ASSERT_NE(-1, rc);
0359
0360 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
0361 alarm.time.tm_mday, alarm.time.tm_mon + 1,
0362 alarm.time.tm_year + 1900, alarm.time.tm_hour,
0363 alarm.time.tm_min, alarm.time.tm_sec);
0364
0365 FD_ZERO(&readfds);
0366 FD_SET(self->fd, &readfds);
0367
0368 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0369 ASSERT_NE(-1, rc);
0370 ASSERT_NE(0, rc);
0371
0372 rc = read(self->fd, &data, sizeof(unsigned long));
0373 ASSERT_NE(-1, rc);
0374
0375 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0376 ASSERT_NE(-1, rc);
0377
0378 new = timegm((struct tm *)&tm);
0379 ASSERT_EQ(new, secs);
0380 }
0381
0382 static void __attribute__((constructor))
0383 __constructor_order_last(void)
0384 {
0385 if (!__constructor_order)
0386 __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
0387 }
0388
0389 int main(int argc, char **argv)
0390 {
0391 switch (argc) {
0392 case 2:
0393 rtc_file = argv[1];
0394
0395 case 1:
0396 break;
0397 default:
0398 fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
0399 return 1;
0400 }
0401
0402 return test_harness_run(argc, argv);
0403 }