[PATCH] wakealarm: use ioctl() interface as this more of a generic interface

Colin King colin.king at canonical.com
Mon Oct 28 17:36:15 UTC 2013


From: Colin Ian King <colin.king at canonical.com>

This test fails on non-x86 architectures, so use the more generic ioctl
alarm interface instead.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 src/acpi/wakealarm/wakealarm.c   |  18 ++---
 src/lib/include/fwts_wakealarm.h |   5 +-
 src/lib/src/fwts_wakealarm.c     | 159 ++++++++++++++++++++++++++++++---------
 3 files changed, 132 insertions(+), 50 deletions(-)

diff --git a/src/acpi/wakealarm/wakealarm.c b/src/acpi/wakealarm/wakealarm.c
index 7f4886a..1176be0 100644
--- a/src/acpi/wakealarm/wakealarm.c
+++ b/src/acpi/wakealarm/wakealarm.c
@@ -25,27 +25,23 @@
 #include <unistd.h>
 #include <string.h>
 
-static const char *wkalarm = WAKEALARM;
-
 static int wakealarm_test1(fwts_framework *fw)
 {
-	struct stat buf;
-
-	if (stat(wkalarm, &buf) == 0)
-		fwts_passed(fw, WAKEALARM " found.");
+	if (fwts_wakealarm_exits(fw) == FWTS_OK)
+		fwts_passed(fw, "RTC with a RTC alarm ioctl() interface found.");
 	else {
 		fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoWakeAlarmTest1",
-			"Could not find " WAKEALARM ".");
+			"Could not find an RTC with an alarm ioctl() interface.");
 #ifdef FWTS_ARCH_INTEL
 		/* For x86 devices, this is considered a failure */
 		fwts_advice(fw,
 			"x86 devices generally should have an RTC wake alarm that "
-			"is normally controlled by the " WAKEALARM " interface. This interface "
+			"is normally controlled by the RTC alarm ioctl() interface. This interface "
 			"does not exist, so the wake alarm tests will be aborted.");
 #else
 		fwts_advice(fw,
 			"non-x86 devices sometimes do not have an RTC wake alarm that "
-			"is normally controlled by the " WAKEALARM " interface. This "
+			"is normally controlled by the RTC alarm ioctl() interface. This "
 			"interface does not exist, so the wake alarm tests will be aborted.");
 #endif
 		return FWTS_ABORTED;
@@ -64,6 +60,8 @@ static int wakealarm_test2(fwts_framework *fw)
 		return FWTS_OK;
 	}
 
+	(void)fwts_wakealarm_cancel(fw);
+
 	fwts_passed(fw, "RTC wakealarm was triggered successfully.");
 
 	return FWTS_OK;
