root/tools/testing/selftests/rtc/rtctest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. FIXTURE
  2. FIXTURE_SETUP
  3. FIXTURE_TEARDOWN
  4. TEST_F
  5. TEST_F_TIMEOUT
  6. TEST_F
  7. TEST_F
  8. TEST_F
  9. TEST_F_TIMEOUT
  10. TEST_F_TIMEOUT
  11. __constructor_order_last
  12. main

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

/* [<][>][^][v][top][bottom][index][help] */