linux/tools/testing/selftests/timers/rtctest.c
<<
>>
Prefs
   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