Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Real Time Clock Driver Test Program
  4 *
  5 * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com>
  6 */
  7
  8#include <errno.h>
  9#include <fcntl.h>
 10#include <linux/rtc.h>
 11#include <stdio.h>
 12#include <stdlib.h>
 13#include <sys/ioctl.h>
 14#include <sys/time.h>
 15#include <sys/types.h>
 16#include <time.h>
 17#include <unistd.h>
 18
 19#include "../kselftest_harness.h"
 20
 21#define NUM_UIE 3
 22#define ALARM_DELTA 3
 23#define READ_LOOP_DURATION_SEC 30
 24#define READ_LOOP_SLEEP_MS 11
 25
 26static char *rtc_file = "/dev/rtc0";
 27
 28enum rtc_alarm_state {
 29	RTC_ALARM_UNKNOWN,
 30	RTC_ALARM_ENABLED,
 31	RTC_ALARM_DISABLED,
 32};
 33
 34FIXTURE(rtc) {
 35	int fd;
 36};
 37
 38FIXTURE_SETUP(rtc) {
 39	self->fd = open(rtc_file, O_RDONLY);
 40}
 41
 42FIXTURE_TEARDOWN(rtc) {
 43	close(self->fd);
 44}
 45
 46TEST_F(rtc, date_read) {
 47	int rc;
 48	struct rtc_time rtc_tm;
 49
 50	if (self->fd == -1 && errno == ENOENT)
 51		SKIP(return, "Skipping test since %s does not exist", rtc_file);
 52	ASSERT_NE(-1, self->fd);
 53
 54	/* Read the RTC time/date */
 55	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
 56	ASSERT_NE(-1, rc);
 57
 58	TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
 59	       rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
 60	       rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
 61}
 62
 63static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
 64{
 65	struct tm tm_time = {
 66	       .tm_sec = rtc_time->tm_sec,
 67	       .tm_min = rtc_time->tm_min,
 68	       .tm_hour = rtc_time->tm_hour,
 69	       .tm_mday = rtc_time->tm_mday,
 70	       .tm_mon = rtc_time->tm_mon,
 71	       .tm_year = rtc_time->tm_year,
 72	};
 73
 74	return mktime(&tm_time);
 75}
 76
 77static void nanosleep_with_retries(long ns)
 78{
 79	struct timespec req = {
 80		.tv_sec = 0,
 81		.tv_nsec = ns,
 82	};
 83	struct timespec rem;
 84
 85	while (nanosleep(&req, &rem) != 0) {
 86		req.tv_sec = rem.tv_sec;
 87		req.tv_nsec = rem.tv_nsec;
 88	}
 89}
 90
 91static enum rtc_alarm_state get_rtc_alarm_state(int fd)
 92{
 93	struct rtc_param param = { 0 };
 94	int rc;
 95
 96	/* Validate kernel reflects unsupported RTC alarm state */
 97	param.param = RTC_PARAM_FEATURES;
 98	param.index = 0;
 99	rc = ioctl(fd, RTC_PARAM_GET, &param);
100	if (rc < 0)
101		return RTC_ALARM_UNKNOWN;
102
103	if ((param.uvalue & _BITUL(RTC_FEATURE_ALARM)) == 0)
104		return RTC_ALARM_DISABLED;
105
106	return RTC_ALARM_ENABLED;
107}
108
109TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
110	int rc;
111	long iter_count = 0;
112	struct rtc_time rtc_tm;
113	time_t start_rtc_read, prev_rtc_read;
114
115	if (self->fd == -1 && errno == ENOENT)
116		SKIP(return, "Skipping test since %s does not exist", rtc_file);
117	ASSERT_NE(-1, self->fd);
118
119	TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
120	       READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
121
122	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
123	ASSERT_NE(-1, rc);
124	start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
125	prev_rtc_read = start_rtc_read;
126
127	do  {
128		time_t rtc_read;
129
130		rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
131		ASSERT_NE(-1, rc);
132
133		rtc_read = rtc_time_to_timestamp(&rtc_tm);
134		/* Time should not go backwards */
135		ASSERT_LE(prev_rtc_read, rtc_read);
136		/* Time should not increase more then 1s at a time */
137		ASSERT_GE(prev_rtc_read + 1, rtc_read);
138
139		/* Sleep 11ms to avoid killing / overheating the RTC */
140		nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
141
142		prev_rtc_read = rtc_read;
143		iter_count++;
144	} while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
145
146	TH_LOG("Performed %ld RTC time reads.", iter_count);
147}
148
149TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
150	int i, rc, irq = 0;
151	unsigned long data;
152
153	if (self->fd == -1 && errno == ENOENT)
154		SKIP(return, "Skipping test since %s does not exist", rtc_file);
155	ASSERT_NE(-1, self->fd);
156
157	/* Turn on update interrupts */
158	rc = ioctl(self->fd, RTC_UIE_ON, 0);
159	if (rc == -1) {
160		ASSERT_EQ(EINVAL, errno);
161		TH_LOG("skip update IRQs not supported.");
162		return;
163	}
164
165	for (i = 0; i < NUM_UIE; i++) {
166		/* This read will block */
167		rc = read(self->fd, &data, sizeof(data));
168		ASSERT_NE(-1, rc);
169		irq++;
170	}
171
172	EXPECT_EQ(NUM_UIE, irq);
173
174	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
175	ASSERT_NE(-1, rc);
176}
177
178TEST_F(rtc, uie_select) {
179	int i, rc, irq = 0;
180	unsigned long data;
181
182	if (self->fd == -1 && errno == ENOENT)
183		SKIP(return, "Skipping test since %s does not exist", rtc_file);
184	ASSERT_NE(-1, self->fd);
185
186	/* Turn on update interrupts */
187	rc = ioctl(self->fd, RTC_UIE_ON, 0);
188	if (rc == -1) {
189		ASSERT_EQ(EINVAL, errno);
190		TH_LOG("skip update IRQs not supported.");
191		return;
192	}
193
194	for (i = 0; i < NUM_UIE; i++) {
195		struct timeval tv = { .tv_sec = 2 };
196		fd_set readfds;
197
198		FD_ZERO(&readfds);
199		FD_SET(self->fd, &readfds);
200		/* The select will wait until an RTC interrupt happens. */
201		rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
202		ASSERT_NE(-1, rc);
203		ASSERT_NE(0, rc);
204
205		/* This read won't block */
206		rc = read(self->fd, &data, sizeof(unsigned long));
207		ASSERT_NE(-1, rc);
208		irq++;
209	}
210
211	EXPECT_EQ(NUM_UIE, irq);
212
213	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
214	ASSERT_NE(-1, rc);
215}
216
217TEST_F(rtc, alarm_alm_set) {
218	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
219	unsigned long data;
220	struct rtc_time tm;
221	fd_set readfds;
222	time_t secs, new;
223	int rc;
224	enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
225
226	if (self->fd == -1 && errno == ENOENT)
227		SKIP(return, "Skipping test since %s does not exist", rtc_file);
228	ASSERT_NE(-1, self->fd);
229
230	alarm_state = get_rtc_alarm_state(self->fd);
231	if (alarm_state == RTC_ALARM_DISABLED)
232		SKIP(return, "Skipping test since alarms are not supported.");
233
234	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
235	ASSERT_NE(-1, rc);
236
237	secs = timegm((struct tm *)&tm) + ALARM_DELTA;
238	gmtime_r(&secs, (struct tm *)&tm);
239
240	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
241	if (rc == -1) {
242		/*
243		 * Report error if rtc alarm was enabled. Fallback to check ioctl
244		 * error number if rtc alarm state is unknown.
245		 */
246		ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
247		ASSERT_EQ(EINVAL, errno);
248		TH_LOG("skip alarms are not supported.");
249		return;
250	}
251
252	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
253	ASSERT_NE(-1, rc);
254
255	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
256	       tm.tm_hour, tm.tm_min, tm.tm_sec);
257
258	/* Enable alarm interrupts */
259	rc = ioctl(self->fd, RTC_AIE_ON, 0);
260	ASSERT_NE(-1, rc);
261
262	FD_ZERO(&readfds);
263	FD_SET(self->fd, &readfds);
264
265	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
266	ASSERT_NE(-1, rc);
267	ASSERT_NE(0, rc);
268
269	/* Disable alarm interrupts */
270	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
271	ASSERT_NE(-1, rc);
272
273	rc = read(self->fd, &data, sizeof(unsigned long));
274	ASSERT_NE(-1, rc);
275	TH_LOG("data: %lx", data);
276
277	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
278	ASSERT_NE(-1, rc);
279
280	new = timegm((struct tm *)&tm);
281	ASSERT_EQ(new, secs);
282}
283
284TEST_F(rtc, alarm_wkalm_set) {
285	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
286	struct rtc_wkalrm alarm = { 0 };
287	struct rtc_time tm;
288	unsigned long data;
289	fd_set readfds;
290	time_t secs, new;
291	int rc;
292	enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
293
294	if (self->fd == -1 && errno == ENOENT)
295		SKIP(return, "Skipping test since %s does not exist", rtc_file);
296	ASSERT_NE(-1, self->fd);
297
298	alarm_state = get_rtc_alarm_state(self->fd);
299	if (alarm_state == RTC_ALARM_DISABLED)
300		SKIP(return, "Skipping test since alarms are not supported.");
301
302	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
303	ASSERT_NE(-1, rc);
304
305	secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
306	gmtime_r(&secs, (struct tm *)&alarm.time);
307
308	alarm.enabled = 1;
309
310	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
311	if (rc == -1) {
312		/*
313		 * Report error if rtc alarm was enabled. Fallback to check ioctl
314		 * error number if rtc alarm state is unknown.
315		 */
316		ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
317		ASSERT_EQ(EINVAL, errno);
318		TH_LOG("skip alarms are not supported.");
319		return;
320	}
321
322	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
323	ASSERT_NE(-1, rc);
324
325	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
326	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
327	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
328	       alarm.time.tm_min, alarm.time.tm_sec);
329
330	FD_ZERO(&readfds);
331	FD_SET(self->fd, &readfds);
332
333	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
334	ASSERT_NE(-1, rc);
335	ASSERT_NE(0, rc);
336
337	rc = read(self->fd, &data, sizeof(unsigned long));
338	ASSERT_NE(-1, rc);
339
340	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
341	ASSERT_NE(-1, rc);
342
343	new = timegm((struct tm *)&tm);
344	ASSERT_EQ(new, secs);
345}
346
347TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
348	struct timeval tv = { .tv_sec = 62 };
349	unsigned long data;
350	struct rtc_time tm;
351	fd_set readfds;
352	time_t secs, new;
353	int rc;
354	enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
355
356	if (self->fd == -1 && errno == ENOENT)
357		SKIP(return, "Skipping test since %s does not exist", rtc_file);
358	ASSERT_NE(-1, self->fd);
359
360	alarm_state = get_rtc_alarm_state(self->fd);
361	if (alarm_state == RTC_ALARM_DISABLED)
362		SKIP(return, "Skipping test since alarms are not supported.");
363
364	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
365	ASSERT_NE(-1, rc);
366
367	secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
368	gmtime_r(&secs, (struct tm *)&tm);
369
370	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
371	if (rc == -1) {
372		/*
373		 * Report error if rtc alarm was enabled. Fallback to check ioctl
374		 * error number if rtc alarm state is unknown.
375		 */
376		ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
377		ASSERT_EQ(EINVAL, errno);
378		TH_LOG("skip alarms are not supported.");
379		return;
380	}
381
382	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
383	ASSERT_NE(-1, rc);
384
385	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
386	       tm.tm_hour, tm.tm_min, tm.tm_sec);
387
388	/* Enable alarm interrupts */
389	rc = ioctl(self->fd, RTC_AIE_ON, 0);
390	ASSERT_NE(-1, rc);
391
392	FD_ZERO(&readfds);
393	FD_SET(self->fd, &readfds);
394
395	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
396	ASSERT_NE(-1, rc);
397	ASSERT_NE(0, rc);
398
399	/* Disable alarm interrupts */
400	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
401	ASSERT_NE(-1, rc);
402
403	rc = read(self->fd, &data, sizeof(unsigned long));
404	ASSERT_NE(-1, rc);
405	TH_LOG("data: %lx", data);
406
407	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
408	ASSERT_NE(-1, rc);
409
410	new = timegm((struct tm *)&tm);
411	ASSERT_EQ(new, secs);
412}
413
414TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
415	struct timeval tv = { .tv_sec = 62 };
416	struct rtc_wkalrm alarm = { 0 };
417	struct rtc_time tm;
418	unsigned long data;
419	fd_set readfds;
420	time_t secs, new;
421	int rc;
422	enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
423
424	if (self->fd == -1 && errno == ENOENT)
425		SKIP(return, "Skipping test since %s does not exist", rtc_file);
426	ASSERT_NE(-1, self->fd);
427
428	alarm_state = get_rtc_alarm_state(self->fd);
429	if (alarm_state == RTC_ALARM_DISABLED)
430		SKIP(return, "Skipping test since alarms are not supported.");
431
432	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
433	ASSERT_NE(-1, rc);
434
435	secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
436	gmtime_r(&secs, (struct tm *)&alarm.time);
437
438	alarm.enabled = 1;
439
440	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
441	if (rc == -1) {
442		/*
443		 * Report error if rtc alarm was enabled. Fallback to check ioctl
444		 * error number if rtc alarm state is unknown.
445		 */
446		ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
447		ASSERT_EQ(EINVAL, errno);
448		TH_LOG("skip alarms are not supported.");
449		return;
450	}
451
452	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
453	ASSERT_NE(-1, rc);
454
455	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
456	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
457	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
458	       alarm.time.tm_min, alarm.time.tm_sec);
459
460	FD_ZERO(&readfds);
461	FD_SET(self->fd, &readfds);
462
463	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
464	ASSERT_NE(-1, rc);
465	ASSERT_NE(0, rc);
466
467	rc = read(self->fd, &data, sizeof(unsigned long));
468	ASSERT_NE(-1, rc);
469
470	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
471	ASSERT_NE(-1, rc);
472
473	new = timegm((struct tm *)&tm);
474	ASSERT_EQ(new, secs);
475}
476
477int main(int argc, char **argv)
 
