Home | History | Annotate | Download | only in src
      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