par.param = RTC_PARAM_BACKUP_SWITCH_MODE;
par.uvalue = value;
- printf("Set backup switch mode to: $%02X\n", value);
-
ret = ioctl(fd, RTC_PARAM_SET, &par);
if (ret < 0) {
perror("set RTC_PARAM_BACKUP_SWITCH_MODE");
return 0;
}
+static int rtc_param_get_vl_backup(int fd)
+{
+ const char *prefix = "Backup voltage:";
+ unsigned long tmp;
+ int voltage_good;
+ int ret;
+
+ ret = ioctl(fd, RTC_VL_READ, &tmp);
+ if (ret < 0) {
+ perror("get RTC_VL_READ");
+ return ret;
+ }
+
+ voltage_good = true;
+
+ if (tmp & RTC_VL_DATA_INVALID) {
+ printf("%s too low, RTC data is invalid\n", prefix);
+ voltage_good = false;
+ }
+
+ if (tmp & RTC_VL_BACKUP_LOW) {
+ printf("%s low, check/replace RTC battery\n", prefix);
+ voltage_good = false;
+ }
+
+ if (tmp & RTC_VL_BACKUP_EMPTY) {
+ printf("%s empty or not present\n", prefix);
+ voltage_good = false;
+ }
+
+ if (tmp & RTC_VL_ACCURACY_LOW) {
+ printf("%s low, RTC accuracy is reduced\n", prefix);
+ voltage_good = false;
+ }
+
+ if (voltage_good)
+ printf("%s good\n", prefix);
+
+ if (tmp & RTC_VL_BACKUP_SWITCH)
+ printf("%s switchover event detected\n", prefix);
+
+ return 0;
+}
+
+static int rtc_param_clear_vl_backup(int fd)
+{
+ struct rtc_param par;
+ int ret;
+
+ ret = ioctl(fd, RTC_VL_CLR, &par);
+ if (ret < 0) {
+ perror("get RTC_VL_CLR");
+ return ret;
+ }
+
+ return 0;
+}
+
static int rtc_test_uie(int fd)
{
unsigned long data;
}
}
+ if (options.vl_backup) {
+ rc = rtc_param_get_vl_backup(fd);
+ if (rc < 0)
+ exit(rc);
+ }
+
+ if (options.clear) {
+ rc = rtc_param_clear_vl_backup(fd);
+ if (rc < 0)
+ exit(rc);
+ }
+
if (options.test) {
rc = rtc_test(fd);
if (rc < 0)
#include <stdlib.h>
#include <argp.h>
#include <stdarg.h> /* va_start */
+#include <linux/rtc.h>
#if STDC_HEADERS
# include <string.h>
*/
#define USAGE_KEY 0x123
+#define ARGP_BSM_STR \
+ " disabled RTC_BSM_DISABLED\n" \
+ " direct RTC_BSM_DIRECT\n" \
+ " level RTC_BSM_LEVEL\n" \
+ " standby RTC_BSM_STANDBY"
+
/* The options we understand. */
static struct argp_option argp_options[] = {
- {"bsm", 'b', "value", OPTION_ARG_OPTIONAL, "Get/Set Backup Switch Mode (BSM)", 0},
- {"dev", 'd', "path", 0, "RTC device path (optional)", 0},
+ {"bsm", 'b', "value", OPTION_ARG_OPTIONAL, "Get/Set Backup Switch Mode (BSM):", 0},
+ {0, 0, 0, 0, ARGP_BSM_STR, 0},
+ {"clear", 'c', 0, 0, "Clear \"voltage low\" event", 0},
+ {"dev", 'd', "path", 0, "RTC device path (optional)", 0},
{"test", 't', 0, 0, "Test RTC", 0},
+ {"voltage-level", 'v', 0, 0, "Get battery backup voltage level", 0},
/*
* Add -h manually; OPTION_HIDDEN prevents it from appearing twice in --help.
* This must be listed after all other options, to prevent an empty line.
}
static void
-decode_int(char *arg, struct argp_state *state, int *dest)
+decode_bsm(char *arg, struct argp_state *state)
{
- char *endptr;
-
- *dest = strtol(arg, &endptr, 0);
-
- if (*endptr != '\0') {
- log_err("Invalid option: %s\n", arg);
- argp_usage(state);
+ if (STREQ(arg, "disabled")) {
+ options.bsm_arg = RTC_BSM_DISABLED;
+ } else if (STREQ(arg, "direct")) {
+ options.bsm_arg = RTC_BSM_DIRECT;
+ } else if (STREQ(arg, "level")) {
+ options.bsm_arg = RTC_BSM_LEVEL;
+ } else if (STREQ(arg, "standby")) {
+ options.bsm_arg = RTC_BSM_STANDBY;
+ } else {
+ log_fail("Unknown BSM value: %s\n", arg);
+ argp_usage(state);
}
}
case 'b':
options.bsm = true;
if (arg)
- decode_int(arg, state, &options.bsm_arg);
+ decode_bsm(arg, state);
+ break;
+ case 'c':
+ options.clear = true;
break;
case 'd':
options.rtc_path = arg;
case 't':
options.test = true;
break;
+ case 'v':
+ options.vl_backup = true;
+ break;
default:
return ARGP_ERR_UNKNOWN;
}