478{
479	int ret = -1;
 
 
480
 
 
481	switch (argc) {
482	case 2:
483		rtc_file = argv[1];
484		/* FALLTHROUGH */
485	case 1:
486		break;
487	default:
488		fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
489		return 1;
490	}
491
492	/* Run the test if rtc_file is accessible */
493	if (access(rtc_file, R_OK) == 0)
494		ret = test_harness_run(argc, argv);
495	else
496		ksft_exit_skip("[SKIP]: Cannot access rtc file %s - Exiting\n",
497						rtc_file);
498
499	return ret;
500}
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Real Time Clock Driver Test Program
  4 *
  5 * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com>
  6 */
  7
  8#include <errno.h>
  9#include <fcntl.h>
 10#include <linux/rtc.h>
 11#include <stdio.h>
 12#include <stdlib.h>
 13#include <sys/ioctl.h>
 14#include <sys/time.h>
 15#include <sys/types.h>
 16#include <time.h>
 17#include <unistd.h>
 18
 19#include "../kselftest_harness.h"
 20
 21#define NUM_UIE 3
 22#define ALARM_DELTA 3
 23#define READ_LOOP_DURATION_SEC 30
 24#define READ_LOOP_SLEEP_MS 11
 25
 26static char *rtc_file = "/dev/rtc0";
 27
 
 
 
 
 
 
 28FIXTURE(rtc) {
 29	int fd;
 30};
 31
 32FIXTURE_SETUP(rtc) {
 33	self->fd = open(rtc_file, O_RDONLY);
 34}
 35
 36FIXTURE_TEARDOWN(rtc) {
 37	close(self->fd);
 38}
 39
 40TEST_F(rtc, date_read) {
 41	int rc;
 42	struct rtc_time rtc_tm;
 43
 44	if (self->fd == -1 && errno == ENOENT)
 45		SKIP(return, "Skipping test since %s does not exist", rtc_file);
 46	ASSERT_NE(-1, self->fd);
 47
 48	/* Read the RTC time/date */
 49	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
 50	ASSERT_NE(-1, rc);
 51
 52	TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
 53	       rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
 54	       rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
 55}
 56
 57static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
 58{
 59	struct tm tm_time = {
 60	       .tm_sec = rtc_time->tm_sec,
 61	       .tm_min = rtc_time->tm_min,
 62	       .tm_hour = rtc_time->tm_hour,
 63	       .tm_mday = rtc_time->tm_mday,
 64	       .tm_mon = rtc_time->tm_mon,
 65	       .tm_year = rtc_time->tm_year,
 66	};
 67
 68	return mktime(&tm_time);
 69}
 70
 71static void nanosleep_with_retries(long ns)
 72{
 73	struct timespec req = {
 74		.tv_sec = 0,
 75		.tv_nsec = ns,
 76	};
 77	struct timespec rem;
 78
 79	while (nanosleep(&req, &rem) != 0) {
 80		req.tv_sec = rem.tv_sec;
 81		req.tv_nsec = rem.tv_nsec;
 82	}
 83}
 84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 85TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
 86	int rc;
 87	long iter_count = 0;
 88	struct rtc_time rtc_tm;
 89	time_t start_rtc_read, prev_rtc_read;
 90
 91	if (self->fd == -1 && errno == ENOENT)
 92		SKIP(return, "Skipping test since %s does not exist", rtc_file);
 93	ASSERT_NE(-1, self->fd);
 94
 95	TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
 96	       READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
 97
 98	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
 99	ASSERT_NE(-1, rc);
100	start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
101	prev_rtc_read = start_rtc_read;
102
103	do  {
104		time_t rtc_read;
105
106		rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
107		ASSERT_NE(-1, rc);
108
109		rtc_read = rtc_time_to_timestamp(&rtc_tm);
110		/* Time should not go backwards */
111		ASSERT_LE(prev_rtc_read, rtc_read);
112		/* Time should not increase more then 1s at a time */
113		ASSERT_GE(prev_rtc_read + 1, rtc_read);
114
115		/* Sleep 11ms to avoid killing / overheating the RTC */
116		nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
117
118		prev_rtc_read = rtc_read;
119		iter_count++;
120	} while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
121
122	TH_LOG("Performed %ld RTC time reads.", iter_count);
123}
124
125TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
126	int i, rc, irq = 0;
127	unsigned long data;
128
129	if (self->fd == -1 && errno == ENOENT)
130		SKIP(return, "Skipping test since %s does not exist", rtc_file);
131	ASSERT_NE(-1, self->fd);
132
133	/* Turn on update interrupts */
134	rc = ioctl(self->fd, RTC_UIE_ON, 0);
135	if (rc == -1) {
136		ASSERT_EQ(EINVAL, errno);
137		TH_LOG("skip update IRQs not supported.");
138		return;
139	}
140
141	for (i = 0; i < NUM_UIE; i++) {
142		/* This read will block */
143		rc = read(self->fd, &data, sizeof(data));
144		ASSERT_NE(-1, rc);
145		irq++;
146	}
147
148	EXPECT_EQ(NUM_UIE, irq);
149
150	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
151	ASSERT_NE(-1, rc);
152}
153
154TEST_F(rtc, uie_select) {
155	int i, rc, irq = 0;
156	unsigned long data;
157
158	if (self->fd == -1 && errno == ENOENT)
159		SKIP(return, "Skipping test since %s does not exist", rtc_file);
160	ASSERT_NE(-1, self->fd);
161
162	/* Turn on update interrupts */
163	rc = ioctl(self->fd, RTC_UIE_ON, 0);
164	if (rc == -1) {
165		ASSERT_EQ(EINVAL, errno);
166		TH_LOG("skip update IRQs not supported.");
167		return;
168	}
169
170	for (i = 0; i < NUM_UIE; i++) {
171		struct timeval tv = { .tv_sec = 2 };
172		fd_set readfds;
173
174		FD_ZERO(&readfds);
175		FD_SET(self->fd, &readfds);
176		/* The select will wait until an RTC interrupt happens. */
177		rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
178		ASSERT_NE(-1, rc);
179		ASSERT_NE(0, rc);
180
181		/* This read won't block */
182		rc = read(self->fd, &data, sizeof(unsigned long));
183		ASSERT_NE(-1, rc);
184		irq++;
185	}
186
187	EXPECT_EQ(NUM_UIE, irq);
188
189	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
190	ASSERT_NE(-1, rc);
191}
192
193TEST_F(rtc, alarm_alm_set) {
194	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
195	unsigned long data;
196	struct rtc_time tm;
197	fd_set readfds;
198	time_t secs, new;
199	int rc;
 
200
201	if (self->fd == -1 && errno == ENOENT)
202		SKIP(return, "Skipping test since %s does not exist", rtc_file);
203	ASSERT_NE(-1, self->fd);
204
 
 
 
 
205	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
206	ASSERT_NE(-1, rc);
207
208	secs = timegm((struct tm *)&tm) + ALARM_DELTA;
209	gmtime_r(&secs, (struct tm *)&tm);
210
211	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
212	if (rc == -1) {
 
 
 
 
 
213		ASSERT_EQ(EINVAL, errno);
214		TH_LOG("skip alarms are not supported.");
215		return;
216	}
217
218	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
219	ASSERT_NE(-1, rc);
220
221	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
222	       tm.tm_hour, tm.tm_min, tm.tm_sec);
223
224	/* Enable alarm interrupts */
225	rc = ioctl(self->fd, RTC_AIE_ON, 0);
226	ASSERT_NE(-1, rc);
227
228	FD_ZERO(&readfds);
229	FD_SET(self->fd, &readfds);
230
231	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
232	ASSERT_NE(-1, rc);
233	ASSERT_NE(0, rc);
234
235	/* Disable alarm interrupts */
236	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
237	ASSERT_NE(-1, rc);
238
239	rc = read(self->fd, &data, sizeof(unsigned long));
240	ASSERT_NE(-1, rc);
241	TH_LOG("data: %lx", data);
242
243	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
244	ASSERT_NE(-1, rc);
245
246	new = timegm((struct tm *)&tm);
247	ASSERT_EQ(new, secs);
248}
249
250TEST_F(rtc, alarm_wkalm_set) {
251	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
252	struct rtc_wkalrm alarm = { 0 };
253	struct rtc_time tm;
254	unsigned long data;
255	fd_set readfds;
256	time_t secs, new;
257	int rc;
 
258
259	if (self->fd == -1 && errno == ENOENT)
260		SKIP(return, "Skipping test since %s does not exist", rtc_file);
261	ASSERT_NE(-1, self->fd);
262
 
 
 
 
263	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
264	ASSERT_NE(-1, rc);
265
266	secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
267	gmtime_r(&secs, (struct tm *)&alarm.time);
268
269	alarm.enabled = 1;
270
271	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
272	if (rc == -1) {
 
 
 
 
 
273		ASSERT_EQ(EINVAL, errno);
274		TH_LOG("skip alarms are not supported.");
275		return;
276	}
277
278	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
279	ASSERT_NE(-1, rc);
280
281	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
282	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
283	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
284	       alarm.time.tm_min, alarm.time.tm_sec);
285
286	FD_ZERO(&readfds);
287	FD_SET(self->fd, &readfds);
288
289	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
290	ASSERT_NE(-1, rc);
291	ASSERT_NE(0, rc);
292
293	rc = read(self->fd, &data, sizeof(unsigned long));
294	ASSERT_NE(-1, rc);
295
296	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
297	ASSERT_NE(-1, rc);
298
299	new = timegm((struct tm *)&tm);
300	ASSERT_EQ(new, secs);
301}
302
303TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
304	struct timeval tv = { .tv_sec = 62 };
305	unsigned long data;
306	struct rtc_time tm;
307	fd_set readfds;
308	time_t secs, new;
309	int rc;
 