@@ -122,7 +120,7 @@ static int wakealarm_test4(fwts_framework *fw)
 }
 
 static fwts_framework_minor_test wakealarm_tests[] = {
-	{ wakealarm_test1, "Check existence of " WAKEALARM "." },
+	{ wakealarm_test1, "Check existence of RTC with alarm interface." },
 	{ wakealarm_test2, "Trigger wakealarm for 1 seconds in the future." },
 	{ wakealarm_test3, "Check if wakealarm is fired." },
 	{ wakealarm_test4, "Multiple wakealarm firing tests." },
diff --git a/src/lib/include/fwts_wakealarm.h b/src/lib/include/fwts_wakealarm.h
index df95e41..b4994fd 100644
--- a/src/lib/include/fwts_wakealarm.h
+++ b/src/lib/include/fwts_wakealarm.h
@@ -22,10 +22,9 @@
 
 #include "fwts_framework.h"
 
-#define WAKEALARM "/sys/class/rtc/rtc0/wakealarm"
-
-int fwts_wakealarm_get_irq_state(void);
+int fwts_wakealarm_exits(fwts_framework *fw);
 int fwts_wakealarm_test_firing(fwts_framework *fw, const int sleep);
 int fwts_wakealarm_trigger(fwts_framework *fw, const int seconds);
+int fwts_wakealarm_cancel(fwts_framework *fw);
 
 #endif
diff --git a/src/lib/src/fwts_wakealarm.c b/src/lib/src/fwts_wakealarm.c
index f22ce4c..a2573b3 100644
--- a/src/lib/src/fwts_wakealarm.c
+++ b/src/lib/src/fwts_wakealarm.c
@@ -18,38 +18,42 @@
  */
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
 #include <unistd.h>
 #include <string.h>
+#include <fcntl.h>
+#include <linux/rtc.h>
 
 #include "fwts.h"
 
-static char *fwts_wkalarm = "/sys/class/rtc/rtc0/wakealarm";
+static char *fwts_rtc = "/dev/rtc0";
 
 /*
- *  fwts_wakealarm_get_irq_state()
- *	get wakealarm IRQ state.  checks if alarm_IRQ exists and if
- *	it is set.
+ *  fwts_wakealarm_exits()
+ *	check that a RTC exists that supports minimal RTC alarm ioctl
  */
-int fwts_wakealarm_get_irq_state(void)
+int fwts_wakealarm_exits(fwts_framework *fw)
 {
-	FILE *fp;
-	char field[32];
-	char value[32];
+	int fd;
+	int ret = FWTS_OK;
+	struct rtc_time rtc_tm;
 
-	if ((fp = fopen("/proc/driver/rtc", "r")) == NULL)
+	if ((fd = open(fwts_rtc, O_RDWR)) < 0) {
+		fwts_log_error(fw, "Cannot access Real Time Clock device %s.", fwts_rtc);
 		return FWTS_ERROR;
+	}
 
-	while (fscanf(fp, "%s : %s\n", field, value) != EOF) {
-		if (!strcmp(field, "alarm_IRQ")) {
-			fclose(fp);
-			return strcmp(value, "no");
-		}
+	if (ioctl(fd, RTC_ALM_READ, &rtc_tm) < 0) {
+		fwts_log_error(fw, "Cannot read Real Time Clock with ioctl RTC_RD_TIME %s.", fwts_rtc);
+		ret = FWTS_ERROR;
 	}
-	fclose(fp);
+	(void)close(fd);
 
-	return FWTS_ERROR;
+	return ret;
 }
 
 /*
@@ -58,29 +62,110 @@ int fwts_wakealarm_get_irq_state(void)
  */
 int fwts_wakealarm_trigger(fwts_framework *fw, const int seconds)
 {
-	char buffer[32];
-	int ret;
-
-	snprintf(buffer, sizeof(buffer), "+%d", seconds);
+	int fd, ret = FWTS_OK;
+	struct rtc_time rtc_tm;
 
-	if (fwts_set("0", fwts_wkalarm)) {
-		fwts_log_error(fw, "Cannot write '0' to %s", fwts_wkalarm);
+	if ((fd = open(fwts_rtc, O_RDWR)) < 0) {
+		fwts_log_error(fw, "Cannot access Real Time Clock device %s.", fwts_rtc);
 		return FWTS_ERROR;
 	}
-	if (fwts_set(buffer, fwts_wkalarm)) {
-		fwts_log_error(fw, "Cannot write '%s' to %s", buffer, fwts_wkalarm);
-		return FWTS_ERROR;
+
+	if (ioctl(fd, RTC_RD_TIME, &rtc_tm) < 0) {
+		fwts_log_error(fw, "Cannot read Real Time Clock with ioctl RTC_RD_TIME %s.", fwts_rtc);
+		ret = FWTS_ERROR;
+		goto out;
 	}
-	if ((ret = fwts_wakealarm_get_irq_state()) == FWTS_ERROR)
+
+	rtc_tm.tm_sec += seconds;
+	if (rtc_tm.tm_sec >= 60) {
+		rtc_tm.tm_min += rtc_tm.tm_sec / 60;
+		rtc_tm.tm_sec %= 60;
+	}
+	if (rtc_tm.tm_min >= 60) {
+		rtc_tm.tm_hour += rtc_tm.tm_min / 60;
+		rtc_tm.tm_min %= 60;
+	}
+	if (rtc_tm.tm_hour >= 24) {
+		rtc_tm.tm_hour %= 24;
+	}
+	errno = 0;
+	if (ioctl(fd, RTC_ALM_SET, &rtc_tm) < 0) {
+		if (errno == ENOTTY) {
+			fwts_log_error(fw, "Real Time Clock device %s does not support alarm interrupts.", fwts_rtc);
+			ret = FWTS_ERROR;
+			goto out;
+		}
+	}
+	if (ioctl(fd, RTC_AIE_ON, 0) < 0) {
+		fwts_log_error(fw, "Cannot enable alarm interrupts on Real Time Clock device %s.", fwts_rtc);
+		ret = FWTS_ERROR;
+	}
+out:
+	(void)close(fd);
+
+	return ret;
+}
+
+int fwts_wakealarm_cancel(fwts_framework *fw)
+{
+	int fd, ret = FWTS_OK;
+
+	if ((fd = open(fwts_rtc, O_RDWR)) < 0) {
+		fwts_log_error(fw, "Cannot access Real Time Clock device %s.", fwts_rtc);
 		return FWTS_ERROR;
+	}
+
+	if (ioctl(fd, RTC_AIE_OFF, 0) < 0) {
+		fwts_log_error(fw, "Cannot read Real Time Clock with ioctl RTC_RD_TIME %s.", fwts_rtc);
+		ret = FWTS_ERROR;
+	}
+	(void)close(fd);
+
+	return ret;
+}
+
+/*
+ *  fwts_wakealarm_check_fired()
+ *	check if wakealarm fires
+ */
+int fwts_wakealarm_check_fired(fwts_framework *fw, const int seconds)
+{
+	int fd, rc, ret = FWTS_OK;
+	fd_set rfds;
+	struct timeval tv;
 
-	if (!fwts_wakealarm_get_irq_state()) {
-		fwts_log_error(fw, "Wakealarm %s did not get set", fwts_wkalarm);
+	if ((fd = open(fwts_rtc, O_RDWR)) < 0) {
+		fwts_log_error(fw, "Cannot access Real Time Clock device %s.", fwts_rtc);
 		return FWTS_ERROR;
 	}
-	return FWTS_OK;
+
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+
+	/* Wait for 1 second longer than the alarm */
+	tv.tv_sec = seconds + 1;
+	tv.tv_usec = 0;
+
+	/* Wait for data to be available or timeout */
+	rc = select(fd + 1, &rfds, NULL, NULL, &tv);
+	if (rc == -1) {
+		fwts_log_error(fw, "Select failed waitin for Real Time Clock device %s to fire.\n", fwts_rtc);
+		ret = FWTS_ERROR;
+		goto out;
+	}
+
+	/* Timed out, no data available, so alarm did not fire */
+	if (rc == 0) {
+		fwts_log_error(fw, "Wakealarm Real Time Clock device %s did not fire", fwts_rtc);
+		ret = FWTS_ERROR;
+	}
+out:
+	(void)close(fd);
+
+	return ret;
 }
 
+
 /*
  *  fwts_wakealarm_test_firing()
  *	test RTC wakealarm trigger and firing from 'seconds' seconds time
@@ -88,15 +173,15 @@ int fwts_wakealarm_trigger(fwts_framework *fw, const int seconds)
  */
 int fwts_wakealarm_test_firing(fwts_framework *fw, const int seconds)
 {
-	int ret;
+	int ret = FWTS_OK;
 
-	if ((ret = fwts_wakealarm_trigger(fw, seconds)) != FWTS_OK)
+	if (fwts_wakealarm_trigger(fw, seconds + 2) != FWTS_OK)
 		return FWTS_ERROR;
 
-	sleep(seconds+1);
-	if (fwts_wakealarm_get_irq_state() != FWTS_OK) {
-		fwts_log_error(fw, "Wakealarm %s did not fire", fwts_wkalarm);
-		return FWTS_ERROR;
-	}
-	return FWTS_OK;
+	if (fwts_wakealarm_check_fired(fw, seconds + 2) != FWTS_OK)
+		ret = FWTS_ERROR;
+
+	fwts_wakealarm_cancel(fw);
+
+	return ret;
 }
-- 
1.8.3.2




More information about the fwts-devel mailing list