[PATCH] hwclock: add support for RTC_VL_READ/RTC_VL_CLR ioctls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement a way for userspace to query the status of the backup
battery, if supported by the hardware and driver.

The RTC_VL_* bits are a somewhat recent addition (3431ca4837bf, but
really only from b0efe0281234) to the uapi header,
so provide our own definition if the build host's header doesn't.

Signed-off-by: Rasmus Villemoes <rasmus.villemoes@xxxxxxxxx>
---
 sys-utils/hwclock-rtc.c | 86 +++++++++++++++++++++++++++++++++++++++++
 sys-utils/hwclock.c     | 35 +++++++++++++++++
 sys-utils/hwclock.h     |  5 +++
 3 files changed, 126 insertions(+)

diff --git a/sys-utils/hwclock-rtc.c b/sys-utils/hwclock-rtc.c
index 7094cd063..f918272a1 100644
--- a/sys-utils/hwclock-rtc.c
+++ b/sys-utils/hwclock-rtc.c
@@ -518,3 +518,89 @@ done:
 	free(opt);
 	return rc;
 }
+
+#ifndef RTC_VL_DATA_INVALID
+#define RTC_VL_DATA_INVALID     0x1
+#endif
+#ifndef RTC_VL_BACKUP_LOW
+#define RTC_VL_BACKUP_LOW       0x2
+#endif
+#ifndef RTC_VL_BACKUP_EMPTY
+#define RTC_VL_BACKUP_EMPTY     0x4
+#endif
+#ifndef RTC_VL_ACCURACY_LOW
+#define RTC_VL_ACCURACY_LOW     0x8
+#endif
+#ifndef RTC_VL_BACKUP_SWITCH
+#define RTC_VL_BACKUP_SWITCH    0x10
+#endif
+
+int rtc_vl_read(const struct hwclock_control *ctl)
+{
+	unsigned int vl;
+	int rtc_fd;
+	size_t i;
+	static const struct vl_bit {
+		unsigned int bit;
+		const char *desc;
+	} vl_bits[] = {
+		{ RTC_VL_DATA_INVALID,  N_("Voltage too low, RTC data is invalid") },
+		{ RTC_VL_BACKUP_LOW,    N_("Backup voltage is low") },
+		{ RTC_VL_BACKUP_EMPTY,  N_("Backup empty or not present") },
+		{ RTC_VL_ACCURACY_LOW,  N_("Voltage is low, RTC accuracy is reduced") },
+		{ RTC_VL_BACKUP_SWITCH, N_("Backup switchover happened") },
+	};
+
+	rtc_fd = open_rtc(ctl);
+	if (rtc_fd < 0) {
+		warnx(_("cannot open %s"), rtc_dev_name);
+		return 1;
+	}
+
+	if (ioctl(rtc_fd, RTC_VL_READ, &vl) == -1) {
+		warn(_("ioctl(%d, RTC_VL_READ) on %s failed"),
+		     rtc_fd, rtc_dev_name);
+		return 1;
+	}
+
+	if (ctl->verbose) {
+		printf(_("ioctl(%d, RTC_VL_READ) on %s returned 0x%x\n"),
+		       rtc_fd, rtc_dev_name, vl);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vl_bits); ++i) {
+		const struct vl_bit *vlb = &vl_bits[i];
+
+		if (vl & vlb->bit) {
+			printf("0x%02x - %s\n", vlb->bit, vlb->desc);
+			vl &= ~vlb->bit;
+		}
+	}
+	if (vl)
+		printf("0x%02x - unknown bit(s)\n", vl);
+
+	return 0;
+}
+
+int rtc_vl_clear(const struct hwclock_control *ctl)
+{
+	int rtc_fd;
+
+	rtc_fd = open_rtc(ctl);
+	if (rtc_fd < 0) {
+		warnx(_("cannot open %s"), rtc_dev_name);
+		return 1;
+	}
+
+	if (ioctl(rtc_fd, RTC_VL_CLR) == -1) {
+		warn(_("ioctl(%d, RTC_VL_CLEAR) on %s failed"),
+		     rtc_fd, rtc_dev_name);
+		return 1;
+	}
+
+	if (ctl->verbose)
+		printf(_("ioctl(%d, RTC_VL_CLEAR) on %s succeeded.\n"),
+		       rtc_fd, rtc_dev_name);
+
+	return 0;
+}
diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
index 2a1844309..b043646b3 100644
--- a/sys-utils/hwclock.c
+++ b/sys-utils/hwclock.c
@@ -1180,6 +1180,20 @@ manipulate_rtc_param(const struct hwclock_control *ctl)
 
 	return 1;
 }