310
311	if (self->fd == -1 && errno == ENOENT)
312		SKIP(return, "Skipping test since %s does not exist", rtc_file);
313	ASSERT_NE(-1, self->fd);
314
 
 
 
 
315	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
316	ASSERT_NE(-1, rc);
317
318	secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
319	gmtime_r(&secs, (struct tm *)&tm);
320
321	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
322	if (rc == -1) {
 
 
 
 
 
323		ASSERT_EQ(EINVAL, errno);
324		TH_LOG("skip alarms are not supported.");
325		return;
326	}
327
328	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
329	ASSERT_NE(-1, rc);
330
331	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
332	       tm.tm_hour, tm.tm_min, tm.tm_sec);
333
334	/* Enable alarm interrupts */
335	rc = ioctl(self->fd, RTC_AIE_ON, 0);
336	ASSERT_NE(-1, rc);
337
338	FD_ZERO(&readfds);
339	FD_SET(self->fd, &readfds);
340
341	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
342	ASSERT_NE(-1, rc);
343	ASSERT_NE(0, rc);
344
345	/* Disable alarm interrupts */
346	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
347	ASSERT_NE(-1, rc);
348
349	rc = read(self->fd, &data, sizeof(unsigned long));
350	ASSERT_NE(-1, rc);
351	TH_LOG("data: %lx", data);
352
353	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
354	ASSERT_NE(-1, rc);
355
356	new = timegm((struct tm *)&tm);
357	ASSERT_EQ(new, secs);
358}
359
360TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
361	struct timeval tv = { .tv_sec = 62 };
362	struct rtc_wkalrm alarm = { 0 };
363	struct rtc_time tm;
364	unsigned long data;
365	fd_set readfds;
366	time_t secs, new;
367	int rc;
 
368
369	if (self->fd == -1 && errno == ENOENT)
370		SKIP(return, "Skipping test since %s does not exist", rtc_file);
371	ASSERT_NE(-1, self->fd);
372
 
 
 
 
373	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
374	ASSERT_NE(-1, rc);
375
376	secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
377	gmtime_r(&secs, (struct tm *)&alarm.time);
378
379	alarm.enabled = 1;
380
381	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
382	if (rc == -1) {
 
 
 
 
 
383		ASSERT_EQ(EINVAL, errno);
384		TH_LOG("skip alarms are not supported.");
385		return;
386	}
387
388	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
389	ASSERT_NE(-1, rc);
390
391	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
392	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
393	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
394	       alarm.time.tm_min, alarm.time.tm_sec);
395
396	FD_ZERO(&readfds);
397	FD_SET(self->fd, &readfds);
398
399	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
400	ASSERT_NE(-1, rc);
401	ASSERT_NE(0, rc);
402
403	rc = read(self->fd, &data, sizeof(unsigned long));
404	ASSERT_NE(-1, rc);
405
406	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
407	ASSERT_NE(-1, rc);
408
409	new = timegm((struct tm *)&tm);
410	ASSERT_EQ(new, secs);
411}
412
413static void __attribute__((constructor))
414__constructor_order_last(void)
415{
416	if (!__constructor_order)
417		__constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
418}
419
420int main(int argc, char **argv)
421{
422	switch (argc) {
423	case 2:
424		rtc_file = argv[1];
425		/* FALLTHROUGH */
426	case 1:
427		break;
428	default:
429		fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
430		return 1;
431	}
432
433	return test_harness_run(argc, argv);
 
 
 
 
 
 
 
434}