diff options
author | Ahmad Fatoum <a.fatoum@pengutronix.de> | 2021-05-03 13:48:46 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-05-03 13:55:29 +0200 |
commit | 0394fe51b489028388063ed6f238dab3efbd1ae7 (patch) | |
tree | cf1d77588a9889104546c5b71e0348687b4d8a12 | |
parent | af0f068a6edad45b033e772056ac0352e1ba3613 (diff) | |
download | barebox-0394fe51b489028388063ed6f238dab3efbd1ae7.tar.gz barebox-0394fe51b489028388063ed6f238dab3efbd1ae7.tar.xz |
show_progress: add system wide progress stage notifier
Use case is e.g. board code that wants to register a client to light
status LEDs to indicate system state when no serial output is available.
This functionality doesn't increase code size due to linker GC when
CONFIG_PROGRESS_NOTIFIER is disabled.
There is a generic progress notifier provided that just logs the
status. This could be shared with the booted kernel via pstore or
the log as a whole written to a system setup USB drive.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Link: https://lore.barebox.org/20210503114901.13095-2-a.fatoum@pengutronix.de
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | include/progress.h | 43 | ||||
-rw-r--r-- | lib/Kconfig | 6 | ||||
-rw-r--r-- | lib/show_progress.c | 28 |
3 files changed, 77 insertions, 0 deletions
diff --git a/include/progress.h b/include/progress.h index 50b15fb12b..7230bd3a9b 100644 --- a/include/progress.h +++ b/include/progress.h @@ -3,6 +3,8 @@ #define __PROGRSS_H #include <linux/types.h> +#include <notifier.h> +#include <errno.h> /* Initialize a progress bar. If max > 0 a one line progress * bar is printed where 'max' corresponds to 100%. If max == 0 @@ -15,4 +17,45 @@ void init_progression_bar(loff_t max); */ void show_progress(loff_t now); +extern struct notifier_head progress_notifier; + +enum progress_stage { + PROGRESS_UNSPECIFIED = 0, + PROGRESS_UPDATING, + PROGRESS_UPDATE_SUCCESS, + PROGRESS_UPDATE_FAIL, +}; + +/* + * Notifier list for code which wants to be called at progress + * This could use by board code to e.g. flash a LED during updates + */ +extern struct notifier_head progress_notifier_list; + +/* generic client that just logs the state */ +extern struct notifier_block progress_log_client; + +static inline int progress_register_client(struct notifier_block *nb) +{ + if (!IS_ENABLED(CONFIG_PROGRESS_NOTIFIER)) + return -ENOSYS; + return notifier_chain_register(&progress_notifier_list, nb); +} + +static inline int progress_unregister_client(struct notifier_block *nb) +{ + if (!IS_ENABLED(CONFIG_PROGRESS_NOTIFIER)) + return -ENOSYS; + return notifier_chain_unregister(&progress_notifier_list, nb); +} + +static inline int progress_notifier_call_chain(enum progress_stage stage, const char *prefix) +{ + if (!IS_ENABLED(CONFIG_PROGRESS_NOTIFIER)) + return -ENOSYS; + + /* clients should not modify the prefix */ + return notifier_call_chain(&progress_notifier_list, stage, (char *)(prefix ?: "")); +} + #endif /* __PROGRSS_H */ diff --git a/lib/Kconfig b/lib/Kconfig index e5831ecdb9..922710e106 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -154,6 +154,12 @@ source "lib/logo/Kconfig" source "lib/bootstrap/Kconfig" +config PROGRESS_NOTIFIER + bool + help + This is selected by boards that register a notifier to visualize + progress, like blinking a LED during an update. + config PRINTF_UUID bool diff --git a/lib/show_progress.c b/lib/show_progress.c index 1be06ea780..1b624bcb9a 100644 --- a/lib/show_progress.c +++ b/lib/show_progress.c @@ -57,3 +57,31 @@ void init_progression_bar(loff_t max) else printf("\t"); } + +NOTIFIER_HEAD(progress_notifier_list); + +static int progress_logger(struct notifier_block *r, unsigned long stage, void *_prefix) +{ + const char *prefix = _prefix; + + switch ((enum progress_stage)stage) { + case PROGRESS_UPDATING: + pr_info("%sSoftware update in progress\n", prefix); + break; + case PROGRESS_UPDATE_SUCCESS: + pr_info("%sSoftware update finished successfully\n", prefix); + break; + case PROGRESS_UPDATE_FAIL: + pr_info("%sSoftware update failed\n", prefix); + break; + case PROGRESS_UNSPECIFIED: + /* default state. This should not be reached */ + break; + } + + return 0; +} + +struct notifier_block progress_log_client = { + .notifier_call = progress_logger +}; |