aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rtc_.h18
-rw-r--r--util-linux/hwclock.c87
2 files changed, 100 insertions, 5 deletions
diff --git a/include/rtc_.h b/include/rtc_.h
index 24ff5363f..782966090 100644
--- a/include/rtc_.h
+++ b/include/rtc_.h
@@ -46,6 +46,17 @@ struct linux_rtc_wkalrm {
46 struct linux_rtc_time time; /* time the alarm is set to */ 46 struct linux_rtc_time time; /* time the alarm is set to */
47}; 47};
48 48
49struct rtc_param {
50 uint64_t param;
51 union {
52 uint64_t uvalue;
53 int64_t svalue;
54 uint64_t ptr;
55 };
56 uint32_t index;
57 uint32_t __pad;
58};
59
49/* 60/*
50 * ioctl calls that are permitted to the /dev/rtc interface, if 61 * ioctl calls that are permitted to the /dev/rtc interface, if
51 * any of the RTC drivers are enabled. 62 * any of the RTC drivers are enabled.
@@ -71,12 +82,19 @@ struct linux_rtc_wkalrm {
71#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ 82#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/
72#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ 83#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/
73 84
85#define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param) /* Get parameter */
86#define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param) /* Set parameter */
87
74/* interrupt flags */ 88/* interrupt flags */
75#define RTC_IRQF 0x80 /* any of the following is active */ 89#define RTC_IRQF 0x80 /* any of the following is active */
76#define RTC_PF 0x40 90#define RTC_PF 0x40
77#define RTC_AF 0x20 91#define RTC_AF 0x20
78#define RTC_UF 0x10 92#define RTC_UF 0x10
79 93
94#define RTC_PARAM_FEATURES 0
95#define RTC_PARAM_CORRECTION 1
96#define RTC_PARAM_BACKUP_SWITCH_MODE 2
97
80POP_SAVED_FUNCTION_VISIBILITY 98POP_SAVED_FUNCTION_VISIBILITY
81 99
82#endif 100#endif
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index a0b7b52bd..d78bfe374 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)
320 close(rtc); 320 close(rtc);
321} 321}
322 322
323static uint64_t resolve_rtc_param_alias(const char *alias)
324{
325 int n;
326
327 BUILD_BUG_ON(RTC_PARAM_FEATURES != 0
328 || RTC_PARAM_CORRECTION != 1
329 || RTC_PARAM_BACKUP_SWITCH_MODE != 2
330 );
331 n = index_in_strings(
332 "features" "\0"
333 "correction" "\0"
334 "bsm" "\0"
335 , alias);
336 if (n >= 0)
337 return n;
338 return xstrtoull(alias, 0);
339}
340
341static void get_rtc_param(const char **pp_rtcname, const char *rtc_param)
342{
343 int rtc;
344 struct rtc_param param;
345
346 param.param = resolve_rtc_param_alias(rtc_param);
347
348 rtc = rtc_xopen(pp_rtcname, O_RDONLY);
349
350 xioctl(rtc, RTC_PARAM_GET, &param);
351
352 printf("The RTC parameter 0x%llx is set to 0x%llx.\n",
353 (unsigned long long) param.param, (unsigned long long) param.uvalue);
354
355 if (ENABLE_FEATURE_CLEAN_UP)
356 close(rtc);
357}
358
359static void set_rtc_param(const char **pp_rtcname, char *rtc_param)
360{
361 int rtc;
362 struct rtc_param param;
363 char *eq;
364
365 /* handle param name */
366 eq = strchr(rtc_param, '=');
367 if (!eq)
368 bb_error_msg_and_die("expected <param>=<value>");
369 *eq = '\0';
370 param.param = resolve_rtc_param_alias(rtc_param);
371 *eq = '=';
372
373 /* handle param value */
374 param.uvalue = xstrtoull(eq + 1, 0);
375
376 rtc = rtc_xopen(pp_rtcname, O_WRONLY);
377
378 printf("The RTC parameter 0x%llx will be set to 0x%llx.\n",
379 (unsigned long long) param.param, (unsigned long long) param.uvalue);
380
381 xioctl(rtc, RTC_PARAM_SET, &param);
382
383 if (ENABLE_FEATURE_CLEAN_UP)
384 close(rtc);
385}
386
323// hwclock from util-linux 2.36.1 387// hwclock from util-linux 2.36.1
324// hwclock [function] [option...] 388// hwclock [function] [option...]
325//Functions: 389//Functions:
@@ -346,10 +410,10 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
346 410
347//usage:#define hwclock_trivial_usage 411//usage:#define hwclock_trivial_usage
348//usage: IF_LONG_OPTS( 412//usage: IF_LONG_OPTS(
349//usage: "[-swul] [--systz] [-f DEV]" 413//usage: "[-swul] [--systz] [--param-get PARAM] [--param-set PARAM=VAL] [-f DEV]"
350//usage: ) 414//usage: )
351//usage: IF_NOT_LONG_OPTS( 415//usage: IF_NOT_LONG_OPTS(
352//usage: "[-swult] [-f DEV]" 416//usage: "[-swult] [-g PARAM] [-p PARAM=VAL] [-f DEV]"
353//usage: ) 417//usage: )
354//usage:#define hwclock_full_usage "\n\n" 418//usage:#define hwclock_full_usage "\n\n"
355//usage: "Show or set hardware clock (RTC)\n" 419//usage: "Show or set hardware clock (RTC)\n"
@@ -360,6 +424,8 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
360//usage: IF_LONG_OPTS( 424//usage: IF_LONG_OPTS(
361//usage: "\n --systz Set in-kernel timezone, correct system time" 425//usage: "\n --systz Set in-kernel timezone, correct system time"
362//usage: "\n if RTC is kept in local time" 426//usage: "\n if RTC is kept in local time"
427//usage: "\n --param-get PARAM Get RTC parameter"
428//usage: "\n --param-set PARAM=VAL Set RTC parameter"
363//usage: ) 429//usage: )
364//usage: "\n -f DEV Use specified device (e.g. /dev/rtc2)" 430//usage: "\n -f DEV Use specified device (e.g. /dev/rtc2)"
365//usage: "\n -u Assume RTC is kept in UTC" 431//usage: "\n -u Assume RTC is kept in UTC"
@@ -375,11 +441,14 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
375#define HWCLOCK_OPT_SYSTOHC 0x10 441#define HWCLOCK_OPT_SYSTOHC 0x10
376#define HWCLOCK_OPT_SYSTZ 0x20 442#define HWCLOCK_OPT_SYSTZ 0x20
377#define HWCLOCK_OPT_RTCFILE 0x40 443#define HWCLOCK_OPT_RTCFILE 0x40
444#define HWCLOCK_OPT_PARAM_GET 0x80
445#define HWCLOCK_OPT_PARAM_SET 0x100
378 446
379int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 447int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
380int hwclock_main(int argc UNUSED_PARAM, char **argv) 448int hwclock_main(int argc UNUSED_PARAM, char **argv)
381{ 449{
382 const char *rtcname = NULL; 450 const char *rtcname = NULL;
451 char *param;
383 unsigned opt; 452 unsigned opt;
384 int utc; 453 int utc;
385#if ENABLE_LONG_OPTS 454#if ENABLE_LONG_OPTS
@@ -391,14 +460,18 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
391 "systohc\0" No_argument "w" 460 "systohc\0" No_argument "w"
392 "systz\0" No_argument "t" /* short opt is non-standard */ 461 "systz\0" No_argument "t" /* short opt is non-standard */
393 "rtc\0" Required_argument "f" 462 "rtc\0" Required_argument "f"
463 "param-get\0" Required_argument "g" /* short opt is non-standard */
464 "param-set\0" Required_argument "p" /* short opt is non-standard */
394 ; 465 ;
395#endif 466#endif
396 opt = getopt32long(argv, 467 opt = getopt32long(argv,
397 "^""lurswtf:v" /* -v is accepted and ignored */ 468 "^""lurswtf:g:p:v" /* -v is accepted and ignored */
398 "\0" 469 "\0"
399 "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l", 470 "r--wstgp:w--rstgp:s--wrtgp:t--rswgp:g--rswtp:p--rswtg:l--u:u--l",
400 hwclock_longopts, 471 hwclock_longopts,
401 &rtcname 472 &rtcname,
473 &param,
474 &param
402 ); 475 );
403 476
404 /* If -u or -l wasn't given, check if we are using utc */ 477 /* 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)
413 from_sys_clock(&rtcname, utc); 486 from_sys_clock(&rtcname, utc);
414 else if (opt & HWCLOCK_OPT_SYSTZ) 487 else if (opt & HWCLOCK_OPT_SYSTZ)
415 set_kernel_timezone_and_clock(utc, NULL); 488 set_kernel_timezone_and_clock(utc, NULL);
489 else if (opt & HWCLOCK_OPT_PARAM_GET)
490 get_rtc_param(&rtcname, param);
491 else if (opt & HWCLOCK_OPT_PARAM_SET)
492 set_rtc_param(&rtcname, param);
416 else 493 else
417 /* default HWCLOCK_OPT_SHOW */ 494 /* default HWCLOCK_OPT_SHOW */
418 show_clock(&rtcname, utc); 495 show_clock(&rtcname, utc);