Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.13-rc3 398 lines 8.6 kB view raw
1/* 2 * Real Time Clock Driver Test/Example Program 3 * 4 * Compile with: 5 * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest 6 * 7 * Copyright (C) 1996, Paul Gortmaker. 8 * 9 * Released under the GNU General Public License, version 2, 10 * included herein by reference. 11 * 12 */ 13 14#include <stdio.h> 15#include <linux/rtc.h> 16#include <sys/ioctl.h> 17#include <sys/time.h> 18#include <sys/types.h> 19#include <fcntl.h> 20#include <unistd.h> 21#include <stdlib.h> 22#include <errno.h> 23 24#ifndef ARRAY_SIZE 25# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 26#endif 27 28/* 29 * This expects the new RTC class driver framework, working with 30 * clocks that will often not be clones of what the PC-AT had. 31 * Use the command line to specify another RTC if you need one. 32 */ 33static const char default_rtc[] = "/dev/rtc0"; 34 35static struct rtc_time cutoff_dates[] = { 36 { 37 .tm_year = 70, /* 1970 -1900 */ 38 .tm_mday = 1, 39 }, 40 /* signed time_t 19/01/2038 3:14:08 */ 41 { 42 .tm_year = 138, 43 .tm_mday = 19, 44 }, 45 { 46 .tm_year = 138, 47 .tm_mday = 20, 48 }, 49 { 50 .tm_year = 199, /* 2099 -1900 */ 51 .tm_mday = 1, 52 }, 53 { 54 .tm_year = 200, /* 2100 -1900 */ 55 .tm_mday = 1, 56 }, 57 /* unsigned time_t 07/02/2106 7:28:15*/ 58 { 59 .tm_year = 205, 60 .tm_mon = 1, 61 .tm_mday = 7, 62 }, 63 { 64 .tm_year = 206, 65 .tm_mon = 1, 66 .tm_mday = 8, 67 }, 68 /* signed time on 64bit in nanoseconds 12/04/2262 01:47:16*/ 69 { 70 .tm_year = 362, 71 .tm_mon = 3, 72 .tm_mday = 12, 73 }, 74 { 75 .tm_year = 362, /* 2262 -1900 */ 76 .tm_mon = 3, 77 .tm_mday = 13, 78 }, 79}; 80 81static int compare_dates(struct rtc_time *a, struct rtc_time *b) 82{ 83 if (a->tm_year != b->tm_year || 84 a->tm_mon != b->tm_mon || 85 a->tm_mday != b->tm_mday || 86 a->tm_hour != b->tm_hour || 87 a->tm_min != b->tm_min || 88 ((b->tm_sec - a->tm_sec) > 1)) 89 return 1; 90 91 return 0; 92} 93 94int main(int argc, char **argv) 95{ 96 int i, fd, retval, irqcount = 0, dangerous = 0; 97 unsigned long tmp, data; 98 struct rtc_time rtc_tm; 99 const char *rtc = default_rtc; 100 struct timeval start, end, diff; 101 102 switch (argc) { 103 case 3: 104 if (*argv[2] == 'd') 105 dangerous = 1; 106 case 2: 107 rtc = argv[1]; 108 /* FALLTHROUGH */ 109 case 1: 110 break; 111 default: 112 fprintf(stderr, "usage: rtctest [rtcdev] [d]\n"); 113 return 1; 114 } 115 116 fd = open(rtc, O_RDONLY); 117 118 if (fd == -1) { 119 perror(rtc); 120 exit(errno); 121 } 122 123 fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); 124 125 /* Turn on update interrupts (one per second) */ 126 retval = ioctl(fd, RTC_UIE_ON, 0); 127 if (retval == -1) { 128 if (errno == EINVAL) { 129 fprintf(stderr, 130 "\n...Update IRQs not supported.\n"); 131 goto test_READ; 132 } 133 perror("RTC_UIE_ON ioctl"); 134 exit(errno); 135 } 136 137 fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:", 138 rtc); 139 fflush(stderr); 140 for (i=1; i<6; i++) { 141 /* This read will block */ 142 retval = read(fd, &data, sizeof(unsigned long)); 143 if (retval == -1) { 144 perror("read"); 145 exit(errno); 146 } 147 fprintf(stderr, " %d",i); 148 fflush(stderr); 149 irqcount++; 150 } 151 152 fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); 153 fflush(stderr); 154 for (i=1; i<6; i++) { 155 struct timeval tv = {5, 0}; /* 5 second timeout on select */ 156 fd_set readfds; 157 158 FD_ZERO(&readfds); 159 FD_SET(fd, &readfds); 160 /* The select will wait until an RTC interrupt happens. */ 161 retval = select(fd+1, &readfds, NULL, NULL, &tv); 162 if (retval == -1) { 163 perror("select"); 164 exit(errno); 165 } 166 /* This read won't block unlike the select-less case above. */ 167 retval = read(fd, &data, sizeof(unsigned long)); 168 if (retval == -1) { 169 perror("read"); 170 exit(errno); 171 } 172 fprintf(stderr, " %d",i); 173 fflush(stderr); 174 irqcount++; 175 } 176 177 /* Turn off update interrupts */ 178 retval = ioctl(fd, RTC_UIE_OFF, 0); 179 if (retval == -1) { 180 perror("RTC_UIE_OFF ioctl"); 181 exit(errno); 182 } 183 184test_READ: 185 /* Read the RTC time/date */ 186 retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); 187 if (retval == -1) { 188 perror("RTC_RD_TIME ioctl"); 189 exit(errno); 190 } 191 192 fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", 193 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, 194 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 195 196 /* Set the alarm to 5 sec in the future, and check for rollover */ 197 rtc_tm.tm_sec += 5; 198 if (rtc_tm.tm_sec >= 60) { 199 rtc_tm.tm_sec %= 60; 200 rtc_tm.tm_min++; 201 } 202 if (rtc_tm.tm_min == 60) { 203 rtc_tm.tm_min = 0; 204 rtc_tm.tm_hour++; 205 } 206 if (rtc_tm.tm_hour == 24) 207 rtc_tm.tm_hour = 0; 208 209 retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); 210 if (retval == -1) { 211 if (errno == EINVAL) { 212 fprintf(stderr, 213 "\n...Alarm IRQs not supported.\n"); 214 goto test_PIE; 215 } 216 217 perror("RTC_ALM_SET ioctl"); 218 exit(errno); 219 } 220 221 /* Read the current alarm settings */ 222 retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); 223 if (retval == -1) { 224 perror("RTC_ALM_READ ioctl"); 225 exit(errno); 226 } 227 228 fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", 229 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 230 231 /* Enable alarm interrupts */ 232 retval = ioctl(fd, RTC_AIE_ON, 0); 233 if (retval == -1) { 234 if (errno == EINVAL) { 235 fprintf(stderr, 236 "\n...Alarm IRQs not supported.\n"); 237 goto test_PIE; 238 } 239 240 perror("RTC_AIE_ON ioctl"); 241 exit(errno); 242 } 243 244 fprintf(stderr, "Waiting 5 seconds for alarm..."); 245 fflush(stderr); 246 /* This blocks until the alarm ring causes an interrupt */ 247 retval = read(fd, &data, sizeof(unsigned long)); 248 if (retval == -1) { 249 perror("read"); 250 exit(errno); 251 } 252 irqcount++; 253 fprintf(stderr, " okay. Alarm rang.\n"); 254 255 /* Disable alarm interrupts */ 256 retval = ioctl(fd, RTC_AIE_OFF, 0); 257 if (retval == -1) { 258 perror("RTC_AIE_OFF ioctl"); 259 exit(errno); 260 } 261 262test_PIE: 263 /* Read periodic IRQ rate */ 264 retval = ioctl(fd, RTC_IRQP_READ, &tmp); 265 if (retval == -1) { 266 /* not all RTCs support periodic IRQs */ 267 if (errno == EINVAL) { 268 fprintf(stderr, "\nNo periodic IRQ support\n"); 269 goto test_DATE; 270 } 271 perror("RTC_IRQP_READ ioctl"); 272 exit(errno); 273 } 274 fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); 275 276 fprintf(stderr, "Counting 20 interrupts at:"); 277 fflush(stderr); 278 279 /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ 280 for (tmp=2; tmp<=64; tmp*=2) { 281 282 retval = ioctl(fd, RTC_IRQP_SET, tmp); 283 if (retval == -1) { 284 /* not all RTCs can change their periodic IRQ rate */ 285 if (errno == EINVAL) { 286 fprintf(stderr, 287 "\n...Periodic IRQ rate is fixed\n"); 288 goto test_DATE; 289 } 290 perror("RTC_IRQP_SET ioctl"); 291 exit(errno); 292 } 293 294 fprintf(stderr, "\n%ldHz:\t", tmp); 295 fflush(stderr); 296 297 /* Enable periodic interrupts */ 298 retval = ioctl(fd, RTC_PIE_ON, 0); 299 if (retval == -1) { 300 perror("RTC_PIE_ON ioctl"); 301 exit(errno); 302 } 303 304 for (i=1; i<21; i++) { 305 gettimeofday(&start, NULL); 306 /* This blocks */ 307 retval = read(fd, &data, sizeof(unsigned long)); 308 if (retval == -1) { 309 perror("read"); 310 exit(errno); 311 } 312 gettimeofday(&end, NULL); 313 timersub(&end, &start, &diff); 314 if (diff.tv_sec > 0 || 315 diff.tv_usec > ((1000000L / tmp) * 1.10)) { 316 fprintf(stderr, "\nPIE delta error: %ld.%06ld should be close to 0.%06ld\n", 317 diff.tv_sec, diff.tv_usec, 318 (1000000L / tmp)); 319 fflush(stdout); 320 exit(-1); 321 } 322 323 fprintf(stderr, " %d",i); 324 fflush(stderr); 325 irqcount++; 326 } 327 328 /* Disable periodic interrupts */ 329 retval = ioctl(fd, RTC_PIE_OFF, 0); 330 if (retval == -1) { 331 perror("RTC_PIE_OFF ioctl"); 332 exit(errno); 333 } 334 } 335 336test_DATE: 337 if (!dangerous) 338 goto done; 339 340 fprintf(stderr, "\nTesting problematic dates\n"); 341 342 for (i = 0; i < ARRAY_SIZE(cutoff_dates); i++) { 343 struct rtc_time current; 344 345 /* Write the new date in RTC */ 346 retval = ioctl(fd, RTC_SET_TIME, &cutoff_dates[i]); 347 if (retval == -1) { 348 perror("RTC_SET_TIME ioctl"); 349 close(fd); 350 exit(errno); 351 } 352 353 /* Read back */ 354 retval = ioctl(fd, RTC_RD_TIME, &current); 355 if (retval == -1) { 356 perror("RTC_RD_TIME ioctl"); 357 exit(errno); 358 } 359 360 if(compare_dates(&cutoff_dates[i], &current)) { 361 fprintf(stderr,"Setting date %d failed\n", 362 cutoff_dates[i].tm_year + 1900); 363 goto done; 364 } 365 366 cutoff_dates[i].tm_sec += 5; 367 368 /* Write the new alarm in RTC */ 369 retval = ioctl(fd, RTC_ALM_SET, &cutoff_dates[i]); 370 if (retval == -1) { 371 perror("RTC_ALM_SET ioctl"); 372 close(fd); 373 exit(errno); 374 } 375 376 /* Read back */ 377 retval = ioctl(fd, RTC_ALM_READ, &current); 378 if (retval == -1) { 379 perror("RTC_ALM_READ ioctl"); 380 exit(errno); 381 } 382 383 if(compare_dates(&cutoff_dates[i], &current)) { 384 fprintf(stderr,"Setting alarm %d failed\n", 385 cutoff_dates[i].tm_year + 1900); 386 goto done; 387 } 388 389 fprintf(stderr, "Setting year %d is OK \n", 390 cutoff_dates[i].tm_year + 1900); 391 } 392done: 393 fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); 394 395 close(fd); 396 397 return 0; 398}