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@xxxxxxxxxxxxxx> --- include/progress.h | 43 +++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig | 6 ++++++ lib/show_progress.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/include/progress.h b/include/progress.h index 50b15fb12b4c..7230bd3a9bd5 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 e5831ecdb9a7..922710e106b3 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 1be06ea7806e..1b624bcb9af8 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 +}; -- 2.29.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox