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 23*2aaa36e9SMateusz Jończyk #define READ_LOOP_DURATION_SEC 30 24*2aaa36e9SMateusz Jończyk #define READ_LOOP_SLEEP_MS 11 25a12ab9e1SAlexandre Belloni 26d8da8665SAlexandre Belloni static char *rtc_file = "/dev/rtc0"; 27d8da8665SAlexandre Belloni 28d8da8665SAlexandre Belloni FIXTURE(rtc) { 29d8da8665SAlexandre Belloni int fd; 30a12ab9e1SAlexandre Belloni }; 31a12ab9e1SAlexandre Belloni 32d8da8665SAlexandre Belloni FIXTURE_SETUP(rtc) { 33d8da8665SAlexandre Belloni self->fd = open(rtc_file, O_RDONLY); 34d8da8665SAlexandre Belloni ASSERT_NE(-1, self->fd); 35d8da8665SAlexandre Belloni } 36a12ab9e1SAlexandre Belloni 37d8da8665SAlexandre Belloni FIXTURE_TEARDOWN(rtc) { 38d8da8665SAlexandre Belloni close(self->fd); 39d8da8665SAlexandre Belloni } 40d8da8665SAlexandre Belloni 41d8da8665SAlexandre Belloni TEST_F(rtc, date_read) { 42d8da8665SAlexandre Belloni int rc; 43d8da8665SAlexandre Belloni struct rtc_time rtc_tm; 44d8da8665SAlexandre Belloni 45d8da8665SAlexandre Belloni /* Read the RTC time/date */ 46d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 47d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 48d8da8665SAlexandre Belloni 49d8da8665SAlexandre Belloni TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.", 50d8da8665SAlexandre Belloni rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, 51d8da8665SAlexandre Belloni rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 52d8da8665SAlexandre Belloni } 53d8da8665SAlexandre Belloni 54*2aaa36e9SMateusz Jończyk static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time) 55*2aaa36e9SMateusz Jończyk { 56*2aaa36e9SMateusz Jończyk struct tm tm_time = { 57*2aaa36e9SMateusz Jończyk .tm_sec = rtc_time->tm_sec, 58*2aaa36e9SMateusz Jończyk .tm_min = rtc_time->tm_min, 59*2aaa36e9SMateusz Jończyk .tm_hour = rtc_time->tm_hour, 60*2aaa36e9SMateusz Jończyk .tm_mday = rtc_time->tm_mday, 61*2aaa36e9SMateusz Jończyk .tm_mon = rtc_time->tm_mon, 62*2aaa36e9SMateusz Jończyk .tm_year = rtc_time->tm_year, 63*2aaa36e9SMateusz Jończyk }; 64*2aaa36e9SMateusz Jończyk 65*2aaa36e9SMateusz Jończyk return mktime(&tm_time); 66*2aaa36e9SMateusz Jończyk } 67*2aaa36e9SMateusz Jończyk 68*2aaa36e9SMateusz Jończyk static void nanosleep_with_retries(long ns) 69*2aaa36e9SMateusz Jończyk { 70*2aaa36e9SMateusz Jończyk struct timespec req = { 71*2aaa36e9SMateusz Jończyk .tv_sec = 0, 72*2aaa36e9SMateusz Jończyk .tv_nsec = ns, 73*2aaa36e9SMateusz Jończyk }; 74*2aaa36e9SMateusz Jończyk struct timespec rem; 75*2aaa36e9SMateusz Jończyk 76*2aaa36e9SMateusz Jończyk while (nanosleep(&req, &rem) != 0) { 77*2aaa36e9SMateusz Jończyk req.tv_sec = rem.tv_sec; 78*2aaa36e9SMateusz Jończyk req.tv_nsec = rem.tv_nsec; 79*2aaa36e9SMateusz Jończyk } 80*2aaa36e9SMateusz Jończyk } 81*2aaa36e9SMateusz Jończyk 82*2aaa36e9SMateusz Jończyk TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) { 83*2aaa36e9SMateusz Jończyk int rc; 84*2aaa36e9SMateusz Jończyk long iter_count = 0; 85*2aaa36e9SMateusz Jończyk struct rtc_time rtc_tm; 86*2aaa36e9SMateusz Jończyk time_t start_rtc_read, prev_rtc_read; 87*2aaa36e9SMateusz Jończyk 88*2aaa36e9SMateusz Jończyk TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).", 89*2aaa36e9SMateusz Jończyk READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS); 90*2aaa36e9SMateusz Jończyk 91*2aaa36e9SMateusz Jończyk rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 92*2aaa36e9SMateusz Jończyk ASSERT_NE(-1, rc); 93*2aaa36e9SMateusz Jończyk start_rtc_read = rtc_time_to_timestamp(&rtc_tm); 94*2aaa36e9SMateusz Jończyk prev_rtc_read = start_rtc_read; 95*2aaa36e9SMateusz Jończyk 96*2aaa36e9SMateusz Jończyk do { 97*2aaa36e9SMateusz Jończyk time_t rtc_read; 98*2aaa36e9SMateusz Jończyk 99*2aaa36e9SMateusz Jończyk rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 100*2aaa36e9SMateusz Jończyk ASSERT_NE(-1, rc); 101*2aaa36e9SMateusz Jończyk 102*2aaa36e9SMateusz Jończyk rtc_read = rtc_time_to_timestamp(&rtc_tm); 103*2aaa36e9SMateusz Jończyk /* Time should not go backwards */ 104*2aaa36e9SMateusz Jończyk ASSERT_LE(prev_rtc_read, rtc_read); 105*2aaa36e9SMateusz Jończyk /* Time should not increase more then 1s at a time */ 106*2aaa36e9SMateusz Jończyk ASSERT_GE(prev_rtc_read + 1, rtc_read); 107*2aaa36e9SMateusz Jończyk 108*2aaa36e9SMateusz Jończyk /* Sleep 11ms to avoid killing / overheating the RTC */ 109*2aaa36e9SMateusz Jończyk nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000); 110*2aaa36e9SMateusz Jończyk 111*2aaa36e9SMateusz Jończyk prev_rtc_read = rtc_read; 112*2aaa36e9SMateusz Jończyk iter_count++; 113*2aaa36e9SMateusz Jończyk } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC); 114*2aaa36e9SMateusz Jończyk 115*2aaa36e9SMateusz Jończyk TH_LOG("Performed %ld RTC time reads.", iter_count); 116*2aaa36e9SMateusz Jończyk } 117*2aaa36e9SMateusz Jończyk 118eff82a26SAlexandre Belloni TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) { 119d8da8665SAlexandre Belloni int i, rc, irq = 0; 120d8da8665SAlexandre Belloni unsigned long data; 121d8da8665SAlexandre Belloni 122d8da8665SAlexandre Belloni /* Turn on update interrupts */ 123d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_ON, 0); 124d8da8665SAlexandre Belloni if (rc == -1) { 125d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno); 126d8da8665SAlexandre Belloni TH_LOG("skip update IRQs not supported."); 127d8da8665SAlexandre Belloni return; 128d8da8665SAlexandre Belloni } 129d8da8665SAlexandre Belloni 130d8da8665SAlexandre Belloni for (i = 0; i < NUM_UIE; i++) { 131d8da8665SAlexandre Belloni /* This read will block */ 132d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(data)); 133d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 134d8da8665SAlexandre Belloni irq++; 135d8da8665SAlexandre Belloni } 136d8da8665SAlexandre Belloni 137d8da8665SAlexandre Belloni EXPECT_EQ(NUM_UIE, irq); 138d8da8665SAlexandre Belloni 139d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_OFF, 0); 140d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 141d8da8665SAlexandre Belloni } 142d8da8665SAlexandre Belloni 143d8da8665SAlexandre Belloni TEST_F(rtc, uie_select) { 144d8da8665SAlexandre Belloni int i, rc, irq = 0; 145d8da8665SAlexandre Belloni unsigned long data; 146d8da8665SAlexandre Belloni 147d8da8665SAlexandre Belloni /* Turn on update interrupts */ 148d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_ON, 0); 149d8da8665SAlexandre Belloni if (rc == -1) { 150d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno); 151d8da8665SAlexandre Belloni TH_LOG("skip update IRQs not supported."); 152d8da8665SAlexandre Belloni return; 153d8da8665SAlexandre Belloni } 154d8da8665SAlexandre Belloni 155d8da8665SAlexandre Belloni for (i = 0; i < NUM_UIE; i++) { 156d8da8665SAlexandre Belloni struct timeval tv = { .tv_sec = 2 }; 157d8da8665SAlexandre Belloni fd_set readfds; 158d8da8665SAlexandre Belloni 159d8da8665SAlexandre Belloni FD_ZERO(&readfds); 160d8da8665SAlexandre Belloni FD_SET(self->fd, &readfds); 161d8da8665SAlexandre Belloni /* The select will wait until an RTC interrupt happens. */ 162d8da8665SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 163d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 164d8da8665SAlexandre Belloni ASSERT_NE(0, rc); 165d8da8665SAlexandre Belloni 166d8da8665SAlexandre Belloni /* This read won't block */ 167d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long)); 168d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 169d8da8665SAlexandre Belloni irq++; 170d8da8665SAlexandre Belloni } 171d8da8665SAlexandre Belloni 172d8da8665SAlexandre Belloni EXPECT_EQ(NUM_UIE, irq); 173d8da8665SAlexandre Belloni 174d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_UIE_OFF, 0); 175d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 176d8da8665SAlexandre Belloni } 177d8da8665SAlexandre Belloni 178d8da8665SAlexandre Belloni TEST_F(rtc, alarm_alm_set) { 179d8da8665SAlexandre Belloni struct timeval tv = { .tv_sec = ALARM_DELTA + 2 }; 180d8da8665SAlexandre Belloni unsigned long data; 181d8da8665SAlexandre Belloni struct rtc_time tm; 182d8da8665SAlexandre Belloni fd_set readfds; 183d8da8665SAlexandre Belloni time_t secs, new; 184d8da8665SAlexandre Belloni int rc; 185d8da8665SAlexandre Belloni 186d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm); 187d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 188d8da8665SAlexandre Belloni 189d8da8665SAlexandre Belloni secs = timegm((struct tm *)&tm) + ALARM_DELTA; 190d8da8665SAlexandre Belloni gmtime_r(&secs, (struct tm *)&tm); 191d8da8665SAlexandre Belloni 192d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_SET, &tm); 193d8da8665SAlexandre Belloni if (rc == -1) { 194d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno); 195d8da8665SAlexandre Belloni TH_LOG("skip alarms are not supported."); 196d8da8665SAlexandre Belloni return; 197d8da8665SAlexandre Belloni } 198d8da8665SAlexandre Belloni 199d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_READ, &tm); 200d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 201d8da8665SAlexandre Belloni 202d8da8665SAlexandre Belloni TH_LOG("Alarm time now set to %02d:%02d:%02d.", 203d8da8665SAlexandre Belloni tm.tm_hour, tm.tm_min, tm.tm_sec); 204d8da8665SAlexandre Belloni 205d8da8665SAlexandre Belloni /* Enable alarm interrupts */ 206d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_ON, 0); 207d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 208d8da8665SAlexandre Belloni 209d8da8665SAlexandre Belloni FD_ZERO(&readfds); 210d8da8665SAlexandre Belloni FD_SET(self->fd, &readfds); 211d8da8665SAlexandre Belloni 212d8da8665SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 213d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 214fdac9448SAlexandre Belloni ASSERT_NE(0, rc); 215d8da8665SAlexandre Belloni 216d8da8665SAlexandre Belloni /* Disable alarm interrupts */ 217d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_OFF, 0); 218d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 219d8da8665SAlexandre Belloni 220d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long)); 221d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 222d8da8665SAlexandre Belloni TH_LOG("data: %lx", data); 223d8da8665SAlexandre Belloni 224d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm); 225d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 226d8da8665SAlexandre Belloni 227d8da8665SAlexandre Belloni new = timegm((struct tm *)&tm); 228d8da8665SAlexandre Belloni ASSERT_EQ(new, secs); 229d8da8665SAlexandre Belloni } 230d8da8665SAlexandre Belloni 231d8da8665SAlexandre Belloni TEST_F(rtc, alarm_wkalm_set) { 232d8da8665SAlexandre Belloni struct timeval tv = { .tv_sec = ALARM_DELTA + 2 }; 233d8da8665SAlexandre Belloni struct rtc_wkalrm alarm = { 0 }; 234d8da8665SAlexandre Belloni struct rtc_time tm; 235d8da8665SAlexandre Belloni unsigned long data; 236d8da8665SAlexandre Belloni fd_set readfds; 237d8da8665SAlexandre Belloni time_t secs, new; 238d8da8665SAlexandre Belloni int rc; 239d8da8665SAlexandre Belloni 240d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time); 241d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 242d8da8665SAlexandre Belloni 243d8da8665SAlexandre Belloni secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA; 244d8da8665SAlexandre Belloni gmtime_r(&secs, (struct tm *)&alarm.time); 245d8da8665SAlexandre Belloni 246d8da8665SAlexandre Belloni alarm.enabled = 1; 247d8da8665SAlexandre Belloni 248d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_SET, &alarm); 249d8da8665SAlexandre Belloni if (rc == -1) { 250d8da8665SAlexandre Belloni ASSERT_EQ(EINVAL, errno); 251d8da8665SAlexandre Belloni TH_LOG("skip alarms are not supported."); 252d8da8665SAlexandre Belloni return; 253d8da8665SAlexandre Belloni } 254d8da8665SAlexandre Belloni 255d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_RD, &alarm); 256d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 257d8da8665SAlexandre Belloni 258d8da8665SAlexandre Belloni TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.", 259d8da8665SAlexandre Belloni alarm.time.tm_mday, alarm.time.tm_mon + 1, 260d8da8665SAlexandre Belloni alarm.time.tm_year + 1900, alarm.time.tm_hour, 261d8da8665SAlexandre Belloni alarm.time.tm_min, alarm.time.tm_sec); 262d8da8665SAlexandre Belloni 263d8da8665SAlexandre Belloni FD_ZERO(&readfds); 264d8da8665SAlexandre Belloni FD_SET(self->fd, &readfds); 265d8da8665SAlexandre Belloni 266d8da8665SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 267d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 268fdac9448SAlexandre Belloni ASSERT_NE(0, rc); 269d8da8665SAlexandre Belloni 270d8da8665SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long)); 271d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 272d8da8665SAlexandre Belloni 273d8da8665SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm); 274d8da8665SAlexandre Belloni ASSERT_NE(-1, rc); 275d8da8665SAlexandre Belloni 276d8da8665SAlexandre Belloni new = timegm((struct tm *)&tm); 277d8da8665SAlexandre Belloni ASSERT_EQ(new, secs); 278d8da8665SAlexandre Belloni } 279d8da8665SAlexandre Belloni 280eff82a26SAlexandre Belloni TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) { 2817b302772SAlexandre Belloni struct timeval tv = { .tv_sec = 62 }; 2827b302772SAlexandre Belloni unsigned long data; 2837b302772SAlexandre Belloni struct rtc_time tm; 2847b302772SAlexandre Belloni fd_set readfds; 2857b302772SAlexandre Belloni time_t secs, new; 2867b302772SAlexandre Belloni int rc; 2877b302772SAlexandre Belloni 2887b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm); 2897b302772SAlexandre Belloni ASSERT_NE(-1, rc); 2907b302772SAlexandre Belloni 2917b302772SAlexandre Belloni secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec; 2927b302772SAlexandre Belloni gmtime_r(&secs, (struct tm *)&tm); 2937b302772SAlexandre Belloni 2947b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_SET, &tm); 2957b302772SAlexandre Belloni if (rc == -1) { 2967b302772SAlexandre Belloni ASSERT_EQ(EINVAL, errno); 2977b302772SAlexandre Belloni TH_LOG("skip alarms are not supported."); 2987b302772SAlexandre Belloni return; 2997b302772SAlexandre Belloni } 3007b302772SAlexandre Belloni 3017b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_ALM_READ, &tm); 3027b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3037b302772SAlexandre Belloni 3047b302772SAlexandre Belloni TH_LOG("Alarm time now set to %02d:%02d:%02d.", 3057b302772SAlexandre Belloni tm.tm_hour, tm.tm_min, tm.tm_sec); 3067b302772SAlexandre Belloni 3077b302772SAlexandre Belloni /* Enable alarm interrupts */ 3087b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_ON, 0); 3097b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3107b302772SAlexandre Belloni 3117b302772SAlexandre Belloni FD_ZERO(&readfds); 3127b302772SAlexandre Belloni FD_SET(self->fd, &readfds); 3137b302772SAlexandre Belloni 3147b302772SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 3157b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3167b302772SAlexandre Belloni ASSERT_NE(0, rc); 3177b302772SAlexandre Belloni 3187b302772SAlexandre Belloni /* Disable alarm interrupts */ 3197b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_AIE_OFF, 0); 3207b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3217b302772SAlexandre Belloni 3227b302772SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long)); 3237b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3247b302772SAlexandre Belloni TH_LOG("data: %lx", data); 3257b302772SAlexandre Belloni 3267b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm); 3277b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3287b302772SAlexandre Belloni 3297b302772SAlexandre Belloni new = timegm((struct tm *)&tm); 3307b302772SAlexandre Belloni ASSERT_EQ(new, secs); 3317b302772SAlexandre Belloni } 3327b302772SAlexandre Belloni 333eff82a26SAlexandre Belloni TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) { 3347b302772SAlexandre Belloni struct timeval tv = { .tv_sec = 62 }; 3357b302772SAlexandre Belloni struct rtc_wkalrm alarm = { 0 }; 3367b302772SAlexandre Belloni struct rtc_time tm; 3377b302772SAlexandre Belloni unsigned long data; 3387b302772SAlexandre Belloni fd_set readfds; 3397b302772SAlexandre Belloni time_t secs, new; 3407b302772SAlexandre Belloni int rc; 3417b302772SAlexandre Belloni 3427b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time); 3437b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3447b302772SAlexandre Belloni 3457b302772SAlexandre Belloni secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec; 3467b302772SAlexandre Belloni gmtime_r(&secs, (struct tm *)&alarm.time); 3477b302772SAlexandre Belloni 3487b302772SAlexandre Belloni alarm.enabled = 1; 3497b302772SAlexandre Belloni 3507b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_SET, &alarm); 3517b302772SAlexandre Belloni if (rc == -1) { 3527b302772SAlexandre Belloni ASSERT_EQ(EINVAL, errno); 3537b302772SAlexandre Belloni TH_LOG("skip alarms are not supported."); 3547b302772SAlexandre Belloni return; 3557b302772SAlexandre Belloni } 3567b302772SAlexandre Belloni 3577b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_WKALM_RD, &alarm); 3587b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3597b302772SAlexandre Belloni 3607b302772SAlexandre Belloni TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.", 3617b302772SAlexandre Belloni alarm.time.tm_mday, alarm.time.tm_mon + 1, 3627b302772SAlexandre Belloni alarm.time.tm_year + 1900, alarm.time.tm_hour, 3637b302772SAlexandre Belloni alarm.time.tm_min, alarm.time.tm_sec); 3647b302772SAlexandre Belloni 3657b302772SAlexandre Belloni FD_ZERO(&readfds); 3667b302772SAlexandre Belloni FD_SET(self->fd, &readfds); 3677b302772SAlexandre Belloni 3687b302772SAlexandre Belloni rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 3697b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3707b302772SAlexandre Belloni ASSERT_NE(0, rc); 3717b302772SAlexandre Belloni 3727b302772SAlexandre Belloni rc = read(self->fd, &data, sizeof(unsigned long)); 3737b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3747b302772SAlexandre Belloni 3757b302772SAlexandre Belloni rc = ioctl(self->fd, RTC_RD_TIME, &tm); 3767b302772SAlexandre Belloni ASSERT_NE(-1, rc); 3777b302772SAlexandre Belloni 3787b302772SAlexandre Belloni new = timegm((struct tm *)&tm); 3797b302772SAlexandre Belloni ASSERT_EQ(new, secs); 3807b302772SAlexandre Belloni } 3817b302772SAlexandre Belloni 382d8da8665SAlexandre Belloni static void __attribute__((constructor)) 383d8da8665SAlexandre Belloni __constructor_order_last(void) 384d8da8665SAlexandre Belloni { 385d8da8665SAlexandre Belloni if (!__constructor_order) 386d8da8665SAlexandre Belloni __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD; 387a12ab9e1SAlexandre Belloni } 388a12ab9e1SAlexandre Belloni 389a12ab9e1SAlexandre Belloni int main(int argc, char **argv) 390a12ab9e1SAlexandre Belloni { 391a12ab9e1SAlexandre Belloni switch (argc) { 392a12ab9e1SAlexandre Belloni case 2: 393d8da8665SAlexandre Belloni rtc_file = argv[1]; 394a12ab9e1SAlexandre Belloni /* FALLTHROUGH */ 395a12ab9e1SAlexandre Belloni case 1: 396a12ab9e1SAlexandre Belloni break; 397a12ab9e1SAlexandre Belloni default: 398d8da8665SAlexandre Belloni fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]); 399a12ab9e1SAlexandre Belloni return 1; 400a12ab9e1SAlexandre Belloni } 401a12ab9e1SAlexandre Belloni 402d8da8665SAlexandre Belloni return test_harness_run(argc, argv); 403a12ab9e1SAlexandre Belloni } 404