228 lines
7.1 KiB
Diff
228 lines
7.1 KiB
Diff
From: Andrej Picej <andrej.picej@norik.com>
|
|
Date: Tue, 11 Jul 2023 10:42:49 +0200
|
|
Subject: [PATCH] hwclock: add get/set parameters option
|
|
|
|
In kernel 5.16 special ioctls were introduced to get/set RTC parameters.
|
|
Add option to get/set parameters into busybox version of hwclock.
|
|
Implementation is similar to the one already used in linux-utils hwclock
|
|
tool.
|
|
|
|
Example of parameter get use:
|
|
$ hwclock -g 2
|
|
The RTC parameter 0x2 is set to 0x2.
|
|
$ hwclock --param-get bsm
|
|
The RTC parameter 0x2 is set to 0x2.
|
|
|
|
Example of parameter set use:
|
|
$ hwclock -p 2=1
|
|
The RTC parameter 0x2 will be set to 0x1.
|
|
$ hwclock -p bsm=2
|
|
The RTC parameter 0x2 will be set to 0x2.
|
|
|
|
function old new delta
|
|
hwclock_main 298 576 +278
|
|
.rodata 105231 105400 +169
|
|
packed_usage 34541 34576 +35
|
|
static.hwclock_longopts 60 84 +24
|
|
------------------------------------------------------------------------------
|
|
(add/remove: 0/0 grow/shrink: 4/0 up/down: 506/0) Total: 506 bytes
|
|
|
|
Upstream-Status: Backport [master]
|
|
|
|
Signed-off-by: Andrej Picej <andrej.picej@norik.com>
|
|
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
|
|
(cherry picked from commit d70256a5c719439cc6fab6a4571c1bb46178e4c7)
|
|
Signed-off-by: Javier Viguera <javier.viguera@digi.com>
|
|
---
|
|
include/rtc_.h | 18 +++++++++
|
|
util-linux/hwclock.c | 87 +++++++++++++++++++++++++++++++++++++++++---
|
|
2 files changed, 100 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/include/rtc_.h b/include/rtc_.h
|
|
index 24ff536..7829660 100644
|
|
--- a/include/rtc_.h
|
|
+++ b/include/rtc_.h
|
|
@@ -46,6 +46,17 @@ struct linux_rtc_wkalrm {
|
|
struct linux_rtc_time time; /* time the alarm is set to */
|
|
};
|
|
|
|
+struct rtc_param {
|
|
+ uint64_t param;
|
|
+ union {
|
|
+ uint64_t uvalue;
|
|
+ int64_t svalue;
|
|
+ uint64_t ptr;
|
|
+ };
|
|
+ uint32_t index;
|
|
+ uint32_t __pad;
|
|
+};
|
|
+
|
|
/*
|
|
* ioctl calls that are permitted to the /dev/rtc interface, if
|
|
* any of the RTC drivers are enabled.
|
|
@@ -71,12 +82,19 @@ struct linux_rtc_wkalrm {
|
|
#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/
|
|
#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/
|
|
|
|
+#define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param) /* Get parameter */
|
|
+#define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param) /* Set parameter */
|
|
+
|
|
/* interrupt flags */
|
|
#define RTC_IRQF 0x80 /* any of the following is active */
|
|
#define RTC_PF 0x40
|
|
#define RTC_AF 0x20
|
|
#define RTC_UF 0x10
|
|
|
|
+#define RTC_PARAM_FEATURES 0
|
|
+#define RTC_PARAM_CORRECTION 1
|
|
+#define RTC_PARAM_BACKUP_SWITCH_MODE 2
|
|
+
|
|
POP_SAVED_FUNCTION_VISIBILITY
|
|
|
|
#endif
|
|
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
|
|
index 723b095..0101db7 100644
|
|
--- a/util-linux/hwclock.c
|
|
+++ b/util-linux/hwclock.c
|
|
@@ -320,6 +320,70 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
|
|
close(rtc);
|
|
}
|
|
|
|
+static uint64_t resolve_rtc_param_alias(const char *alias)
|
|
+{
|
|
+ int n;
|
|
+
|
|
+ BUILD_BUG_ON(RTC_PARAM_FEATURES != 0
|
|
+ || RTC_PARAM_CORRECTION != 1
|
|
+ || RTC_PARAM_BACKUP_SWITCH_MODE != 2
|
|
+ );
|
|
+ n = index_in_strings(
|
|
+ "features" "\0"
|
|
+ "correction" "\0"
|
|
+ "bsm" "\0"
|
|
+ , alias);
|
|
+ if (n >= 0)
|
|
+ return n;
|
|
+ return xstrtoull(alias, 0);
|
|
+}
|
|
+
|
|
+static void get_rtc_param(const char **pp_rtcname, const char *rtc_param)
|
|
+{
|
|
+ int rtc;
|
|
+ struct rtc_param param;
|
|
+
|
|
+ param.param = resolve_rtc_param_alias(rtc_param);
|
|
+
|
|
+ rtc = rtc_xopen(pp_rtcname, O_RDONLY);
|
|
+
|
|
+ xioctl(rtc, RTC_PARAM_GET, ¶m);
|
|
+
|
|
+ printf("The RTC parameter 0x%llx is set to 0x%llx.\n",
|
|
+ (unsigned long long) param.param, (unsigned long long) param.uvalue);
|
|
+
|
|
+ if (ENABLE_FEATURE_CLEAN_UP)
|
|
+ close(rtc);
|
|
+}
|
|
+
|
|
+static void set_rtc_param(const char **pp_rtcname, char *rtc_param)
|
|
+{
|
|
+ int rtc;
|
|
+ struct rtc_param param;
|
|
+ char *eq;
|
|
+
|
|
+ /* handle param name */
|
|
+ eq = strchr(rtc_param, '=');
|
|
+ if (!eq)
|
|
+ bb_error_msg_and_die("expected <param>=<value>");
|
|
+ *eq = '\0';
|
|
+ param.param = resolve_rtc_param_alias(rtc_param);
|
|
+ *eq = '=';
|
|
+
|
|
+ /* handle param value */
|
|
+ param.uvalue = xstrtoull(eq + 1, 0);
|
|
+
|
|
+ rtc = rtc_xopen(pp_rtcname, O_WRONLY);
|
|
+
|
|
+ printf("The RTC parameter 0x%llx will be set to 0x%llx.\n",
|
|
+ (unsigned long long) param.param, (unsigned long long) param.uvalue);
|
|
+
|
|
+ xioctl(rtc, RTC_PARAM_SET, ¶m);
|
|
+
|
|
+ if (ENABLE_FEATURE_CLEAN_UP)
|
|
+ close(rtc);
|
|
+}
|
|
+
|
|
// hwclock from util-linux 2.36.1
|
|
// hwclock [function] [option...]
|
|
//Functions:
|
|
@@ -346,10 +410,10 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
|
|
|
|
//usage:#define hwclock_trivial_usage
|
|
//usage: IF_LONG_OPTS(
|
|
-//usage: "[-swul] [--systz] [-f DEV]"
|
|
+//usage: "[-swul] [--systz] [--param-get PARAM] [--param-set PARAM=VAL] [-f DEV]"
|
|
//usage: )
|
|
//usage: IF_NOT_LONG_OPTS(
|
|
-//usage: "[-swult] [-f DEV]"
|
|
+//usage: "[-swult] [-g PARAM] [-p PARAM=VAL] [-f DEV]"
|
|
//usage: )
|
|
//usage:#define hwclock_full_usage "\n\n"
|
|
//usage: "Show or set hardware clock (RTC)\n"
|
|
@@ -360,6 +424,8 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
|
|
//usage: IF_LONG_OPTS(
|
|
//usage: "\n --systz Set in-kernel timezone, correct system time"
|
|
//usage: "\n if RTC is kept in local time"
|
|
+//usage: "\n --param-get PARAM Get RTC parameter"
|
|
+//usage: "\n --param-set PARAM=VAL Set RTC parameter"
|
|
//usage: )
|
|
//usage: "\n -f DEV Use specified device (e.g. /dev/rtc2)"
|
|
//usage: "\n -u Assume RTC is kept in UTC"
|
|
@@ -375,11 +441,14 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
|
|
#define HWCLOCK_OPT_SYSTOHC 0x10
|
|
#define HWCLOCK_OPT_SYSTZ 0x20
|
|
#define HWCLOCK_OPT_RTCFILE 0x40
|
|
+#define HWCLOCK_OPT_PARAM_GET 0x80
|
|
+#define HWCLOCK_OPT_PARAM_SET 0x100
|
|
|
|
int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
|
int hwclock_main(int argc UNUSED_PARAM, char **argv)
|
|
{
|
|
const char *rtcname = NULL;
|
|
+ char *param;
|
|
unsigned opt;
|
|
int utc;
|
|
#if ENABLE_LONG_OPTS
|
|
@@ -391,14 +460,18 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
|
|
"systohc\0" No_argument "w"
|
|
"systz\0" No_argument "t" /* short opt is non-standard */
|
|
"rtc\0" Required_argument "f"
|
|
+ "param-get\0" Required_argument "g" /* short opt is non-standard */
|
|
+ "param-set\0" Required_argument "p" /* short opt is non-standard */
|
|
;
|
|
#endif
|
|
opt = getopt32long(argv,
|
|
- "^""lurswtf:v" /* -v is accepted and ignored */
|
|
+ "^""lurswtf:g:p:v" /* -v is accepted and ignored */
|
|
"\0"
|
|
- "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l",
|
|
+ "r--wstgp:w--rstgp:s--wrtgp:t--rswgp:g--rswtp:p--rswtg:l--u:u--l",
|
|
hwclock_longopts,
|
|
- &rtcname
|
|
+ &rtcname,
|
|
+ ¶m,
|
|
+ ¶m
|
|
);
|
|
|
|
/* If -u or -l wasn't given, check if we are using utc */
|
|
@@ -413,6 +486,10 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
|
|
from_sys_clock(&rtcname, utc);
|
|
else if (opt & HWCLOCK_OPT_SYSTZ)
|
|
set_kernel_timezone_and_clock(utc, NULL);
|
|
+ else if (opt & HWCLOCK_OPT_PARAM_GET)
|
|
+ get_rtc_param(&rtcname, param);
|
|
+ else if (opt & HWCLOCK_OPT_PARAM_SET)
|
|
+ set_rtc_param(&rtcname, param);
|
|
else
|
|
/* default HWCLOCK_OPT_SHOW */
|
|
show_clock(&rtcname, utc);
|