From 0394fe51b489028388063ed6f238dab3efbd1ae7 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:46 +0200 Subject: 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 Link: https://lore.barebox.org/20210503114901.13095-2-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- include/progress.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'include') 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 +#include +#include /* 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 */ -- cgit v1.2.3 From 7a1ae4f032053ed1c2acbfc7b5cf59aa1539e61e Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:47 +0200 Subject: common: console: add log_writefile to write log into new file It can be useful to dump the log into the file, e.g. when doing an update from a USB flash drive with no serial peer attached. Add a function to facilitate this. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-3-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- common/console_common.c | 20 ++++++++++++++++++++ include/printk.h | 1 + 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/common/console_common.c b/common/console_common.c index 4c1230464c..aa9e943ef0 100644 --- a/common/console_common.c +++ b/common/console_common.c @@ -182,6 +182,26 @@ static int console_common_init(void) } device_initcall(console_common_init); +int log_writefile(const char *filepath) +{ + int ret = 0, nbytes = 0, fd = -1; + struct log_entry *log; + + fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) + return -errno; + + list_for_each_entry(log, &barebox_logbuf, list) { + ret = dputs(fd, log->msg); + if (ret < 0) + break; + nbytes += ret; + } + + close(fd); + return ret < 0 ? ret : nbytes; +} + void log_print(unsigned flags, unsigned levels) { struct log_entry *log; diff --git a/include/printk.h b/include/printk.h index 94a25ec9eb..f83ad3bf07 100644 --- a/include/printk.h +++ b/include/printk.h @@ -141,6 +141,7 @@ extern void log_clean(unsigned int limit); #define BAREBOX_LOG_PRINT_ALERT BIT(1) #define BAREBOX_LOG_PRINT_EMERG BIT(0) +int log_writefile(const char *filepath); void log_print(unsigned flags, unsigned levels); struct va_format { -- cgit v1.2.3 From 015d5be8d66386fb9386f565b9d0e04ca78f8061 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:48 +0200 Subject: string: implement strstarts along with strends Both can be useful when parsing file paths. They are added to different files, because only one of them is available in upstream . The other we add to , which contains more barebox-specific string functions. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-4-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- include/linux/string.h | 10 ++++++++++ include/string.h | 1 + lib/string.c | 9 +++++++++ 3 files changed, 20 insertions(+) (limited to 'include') diff --git a/include/linux/string.h b/include/linux/string.h index 58e2a4d2ea..55bc905c0e 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -136,4 +136,14 @@ extern int kstrtobool(const char *s, bool *res); int match_string(const char * const *array, size_t n, const char *string); +/** + * strstarts - does @str start with @prefix? + * @str: string to examine + * @prefix: prefix to look for. + */ +static inline bool strstarts(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} + #endif /* _LINUX_STRING_H_ */ diff --git a/include/string.h b/include/string.h index ef0b5e199e..d423bee6fb 100644 --- a/include/string.h +++ b/include/string.h @@ -7,6 +7,7 @@ int strtobool(const char *str, int *val); char *strsep_unescaped(char **, const char *); char *stpcpy(char *dest, const char *src); +bool strends(const char *str, const char *postfix); void *__default_memset(void *, int, __kernel_size_t); void *__nokasan_default_memset(void *, int, __kernel_size_t); diff --git a/lib/string.c b/lib/string.c index dbb66fe4d2..bad186586f 100644 --- a/lib/string.c +++ b/lib/string.c @@ -866,6 +866,15 @@ int strtobool(const char *str, int *val) } EXPORT_SYMBOL(strtobool); +bool strends(const char *str, const char *postfix) +{ + if (strlen(str) < strlen(postfix)) + return false; + + return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} +EXPORT_SYMBOL(strends); + /** * match_string - matches given string in an array * @array: array of strings -- cgit v1.2.3 From 15e26bb72b334da1830c26917e28ffcac64e8e4c Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:50 +0200 Subject: param: introduce file-list parameter type DFU, fastboot and incoming mass storage support all use file lists as input, but individually check syntax correctness only on use. A dedicated file list parameter would improve the user experience and makes the code using it easier to handle: the struct file_list can be passed around directly instead of having to parse it first on use. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-6-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- common/file-list.c | 47 ++++++++++++++++++++++++++++ include/file-list.h | 3 ++ include/param.h | 15 +++++++++ include/stringlist.h | 1 + lib/parameter.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/stringlist.c | 30 ++++++++++++++++++ 6 files changed, 184 insertions(+) (limited to 'include') diff --git a/common/file-list.c b/common/file-list.c index cd52b5e045..924903cef7 100644 --- a/common/file-list.c +++ b/common/file-list.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #define PARSE_DEVICE 0 @@ -109,6 +110,25 @@ static int file_list_parse_one(struct file_list *files, const char *partstr, con return file_list_add_entry(files, name, filename, flags); } +static const char *flags_to_str(int flags) +{ + static char str[sizeof "srcu"]; + char *s = str;; + + if (flags & FILE_LIST_FLAG_SAFE) + *s++ = 's'; + if (flags & FILE_LIST_FLAG_READBACK) + *s++ = 'r'; + if (flags & FILE_LIST_FLAG_CREATE) + *s++ = 'c'; + if (flags & FILE_LIST_FLAG_UBI) + *s++ = 'u'; + + *s = '\0'; + + return str; +} + struct file_list *file_list_parse(const char *str) { struct file_list *files; @@ -149,3 +169,30 @@ void file_list_free(struct file_list *files) free(files); } + +char *file_list_to_str(const struct file_list *files) +{ + struct file_list_entry *entry; + struct string_list sl; + char *str; + + if (!files) + return strdup(""); + + string_list_init(&sl); + + list_for_each_entry(entry, &files->list, list) { + int ret = string_list_add_asprintf(&sl, "%s(%s)%s", entry->filename, entry->name, + flags_to_str(entry->flags)); + if (ret) { + str = ERR_PTR(ret); + goto out; + } + } + + str = string_list_join(&sl, ","); +out: + string_list_free(&sl); + + return str; +} diff --git a/include/file-list.h b/include/file-list.h index 9a9edfa378..7264a3e2c6 100644 --- a/include/file-list.h +++ b/include/file-list.h @@ -2,6 +2,8 @@ #ifndef __FILE_LIST #define __FILE_LIST +#include + #define FILE_LIST_FLAG_SAFE (1 << 0) #define FILE_LIST_FLAG_READBACK (1 << 1) #define FILE_LIST_FLAG_CREATE (1 << 2) @@ -20,6 +22,7 @@ struct file_list { }; struct file_list *file_list_parse(const char *str); +char *file_list_to_str(const struct file_list *files); void file_list_free(struct file_list *); int file_list_add_entry(struct file_list *files, const char *name, const char *filename, diff --git a/include/param.h b/include/param.h index 6aca1b481d..4835be4d25 100644 --- a/include/param.h +++ b/include/param.h @@ -10,6 +10,7 @@ #define PARAM_GLOBALVAR_UNQUALIFIED (1 << 1) struct device_d; +struct file_list; typedef uint32_t IPaddr_t; enum param_type { @@ -23,6 +24,7 @@ enum param_type { PARAM_TYPE_BITMASK, PARAM_TYPE_IPV4, PARAM_TYPE_MAC, + PARAM_TYPE_FILE_LIST, }; struct param_d { @@ -89,6 +91,11 @@ struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, int (*get)(struct param_d *p, void *priv), u8 *mac, void *priv); +struct param_d *dev_add_param_file_list(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + struct file_list **file_list, void *priv); + struct param_d *dev_add_param_fixed(struct device_d *dev, const char *name, const char *value); void dev_remove_param(struct param_d *p); @@ -185,6 +192,14 @@ static inline struct param_d *dev_add_param_mac(struct device_d *dev, const char return NULL; } +static inline struct param_d *dev_add_param_file_list(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + struct file_list **file_list, void *priv) +{ + return NULL; +} + static inline struct param_d *dev_add_param_fixed(struct device_d *dev, const char *name, const char *value) { diff --git a/include/stringlist.h b/include/stringlist.h index c5d6e70a36..01491082ea 100644 --- a/include/stringlist.h +++ b/include/stringlist.h @@ -14,6 +14,7 @@ int string_list_add_asprintf(struct string_list *sl, const char *fmt, ...); int string_list_add_sorted(struct string_list *sl, const char *str); int string_list_add_sort_uniq(struct string_list *sl, const char *str); int string_list_contains(struct string_list *sl, const char *str); +char *string_list_join(const struct string_list *sl, const char *joinstr); void string_list_print_by_column(struct string_list *sl); static inline void string_list_init(struct string_list *sl) diff --git a/lib/parameter.c b/lib/parameter.c index 173420c58a..adc3c7cdea 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include static const char *param_type_string[] = { [PARAM_TYPE_STRING] = "string", @@ -39,6 +41,7 @@ static const char *param_type_string[] = { [PARAM_TYPE_BITMASK] = "bitmask", [PARAM_TYPE_IPV4] = "ipv4", [PARAM_TYPE_MAC] = "MAC", + [PARAM_TYPE_FILE_LIST] = "file-list", }; const char *get_param_type(struct param_d *param) @@ -907,6 +910,91 @@ struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, return &pm->param; } +struct param_file_list { + struct param_d param; + struct file_list **file_list; + char *file_list_str; + int (*set)(struct param_d *p, void *priv); + int (*get)(struct param_d *p, void *priv); +}; + +static inline struct param_file_list *to_param_file_list(struct param_d *p) +{ + return container_of(p, struct param_file_list, param); +} + +static int param_file_list_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct param_file_list *pfl = to_param_file_list(p); + struct file_list *file_list_save = *pfl->file_list; + int ret; + + if (!val) + val = ""; + + *pfl->file_list = file_list_parse(val); + if (IS_ERR(*pfl->file_list)) { + ret = PTR_ERR(*pfl->file_list); + goto out; + } + + if (pfl->set) { + ret = pfl->set(p, p->driver_priv); + if (ret) { + file_list_free(*pfl->file_list); + goto out; + } + } + + return 0; +out: + *pfl->file_list = file_list_save; + + return ret; +} + +static const char *param_file_list_get(struct device_d *dev, struct param_d *p) +{ + struct param_file_list *pfl = to_param_file_list(p); + int ret; + + if (pfl->get) { + ret = pfl->get(p, p->driver_priv); + if (ret) + return NULL; + } + + free(p->value); + p->value = file_list_to_str(*pfl->file_list); + return p->value; +} + +struct param_d *dev_add_param_file_list(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + struct file_list **file_list, void *priv) +{ + struct param_file_list *pfl; + int ret; + + pfl = xzalloc(sizeof(*pfl)); + pfl->file_list = file_list; + pfl->set = set; + pfl->get = get; + pfl->param.driver_priv = priv; + pfl->param.type = PARAM_TYPE_FILE_LIST; + + ret = __dev_add_param(&pfl->param, dev, name, + param_file_list_set, param_file_list_get, 0); + if (ret) { + free(pfl); + return ERR_PTR(ret); + } + + return &pfl->param; +} + + /** * dev_remove_param - remove a parameter from a device and free its * memory diff --git a/lib/stringlist.c b/lib/stringlist.c index 719fecdaa4..fc86640b94 100644 --- a/lib/stringlist.c +++ b/lib/stringlist.c @@ -2,6 +2,7 @@ #include #include #include +#include #include static int string_list_compare(struct list_head *a, struct list_head *b) @@ -95,6 +96,35 @@ int string_list_contains(struct string_list *sl, const char *str) return 0; } +char *string_list_join(const struct string_list *sl, const char *joinstr) +{ + struct string_list *entry; + size_t len = 0; + size_t joinstr_len = strlen(joinstr); + char *str, *next; + + string_list_for_each_entry(entry, sl) + len += strlen(entry->str) + joinstr_len; + + if (len == 0) + return strdup(""); + + str = malloc(len + 1); + if (!str) + return NULL; + + next = str; + + string_list_for_each_entry(entry, sl) { + next = stpcpy(next, entry->str); + next = stpcpy(next, joinstr); + } + + next[-joinstr_len] = '\0'; + + return str; +} + void string_list_print_by_column(struct string_list *sl) { int len = 0, num, i; -- cgit v1.2.3 From ff40047b3b6300015a8cc2c6a3e0989676250dbd Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:51 +0200 Subject: common: add generic system partitions interface Both Fastboot and DFU have their own global variables that allow specifying the partitions that can be flashed via the environment. With the upcoming addition of the USB mass storage gadget, we will need some way to define the partitions there as well. Instead of adding yet another way download method-specific variable, add a generic global.system.partitions variable that can be specified on a per-board basis and can be used for all methods. Existing variables will still remain for backwards-compatibility, but when unset, it should fall back to this new parameter. This is done in the follow-up patches. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-7-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- common/Kconfig | 11 +++++++++++ common/Makefile | 1 + common/file-list.c | 18 ++++++++++++++++++ common/system-partitions.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/file-list.h | 2 ++ include/system-partitions.h | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 common/system-partitions.c create mode 100644 include/system-partitions.h (limited to 'include') diff --git a/common/Kconfig b/common/Kconfig index bf8054028b..5eb74cabd0 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -703,6 +703,17 @@ config FLEXIBLE_BOOTARGS config BAREBOX_UPDATE bool "In-system barebox update infrastructure" +config SYSTEM_PARTITIONS + bool "Generic system partitions support" + depends on GLOBALVAR + help + System partitions are a generic way for boards to specify the + partitions that should be exported for flashing. + Board drivers that set this directly will select this option + automatically. + Say y here if this should be configurable over the + global.system.partitions device parameter as well. + config IMD select CRC32 bool "barebox metadata support" diff --git a/common/Makefile b/common/Makefile index 17e2ff1129..c2c15817ba 100644 --- a/common/Makefile +++ b/common/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_MACHINE_ID) += machine_id.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o obj-y += version.o obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o +obj-$(CONFIG_SYSTEM_PARTITIONS) += system-partitions.o obj-$(CONFIG_BINFMT) += binfmt.o obj-$(CONFIG_BLOCK) += block.o obj-$(CONFIG_BLSPEC) += blspec.o diff --git a/common/file-list.c b/common/file-list.c index 924903cef7..580423aef7 100644 --- a/common/file-list.c +++ b/common/file-list.c @@ -170,6 +170,24 @@ void file_list_free(struct file_list *files) free(files); } +struct file_list *file_list_dup(struct file_list *old) +{ + struct file_list_entry *old_entry; + struct file_list *new; + + new = xzalloc(sizeof(*new)); + + INIT_LIST_HEAD(&new->list); + + list_for_each_entry(old_entry, &old->list, list) { + (void)file_list_add_entry(new, old_entry->name, old_entry->filename, + old_entry->flags); /* can't fail */ + new->num_entries++; + } + + return new; +} + char *file_list_to_str(const struct file_list *files) { struct file_list_entry *entry; diff --git a/common/system-partitions.c b/common/system-partitions.c new file mode 100644 index 0000000000..547e08a9f3 --- /dev/null +++ b/common/system-partitions.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Ahmad Fatoum, Pengutronix + */ + +#include +#include +#include +#include +#include +#include + +static struct file_list *system_partitions; + +bool system_partitions_empty(void) +{ + return file_list_empty(system_partitions); +} + +struct file_list *system_partitions_get(void) +{ + return file_list_dup(system_partitions); +} + +void system_partitions_set(struct file_list *files) +{ + file_list_free(system_partitions); + system_partitions = files; +} + +static int system_partitions_var_init(void) +{ + struct param_d *param; + + system_partitions = file_list_parse(""); + param = dev_add_param_file_list(&global_device, "system.partitions", + NULL, NULL, &system_partitions, NULL); + + return PTR_ERR_OR_ZERO(param); +} +postcore_initcall(system_partitions_var_init); + +BAREBOX_MAGICVAR(global.system.partitions, + "board-specific list of updatable partitions"); diff --git a/include/file-list.h b/include/file-list.h index 7264a3e2c6..2538883c36 100644 --- a/include/file-list.h +++ b/include/file-list.h @@ -28,6 +28,8 @@ void file_list_free(struct file_list *); int file_list_add_entry(struct file_list *files, const char *name, const char *filename, unsigned long flags); +struct file_list *file_list_dup(struct file_list *old); + struct file_list_entry *file_list_entry_by_name(struct file_list *files, const char *name); #define file_list_for_each_entry(files, entry) \ diff --git a/include/system-partitions.h b/include/system-partitions.h new file mode 100644 index 0000000000..86de3612cc --- /dev/null +++ b/include/system-partitions.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef SYSTEM_PARTITIONS_H_ +#define SYSTEM_PARTITIONS_H_ + +#include + +#ifdef CONFIG_SYSTEM_PARTITIONS + +/* duplicates current system_partitions and returns it */ +struct file_list *system_partitions_get(void); + +/* takes ownership of files and store it internally */ +void system_partitions_set(struct file_list *files); + +/* + * check whether system_partitions_get would return an empty + * file_list without doing an allocation + */ +bool system_partitions_empty(void); + +#else + +static inline struct file_list *system_partitions_get(void) +{ + return file_list_parse(""); +} + +static inline bool system_partitions_empty(void) +{ + return true; +} + +/* + * system_partitions_set() intentionally left unimplemented. + * select CONFIG_SYSTEM_PARTITIONS if you want to set it + */ + +#endif + +#endif -- cgit v1.2.3 From f1dd6339a8d7d62667ba8a1da863319bc5a1dc57 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:57 +0200 Subject: fastboot/dfu: use system partitions as fall back Use the new system partitions infrastructure to have fastboot and DFU fall back to using the same partitions if the global.usbgadget.dfu_function and global.fastboot_partitions are not set, respectively. No functional change intended for configurations that have SYSTEM_PARTITIONS disabled. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-13-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- common/fastboot.c | 9 ++++-- common/usbgadget.c | 77 +++++++++++++++++++++++++++++----------------- drivers/usb/gadget/multi.c | 12 ++++++++ include/fastboot.h | 6 ++-- include/file-list.h | 5 +++ include/usb/gadget-multi.h | 1 + net/fastboot.c | 4 +-- 7 files changed, 77 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/common/fastboot.c b/common/fastboot.c index c8576a8d97..dc80b66e67 100644 --- a/common/fastboot.c +++ b/common/fastboot.c @@ -41,6 +41,7 @@ #include #include #include +#include #define FASTBOOT_VERSION "0.4" @@ -932,9 +933,13 @@ bool get_fastboot_bbu(void) return fastboot_bbu; } -const char *get_fastboot_partitions(void) +struct file_list *get_fastboot_partitions(void) { - return fastboot_partitions; + if (fastboot_partitions && *fastboot_partitions) + return file_list_parse(fastboot_partitions); + if (!system_partitions_empty()) + return system_partitions_get(); + return NULL; } static int fastboot_globalvars_init(void) diff --git a/common/usbgadget.c b/common/usbgadget.c index 009debd93e..d4437b5169 100644 --- a/common/usbgadget.c +++ b/common/usbgadget.c @@ -17,6 +17,7 @@ #include #include #include +#include static int autostart; static int acm; @@ -24,14 +25,29 @@ static char *dfu_function; static struct file_list *parse(const char *files) { - struct file_list *list = file_list_parse(files); + struct file_list *list; + + if (!files) + return NULL; + + list = file_list_parse(files); if (IS_ERR(list)) { pr_err("Parsing file list \"%s\" failed: %pe\n", files, list); return NULL; } + return list; } +static inline struct file_list *get_dfu_function(void) +{ + if (dfu_function && *dfu_function) + return file_list_parse(dfu_function); + if (!system_partitions_empty()) + return system_partitions_get(); + return NULL; +} + int usbgadget_register(bool dfu, const char *dfu_opts, bool fastboot, const char *fastboot_opts, bool acm, bool export_bbu) @@ -39,45 +55,44 @@ int usbgadget_register(bool dfu, const char *dfu_opts, int ret; struct device_d *dev; struct f_multi_opts *opts; - const char *fastboot_partitions = get_fastboot_partitions(); - - if (dfu && !dfu_opts && dfu_function && *dfu_function) - dfu_opts = dfu_function; - - if (IS_ENABLED(CONFIG_FASTBOOT_BASE) && fastboot && !fastboot_opts && - fastboot_partitions && *fastboot_partitions) - fastboot_opts = fastboot_partitions; - - if (!dfu_opts && !fastboot_opts && !acm) - return COMMAND_ERROR_USAGE; - - /* - * Creating a gadget with both DFU and Fastboot may not work. - * fastboot 1:8.1.0+r23-5 can deal with it, but dfu-util 0.9 - * seems to assume that the device only has a single configuration - * That's not our fault though. Emit a warning and continue - */ - if (fastboot_opts && dfu_opts) - pr_warn("Both DFU and Fastboot enabled. dfu-util may not like this!\n"); opts = xzalloc(sizeof(*opts)); opts->release = usb_multi_opts_release; - if (fastboot_opts) { + if (dfu) { + opts->dfu_opts.files = parse(dfu_opts); + if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && file_list_empty(opts->dfu_opts.files)) { + file_list_free(opts->dfu_opts.files); + opts->dfu_opts.files = get_dfu_function(); + } + } + + if (fastboot) { opts->fastboot_opts.files = parse(fastboot_opts); + if (IS_ENABLED(CONFIG_FASTBOOT_BASE) && file_list_empty(opts->fastboot_opts.files)) { + file_list_free(opts->fastboot_opts.files); + opts->fastboot_opts.files = get_fastboot_partitions(); + } + opts->fastboot_opts.export_bbu = export_bbu; } - if (dfu_opts) - opts->dfu_opts.files = parse(dfu_opts); + opts->create_acm = acm; - if (!opts->dfu_opts.files && !opts->fastboot_opts.files && !acm) { + if (usb_multi_count_functions(opts) == 0) { pr_warn("No functions to register\n"); - free(opts); - return 0; + ret = COMMAND_ERROR_USAGE; + goto err; } - opts->create_acm = acm; + /* + * Creating a gadget with both DFU and Fastboot may not work. + * fastboot 1:8.1.0+r23-5 can deal with it, but dfu-util 0.9 + * seems to assume that the device only has a single configuration + * That's not our fault though. Emit a warning and continue + */ + if (!file_list_empty(opts->fastboot_opts.files) && !file_list_empty(opts->dfu_opts.files)) + pr_warn("Both DFU and Fastboot enabled. dfu-util may not like this!\n"); dev = get_device_by_name("otg"); if (dev) @@ -85,7 +100,11 @@ int usbgadget_register(bool dfu, const char *dfu_opts, ret = usb_multi_register(opts); if (ret) - usb_multi_opts_release(opts); + goto err; + + return 0; +err: + usb_multi_opts_release(opts); return ret; } diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index da4a759117..144ac0624b 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -266,6 +266,18 @@ void usb_multi_unregister(void) gadget_multi_opts = NULL; } +unsigned usb_multi_count_functions(struct f_multi_opts *opts) +{ + unsigned count = 0; + + count += !file_list_empty(opts->fastboot_opts.files) || + opts->fastboot_opts.export_bbu; + count += !file_list_empty(opts->dfu_opts.files); + count += opts->create_acm; + + return count; +} + void usb_multi_opts_release(struct f_multi_opts *opts) { file_list_free(opts->fastboot_opts.files); diff --git a/include/fastboot.h b/include/fastboot.h index 2eab2dfe6a..cf8a177bf1 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -58,16 +58,16 @@ enum fastboot_msg_type { #ifdef CONFIG_FASTBOOT_BASE bool get_fastboot_bbu(void); -const char *get_fastboot_partitions(void); +struct file_list *get_fastboot_partitions(void); #else static inline int get_fastboot_bbu(void) { return false; } -static inline const char *get_fastboot_partitions(void) +static inline struct file_list *get_fastboot_partitions(void) { - return NULL; + return file_list_parse(""); } #endif diff --git a/include/file-list.h b/include/file-list.h index 2538883c36..be97a49b7a 100644 --- a/include/file-list.h +++ b/include/file-list.h @@ -35,4 +35,9 @@ struct file_list_entry *file_list_entry_by_name(struct file_list *files, const c #define file_list_for_each_entry(files, entry) \ list_for_each_entry(entry, &files->list, list) +static inline bool file_list_empty(struct file_list *files) +{ + return !files || !files->num_entries; +} + #endif /* __FILE_LIST */ diff --git a/include/usb/gadget-multi.h b/include/usb/gadget-multi.h index 9bb6c889f3..f30dae5686 100644 --- a/include/usb/gadget-multi.h +++ b/include/usb/gadget-multi.h @@ -15,6 +15,7 @@ struct f_multi_opts { int usb_multi_register(struct f_multi_opts *opts); void usb_multi_unregister(void); void usb_multi_opts_release(struct f_multi_opts *opts); +unsigned usb_multi_count_functions(struct f_multi_opts *opts); int usbgadget_register(bool dfu, const char *dfu_opts, bool fastboot, const char *fastboot_opts, diff --git a/net/fastboot.c b/net/fastboot.c index 9082aa48f6..df388adc89 100644 --- a/net/fastboot.c +++ b/net/fastboot.c @@ -499,7 +499,6 @@ void fastboot_net_free(struct fastboot_net *fbn) struct fastboot_net *fastboot_net_init(struct fastboot_opts *opts) { struct fastboot_net *fbn; - const char *partitions = get_fastboot_partitions(); bool bbu = get_fastboot_bbu(); int ret; @@ -513,8 +512,7 @@ struct fastboot_net *fastboot_net_init(struct fastboot_opts *opts) fbn->fastboot.cmd_flash = opts->cmd_flash; ret = fastboot_generic_init(&fbn->fastboot, opts->export_bbu); } else { - fbn->fastboot.files = file_list_parse(partitions ? - partitions : ""); + fbn->fastboot.files = get_fastboot_partitions() ?: file_list_parse(""); ret = fastboot_generic_init(&fbn->fastboot, bbu); } if (ret) -- cgit v1.2.3 From 49697b065a04d5a5713ba90626dc4259fd007232 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:58 +0200 Subject: bbu: add function to directly add handlers into file_list bbu_handlers_iterate() is only used for merging handlers into a file_list. This can be useful for other update mechanisms as well. Export a bbu_append_handlers_to_file_list that does this. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-14-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- common/bbu.c | 24 +++++++++++++++--------- common/fastboot.c | 21 ++------------------- include/bbu.h | 10 +++++++++- 3 files changed, 26 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/common/bbu.c b/common/bbu.c index ee9f78ecc9..1a1edda96b 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -16,22 +16,28 @@ #include #include #include +#include static LIST_HEAD(bbu_image_handlers); -int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *ctx) +static void append_bbu_entry(struct bbu_handler *handler, struct file_list *files) { - struct bbu_handler *handler; + char *name; - list_for_each_entry(handler, &bbu_image_handlers, list) { - int ret; + name = basprintf("bbu-%s", handler->name); - ret = fn(handler, ctx); - if (ret) - return ret; - } + if (file_list_add_entry(files, name, handler->devicefile, 0)) + pr_warn("duplicate partition name %s\n", name); - return 0; + free(name); +} + +void bbu_append_handlers_to_file_list(struct file_list *files) +{ + struct bbu_handler *handler; + + list_for_each_entry(handler, &bbu_image_handlers, list) + append_bbu_entry(handler, files); } int bbu_force(struct bbu_data *data, const char *fmt, ...) diff --git a/common/fastboot.c b/common/fastboot.c index dc80b66e67..75f6691b08 100644 --- a/common/fastboot.c +++ b/common/fastboot.c @@ -150,23 +150,6 @@ out: return ret; } -static int fastboot_add_bbu_variables(struct bbu_handler *handler, void *ctx) -{ - struct fastboot *fb = ctx; - char *name; - int ret; - - name = basprintf("bbu-%s", handler->name); - - ret = file_list_add_entry(fb->files, name, handler->devicefile, 0); - if (ret) - pr_warn("duplicate partition name %s\n", name); - - free(name); - - return 0; -} - int fastboot_generic_init(struct fastboot *fb, bool export_bbu) { int ret; @@ -188,8 +171,8 @@ int fastboot_generic_init(struct fastboot *fb, bool export_bbu) if (!fb->tempname) return -ENOMEM; - if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && export_bbu) - bbu_handlers_iterate(fastboot_add_bbu_variables, fb); + if (export_bbu) + bbu_append_handlers_to_file_list(fb->files); file_list_for_each_entry(fb->files, fentry) { ret = fastboot_add_partition_variables(fb, fentry); diff --git a/include/bbu.h b/include/bbu.h index 3b9d2f4bf1..3128339068 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -48,7 +48,7 @@ struct bbu_handler *bbu_find_handler_by_device(const char *devicepath); void bbu_handlers_list(void); -int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *); +struct file_list; #ifdef CONFIG_BAREBOX_UPDATE @@ -57,6 +57,8 @@ int bbu_register_handler(struct bbu_handler *); int bbu_register_std_file_update(const char *name, unsigned long flags, const char *devicefile, enum filetype imagetype); +void bbu_append_handlers_to_file_list(struct file_list *files); + #else static inline int bbu_register_handler(struct bbu_handler *unused) @@ -69,6 +71,12 @@ static inline int bbu_register_std_file_update(const char *name, unsigned long f { return -ENOSYS; } + +static inline void bbu_append_handlers_to_file_list(struct file_list *files) +{ + /* none could be registered, so nothing to do */ +} + #endif #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) -- cgit v1.2.3 From 00e5e596df0b6db478bad982fd38867bd5582e76 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 3 May 2021 13:48:59 +0200 Subject: file_list: add file_list_detect_all() This is a common theme along the code that uses file_lists. Add a function that abstracts it. This could later be used to simplify this operation in the fastboot code. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20210503114901.13095-15-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- common/file-list.c | 17 +++++++++++++++++ include/file-list.h | 2 ++ 2 files changed, 19 insertions(+) (limited to 'include') diff --git a/common/file-list.c b/common/file-list.c index 55e6f0e6b6..05f44514fb 100644 --- a/common/file-list.c +++ b/common/file-list.c @@ -8,6 +8,7 @@ #include #include #include +#include #define PARSE_DEVICE 0 #define PARSE_NAME 1 @@ -217,3 +218,19 @@ out: return str; } + +int file_list_detect_all(const struct file_list *files) +{ + struct file_list_entry *fentry; + struct stat s; + int i = 0; + + list_for_each_entry(fentry, &files->list, list) { + if (stat(fentry->filename, &s)) + continue; + if (device_detect_by_name(devpath_to_name(fentry->filename)) == 0) + i++; + } + + return i; +} diff --git a/include/file-list.h b/include/file-list.h index be97a49b7a..7e2a4d9205 100644 --- a/include/file-list.h +++ b/include/file-list.h @@ -30,6 +30,8 @@ int file_list_add_entry(struct file_list *files, const char *name, const char *f struct file_list *file_list_dup(struct file_list *old); +int file_list_detect_all(const struct file_list *files); + struct file_list_entry *file_list_entry_by_name(struct file_list *files, const char *name); #define file_list_for_each_entry(files, entry) \ -- cgit v1.2.3