+
+static int
+manipulate_rtc_voltage_low(const struct hwclock_control *ctl)
+{
+	if (ctl->vl_read) {
+		if (rtc_vl_read(ctl))
+			return 1;
+	}
+	if (ctl->vl_clear) {
+		if (rtc_vl_clear(ctl))
+			return 1;
+	}
+	return 0;
+}
 #endif
 
 static void out_version(void)
@@ -1215,6 +1229,8 @@ usage(void)
 #ifdef __linux__
 	puts(_("     --param-get <param>         display the RTC parameter"));
 	puts(_("     --param-set <param>=<value> set the RTC parameter"));
+	puts(_("     --vl-read                   read voltage low information"));
+	puts(_("     --vl-clear                  clear voltage low information"));
 #endif
 	puts(_("     --predict                   predict the drifted RTC time according to --date"));
 	fputs(USAGE_OPTIONS, stdout);
@@ -1286,6 +1302,8 @@ int main(int argc, char **argv)
 		OPT_NOADJFILE,
 		OPT_PARAM_GET,
 		OPT_PARAM_SET,
+		OPT_VL_READ,
+		OPT_VL_CLEAR,
 		OPT_PREDICT,
 		OPT_SET,
 		OPT_SETEPOCH,
@@ -1315,6 +1333,8 @@ int main(int argc, char **argv)
 #ifdef __linux__
 		{ "param-get",    required_argument, NULL, OPT_PARAM_GET  },
 		{ "param-set",    required_argument, NULL, OPT_PARAM_SET  },
+		{ "vl-read",      no_argument,       NULL, OPT_VL_READ    },
+		{ "vl-clear",     no_argument,       NULL, OPT_VL_CLEAR   },
 #endif
 		{ "noadjfile",    no_argument,       NULL, OPT_NOADJFILE  },
 		{ "directisa",    no_argument,       NULL, OPT_DIRECTISA  },
@@ -1439,6 +1459,14 @@ int main(int argc, char **argv)
 			ctl.show = 0;
 			ctl.hwaudit_on = 1;
 			break;
+		case OPT_VL_READ:
+			ctl.vl_read = 1;
+			ctl.show = 0;
+			break;
+		case OPT_VL_CLEAR:
+			ctl.vl_clear = 1;
+			ctl.show = 0;
+			break;
 #endif
 		case OPT_NOADJFILE:
 			ctl.noadjfile = 1;
@@ -1540,6 +1568,13 @@ int main(int argc, char **argv)
 
 		hwclock_exit(&ctl, EXIT_SUCCESS);
 	}
+
+	if (ctl.vl_read || ctl.vl_clear) {
+		if (manipulate_rtc_voltage_low(&ctl))
+			hwclock_exit(&ctl, EXIT_FAILURE);
+
+		hwclock_exit(&ctl, EXIT_SUCCESS);
+	}
 #endif
 
 #if defined(__linux__) && defined(__alpha__)
diff --git a/sys-utils/hwclock.h b/sys-utils/hwclock.h
index b5b72d45d..a690e717b 100644
--- a/sys-utils/hwclock.h
+++ b/sys-utils/hwclock.h
@@ -53,6 +53,8 @@ struct hwclock_control {
 		set:1,
 		update:1,
 		universal:1,	/* will store hw_clock_is_utc() return value */
+		vl_read:1,
+		vl_clear:1,
 		verbose:1;
 };
 
@@ -88,6 +90,9 @@ extern int get_param_rtc(const struct hwclock_control *ctl,
 			const char *name, uint64_t *id, uint64_t *value);
 extern int set_param_rtc(const struct hwclock_control *ctl, const char *name);
 
+extern int rtc_vl_read(const struct hwclock_control *ctl);
+extern int rtc_vl_clear(const struct hwclock_control *ctl);
+
 extern void __attribute__((__noreturn__))
 hwclock_exit(const struct hwclock_control *ctl, int status);
 
-- 
2.37.2




[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux