1/*   rtc-test.c
2 *
3 *   Tests for the Real Time Clock driver.
4 *
5 *   Copyright (c) Larsen & Toubro Infotech Ltd., 2010
6 *   Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
7 *
8 *   Author : Silesh C V <Silesh.Vellattu@lntinfotech.com>
9 *
10 *   This program is free software;  you can redistribute it and/or modify
11 *   it under the terms of the GNU General Public License as published by
12 *   the Free Software Foundation; either version 2 of the License, or
13 *   (at your option) any later version.
14 *
15 *   This program is distributed in the hope that it will be useful,
16 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
18 *   the GNU General Public License for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with this program;  if not, write to the Free Software
22 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26#include <sys/ioctl.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <linux/rtc.h>
32#include <errno.h>
33#include <time.h>
34
35#include "test.h"
36#include "safe_macros.h"
37
38int rtc_fd = -1;
39char *TCID = "rtc01";
40int TST_TOTAL = 3;
41
42static char *rtc_dev = "/dev/rtc";
43static int dflag;
44static const option_t options[] = {
45	{"d:", &dflag, &rtc_dev},
46	{NULL, NULL, NULL}
47};
48
49static void help(void)
50{
51	printf("  -d x    rtc device node, default is %s\n",
52		rtc_dev);
53}
54
55/* Read and Alarm Tests :  Read test reads the Date/time from RTC
56 * while Alarm test, sets the alarm to 5 seconds in future and
57 * waits for it to ring.The ioctls tested in these tests are
58 * RTC_RD_TIME, RTC_ALM_SET, RTC_ALM_READ, RTC_AIE_OFF  */
59
60void read_alarm_test(void)
61{
62	struct rtc_time rtc_tm;
63	int ret;
64	unsigned long data;
65	fd_set rfds;
66	struct timeval tv;
67
68	tst_resm(TINFO, "RTC READ TEST:");
69
70	/*Read RTC Time */
71	ret = ioctl(rtc_fd, RTC_RD_TIME, &rtc_tm);
72	if (ret == -1) {
73		tst_resm(TFAIL | TERRNO, "RTC_RD_TIME ioctl failed");
74		return;
75	}
76
77	tst_resm(TPASS, "RTC READ TEST Passed");
78
79	tst_resm(TINFO, "Current RTC date/time is %d-%d-%d, %02d:%02d:%02d.",
80		 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
81		 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
82
83	tst_resm(TINFO, "RTC ALARM TEST :");
84
85	/*set Alarm to 5 Seconds */
86	rtc_tm.tm_sec += 5;
87	if (rtc_tm.tm_sec >= 60) {
88		rtc_tm.tm_sec %= 60;
89		rtc_tm.tm_min++;
90	}
91
92	if (rtc_tm.tm_min == 60) {
93		rtc_tm.tm_min = 0;
94		rtc_tm.tm_hour++;
95	}
96
97	if (rtc_tm.tm_hour == 24)
98		rtc_tm.tm_hour = 0;
99
100	ret = ioctl(rtc_fd, RTC_ALM_SET, &rtc_tm);
101	if (ret == -1) {
102		if (errno == EINVAL)
103			tst_resm(TCONF | TERRNO, "RTC_ALM_SET not supported");
104		else
105			tst_resm(TFAIL | TERRNO, "RTC_ALM_SET ioctl failed");
106		return;
107	}
108
109	/*Read current alarm time */
110	ret = ioctl(rtc_fd, RTC_ALM_READ, &rtc_tm);
111	if (ret == -1) {
112		if (errno == EINVAL) {
113			tst_resm(TCONF | TERRNO, "RTC_ALM_READ not suported");
114		} else {
115			tst_resm(TFAIL | TERRNO, "RTC_ALM_READ ioctl failed");
116			return;
117		}
118	} else {
119		tst_resm(TINFO, "Alarm time set to %02d:%02d:%02d.",
120			 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
121	}
122
123	/* Enable alarm interrupts */
124	ret = ioctl(rtc_fd, RTC_AIE_ON, 0);
125	if (ret == -1) {
126		tst_resm(TINFO | TERRNO, "RTC_AIE_ON ioctl failed");
127		return;
128	}
129
130	tst_resm(TINFO, "Waiting 5 seconds for the alarm...");
131
132	tv.tv_sec = 6;		/*set 6 seconds as the time out */
133	tv.tv_usec = 0;
134
135	FD_ZERO(&rfds);
136	FD_SET(rtc_fd, &rfds);
137
138	ret = select(rtc_fd + 1, &rfds, NULL, NULL, &tv);	/*wait for alarm */
139
140	if (ret == -1) {
141		tst_resm(TFAIL | TERRNO, "select failed");
142		return;
143	} else if (ret) {
144		ret = read(rtc_fd, &data, sizeof(unsigned long));
145		if (ret == -1) {
146			tst_resm(TFAIL | TERRNO, "read failed");
147			return;
148		}
149		tst_resm(TINFO, "Alarm rang.");
150	} else {
151		tst_resm(TFAIL, "Timed out waiting for the alarm");
152		return;
153	}
154
155	/* Disable alarm interrupts */
156	ret = ioctl(rtc_fd, RTC_AIE_OFF, 0);
157	if (ret == -1) {
158		tst_resm(TFAIL | TERRNO, "RTC_AIE_OFF ioctl failed");
159		return;
160	}
161	tst_resm(TPASS, "RTC ALARM TEST Passed");
162}
163
164/* Update_interrupts_test :Once the Update interrupts is enabled,
165 * the RTC gives interrupts (1/sec) on the interrupts line(if the rtc
166 * has one). This is tested by enabling the update interrupts
167 * and then waiting for 5 interrupts.*/
168
169void update_interrupts_test(void)
170{
171	int ret, i;
172	unsigned long data;
173	fd_set rfds;
174	struct timeval tv;
175
176	tst_resm(TINFO, "RTC UPDATE INTERRUPTS TEST :");
177	/*Turn on update interrupts */
178	ret = ioctl(rtc_fd, RTC_UIE_ON, 0);
179	if (ret == -1) {
180		if (errno == EINVAL)
181			tst_resm(TCONF | TERRNO, "RTC_UIE_ON not supported");
182		else
183			tst_resm(TFAIL | TERRNO, "RTC_UIE_ON ioctl failed");
184		return;
185	}
186
187	tst_resm(TINFO, "Waiting for  5 update interrupts...");
188	for (i = 1; i < 6; i++) {
189
190		tv.tv_sec = 2;	/*2 sec time out for each interrupt */
191		tv.tv_usec = 0;
192
193		FD_ZERO(&rfds);
194		FD_SET(rtc_fd, &rfds);
195
196		ret = select(rtc_fd + 1, &rfds, NULL, NULL, &tv);
197		if (ret == -1) {
198			tst_resm(TFAIL | TERRNO, "select failed");
199			return;
200		} else if (ret) {
201			ret = read(rtc_fd, &data, sizeof(unsigned long));
202			if (ret == -1) {
203				tst_resm(TFAIL | TERRNO, "read failed");
204				return;
205			}
206			tst_resm(TINFO, "Update interrupt %d", i);
207		} else {
208			tst_resm(TFAIL,
209				 "Timed out waiting for the update interrupt");
210			return;
211		}
212	}
213
214	/* Turn off update interrupts */
215	ret = ioctl(rtc_fd, RTC_UIE_OFF, 0);
216	if (ret == -1) {
217		tst_resm(TFAIL | TERRNO, "RTC_UIE_OFF ioctl failed");
218		return;
219	}
220	tst_resm(TPASS, "RTC UPDATE INTERRUPTS TEST Passed");
221}
222
223int main(int argc, char *argv[])
224{
225	tst_parse_opts(argc, argv, options, help);
226
227	tst_require_root();
228
229	if (access(rtc_dev, F_OK) == -1)
230		tst_brkm(TCONF, NULL, "couldn't find rtc device '%s'", rtc_dev);
231
232	rtc_fd = SAFE_OPEN(NULL, rtc_dev, O_RDONLY);
233
234	/*Read and alarm tests */
235	read_alarm_test();
236
237	/*Update interrupts test */
238	update_interrupts_test();
239
240	close(rtc_fd);
241
242	tst_resm(TINFO, "RTC Tests Done!");
243	tst_exit();
244}
245