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 25/* 26 * This expects the new RTC class driver framework, working with 27 * clocks that will often not be clones of what the PC-AT had. 28 * Use the command line to specify another RTC if you need one. 29 */ 30static const char default_rtc[] = "/dev/rtc0"; 31 32 33int main(int argc, char **argv) 34{ 35 int i, fd, retval, irqcount = 0; 36 unsigned long tmp, data; 37 struct rtc_time rtc_tm; 38 const char *rtc = default_rtc; 39 struct timeval start, end, diff; 40 41 switch (argc) { 42 case 2: 43 rtc = argv[1]; 44 /* FALLTHROUGH */ 45 case 1: 46 break; 47 default: 48 fprintf(stderr, "usage: rtctest [rtcdev]\n"); 49 return 1; 50 } 51 52 fd = open(rtc, O_RDONLY); 53 54 if (fd == -1) { 55 perror(rtc); 56 exit(errno); 57 } 58 59 fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); 60 61 /* Turn on update interrupts (one per second) */ 62 retval = ioctl(fd, RTC_UIE_ON, 0); 63 if (retval == -1) { 64 if (errno == EINVAL) { 65 fprintf(stderr, 66 "\n...Update IRQs not supported.\n"); 67 goto test_READ; 68 } 69 perror("RTC_UIE_ON ioctl"); 70 exit(errno); 71 } 72 73 fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:", 74 rtc); 75 fflush(stderr); 76 for (i=1; i<6; i++) { 77 /* This read will block */ 78 retval = read(fd, &data, sizeof(unsigned long)); 79 if (retval == -1) { 80 perror("read"); 81 exit(errno); 82 } 83 fprintf(stderr, " %d",i); 84 fflush(stderr); 85 irqcount++; 86 } 87 88 fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); 89 fflush(stderr); 90 for (i=1; i<6; i++) { 91 struct timeval tv = {5, 0}; /* 5 second timeout on select */ 92 fd_set readfds; 93 94 FD_ZERO(&readfds); 95 FD_SET(fd, &readfds); 96 /* The select will wait until an RTC interrupt happens. */ 97 retval = select(fd+1, &readfds, NULL, NULL, &tv); 98 if (retval == -1) { 99 perror("select"); 100 exit(errno); 101 } 102 /* This read won't block unlike the select-less case above. */ 103 retval = read(fd, &data, sizeof(unsigned long)); 104 if (retval == -1) { 105 perror("read"); 106 exit(errno); 107 } 108 fprintf(stderr, " %d",i); 109 fflush(stderr); 110 irqcount++; 111 } 112 113 /* Turn off update interrupts */ 114 retval = ioctl(fd, RTC_UIE_OFF, 0); 115 if (retval == -1) { 116 perror("RTC_UIE_OFF ioctl"); 117 exit(errno); 118 } 119 120test_READ: 121 /* Read the RTC time/date */ 122 retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); 123 if (retval == -1) { 124 perror("RTC_RD_TIME ioctl"); 125 exit(errno); 126 } 127 128 fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", 129 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, 130 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 131 132 /* Set the alarm to 5 sec in the future, and check for rollover */ 133 rtc_tm.tm_sec += 5; 134 if (rtc_tm.tm_sec >= 60) { 135 rtc_tm.tm_sec %= 60; 136 rtc_tm.tm_min++; 137 } 138 if (rtc_tm.tm_min == 60) { 139 rtc_tm.tm_min = 0; 140 rtc_tm.tm_hour++; 141 } 142 if (rtc_tm.tm_hour == 24) 143 rtc_tm.tm_hour = 0; 144 145 retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); 146 if (retval == -1) { 147 if (errno == ENOTTY) { 148 fprintf(stderr, 149 "\n...Alarm IRQs not supported.\n"); 150 goto test_PIE; 151 } 152 perror("RTC_ALM_SET ioctl"); 153 exit(errno); 154 } 155 156 /* Read the current alarm settings */ 157 retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); 158 if (retval == -1) { 159 perror("RTC_ALM_READ ioctl"); 160 exit(errno); 161 } 162 163 fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", 164 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 165 166 /* Enable alarm interrupts */ 167 retval = ioctl(fd, RTC_AIE_ON, 0); 168 if (retval == -1) { 169 perror("RTC_AIE_ON ioctl"); 170 exit(errno); 171 } 172 173 fprintf(stderr, "Waiting 5 seconds for alarm..."); 174 fflush(stderr); 175 /* This blocks until the alarm ring causes an interrupt */ 176 retval = read(fd, &data, sizeof(unsigned long)); 177 if (retval == -1) { 178 perror("read"); 179 exit(errno); 180 } 181 irqcount++; 182 fprintf(stderr, " okay. Alarm rang.\n"); 183 184 /* Disable alarm interrupts */ 185 retval = ioctl(fd, RTC_AIE_OFF, 0); 186 if (retval == -1) { 187 perror("RTC_AIE_OFF ioctl"); 188 exit(errno); 189 } 190 191test_PIE: 192 /* Read periodic IRQ rate */ 193 retval = ioctl(fd, RTC_IRQP_READ, &tmp); 194 if (retval == -1) { 195 /* not all RTCs support periodic IRQs */ 196 if (errno == ENOTTY) { 197 fprintf(stderr, "\nNo periodic IRQ support\n"); 198 goto done; 199 } 200 perror("RTC_IRQP_READ ioctl"); 201 exit(errno); 202 } 203 fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); 204 205 fprintf(stderr, "Counting 20 interrupts at:"); 206 fflush(stderr); 207 208 /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ 209 for (tmp=2; tmp<=64; tmp*=2) { 210 211 retval = ioctl(fd, RTC_IRQP_SET, tmp); 212 if (retval == -1) { 213 /* not all RTCs can change their periodic IRQ rate */ 214 if (errno == ENOTTY) { 215 fprintf(stderr, 216 "\n...Periodic IRQ rate is fixed\n"); 217 goto done; 218 } 219 perror("RTC_IRQP_SET ioctl"); 220 exit(errno); 221 } 222 223 fprintf(stderr, "\n%ldHz:\t", tmp); 224 fflush(stderr); 225 226 /* Enable periodic interrupts */ 227 retval = ioctl(fd, RTC_PIE_ON, 0); 228 if (retval == -1) { 229 perror("RTC_PIE_ON ioctl"); 230 exit(errno); 231 } 232 233 for (i=1; i<21; i++) { 234 gettimeofday(&start, NULL); 235 /* This blocks */ 236 retval = read(fd, &data, sizeof(unsigned long)); 237 if (retval == -1) { 238 perror("read"); 239 exit(errno); 240 } 241 gettimeofday(&end, NULL); 242 timersub(&end, &start, &diff); 243 if (diff.tv_sec > 0 || 244 diff.tv_usec > ((1000000L / tmp) * 1.10)) { 245 fprintf(stderr, "\nPIE delta error: %ld.%06ld should be close to 0.%06ld\n", 246 diff.tv_sec, diff.tv_usec, 247 (1000000L / tmp)); 248 fflush(stdout); 249 exit(-1); 250 } 251 252 fprintf(stderr, " %d",i); 253 fflush(stderr); 254 irqcount++; 255 } 256 257 /* Disable periodic interrupts */ 258 retval = ioctl(fd, RTC_PIE_OFF, 0); 259 if (retval == -1) { 260 perror("RTC_PIE_OFF ioctl"); 261 exit(errno); 262 } 263 } 264 265done: 266 fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); 267 268 close(fd); 269 270 return 0; 271} 272