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