diff options
-rw-r--r-- | include/rtc_.h | 18 | ||||
-rw-r--r-- | util-linux/hwclock.c | 87 |
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 | ||
49 | struct 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 | |||
80 | POP_SAVED_FUNCTION_VISIBILITY | 98 | POP_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 | ||
323 | static 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 | |||
341 | static 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, ¶m); | ||
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 | |||
359 | static 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, ¶m); | ||
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 | ||
379 | int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 447 | int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
380 | int hwclock_main(int argc UNUSED_PARAM, char **argv) | 448 | int 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 | ¶m, | ||
474 | ¶m | ||
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); |