Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Real Time Clock Periodic Interrupt test program
  4 *
  5 * Since commit 6610e0893b8bc ("RTC: Rework RTC code to use timerqueue for
  6 * events"), PIE are completely handled using hrtimers, without actually using
  7 * any underlying hardware RTC.
  8 *
  9 */
 10
 11#include <stdio.h>
 12#include <linux/rtc.h>
 13#include <sys/ioctl.h>
 14#include <sys/time.h>
 15#include <sys/types.h>
 16#include <fcntl.h>
 17#include <unistd.h>
 18#include <stdlib.h>
 19#include <errno.h>
 20
 21/*
 22 * This expects the new RTC class driver framework, working with
 23 * clocks that will often not be clones of what the PC-AT had.
 24 * Use the command line to specify another RTC if you need one.
 25 */
 26static const char default_rtc[] = "/dev/rtc0";
 27
 28int main(int argc, char **argv)
 29{
 30	int i, fd, retval, irqcount = 0;
 31	unsigned long tmp, data, old_pie_rate;
 32	const char *rtc = default_rtc;
 33	struct timeval start, end, diff;
 34
 35	switch (argc) {
 36	case 2:
 37		rtc = argv[1];
 38		/* FALLTHROUGH */
 39	case 1:
 40		break;
 41	default:
 42		fprintf(stderr, "usage:  rtctest [rtcdev] [d]\n");
 43		return 1;
 44	}
 45
 46	fd = open(rtc, O_RDONLY);
 47
 48	if (fd ==  -1) {
 49		perror(rtc);
 50		exit(errno);
 51	}
 52
 53	/* Read periodic IRQ rate */
 54	retval = ioctl(fd, RTC_IRQP_READ, &old_pie_rate);
 55	if (retval == -1) {
 56		/* not all RTCs support periodic IRQs */
 57		if (errno == EINVAL) {
 58			fprintf(stderr, "\nNo periodic IRQ support\n");
 59			goto done;
 60		}
 61		perror("RTC_IRQP_READ ioctl");
 62		exit(errno);
 63	}
 64	fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", old_pie_rate);
 65
 66	fprintf(stderr, "Counting 20 interrupts at:");
 67	fflush(stderr);
 68
 69	/* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
 70	for (tmp=2; tmp<=64; tmp*=2) {
 71
 72		retval = ioctl(fd, RTC_IRQP_SET, tmp);
 73		if (retval == -1) {
 74			/* not all RTCs can change their periodic IRQ rate */
 75			if (errno == EINVAL) {
 76				fprintf(stderr,
 77					"\n...Periodic IRQ rate is fixed\n");
 78				goto done;
 79			}
 80			perror("RTC_IRQP_SET ioctl");
 81			exit(errno);
 82		}
 83
 84		fprintf(stderr, "\n%ldHz:\t", tmp);
 85		fflush(stderr);
 86
 87		/* Enable periodic interrupts */
 88		retval = ioctl(fd, RTC_PIE_ON, 0);
 89		if (retval == -1) {
 90			perror("RTC_PIE_ON ioctl");
 91			exit(errno);
 92		}
 93
 94		for (i=1; i<21; i++) {
 95			gettimeofday(&start, NULL);
 96			/* This blocks */
 97			retval = read(fd, &data, sizeof(unsigned long));
 98			if (retval == -1) {
 99				perror("read");
100				exit(errno);
101			}
102			gettimeofday(&end, NULL);
103			timersub(&end, &start, &diff);
104			if (diff.tv_sec > 0 ||
105			    diff.tv_usec > ((1000000L / tmp) * 1.10)) {
106				fprintf(stderr, "\nPIE delta error: %ld.%06ld should be close to 0.%06ld\n",
107				       diff.tv_sec, diff.tv_usec,
108				       (1000000L / tmp));
109				fflush(stdout);
110				exit(-1);
111			}
112
113			fprintf(stderr, " %d",i);
114			fflush(stderr);
115			irqcount++;
116		}
117
118		/* Disable periodic interrupts */
119		retval = ioctl(fd, RTC_PIE_OFF, 0);
120		if (retval == -1) {
121			perror("RTC_PIE_OFF ioctl");
122			exit(errno);
123		}
124	}
125
126done:
127	ioctl(fd, RTC_IRQP_SET, old_pie_rate);
128
129	fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
130
131	close(fd);
132
133	return 0;
134}