diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 7c3590fd97c2..6966a1854832 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -467,21 +467,85 @@ static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv, #endif /* CONFIG_FW_LOADER_COMPRESS_XZ */ /* direct firmware loading support */ -static char fw_path_para[256]; +#define CUSTOM_FW_PATH_COUNT 10 +#define PATH_SIZE 255 +static char fw_path_para[CUSTOM_FW_PATH_COUNT][PATH_SIZE]; static const char * const fw_path[] = { - fw_path_para, + fw_path_para[0], + fw_path_para[1], + fw_path_para[2], + fw_path_para[3], + fw_path_para[4], + fw_path_para[5], + fw_path_para[6], + fw_path_para[7], + fw_path_para[8], + fw_path_para[9], "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, "/lib/firmware" }; +static char strpath[PATH_SIZE * CUSTOM_FW_PATH_COUNT]; +static int firmware_param_path_set(const char *val, const struct kernel_param *kp) +{ + int i; + char *path, *end; + + strscpy(strpath, val, sizeof(strpath)); + /* Remove leading and trailing spaces from path */ + path = strim(strpath); + for (i = 0; path && i < CUSTOM_FW_PATH_COUNT; i++) { + end = strchr(path, ','); + + /* Skip continuous token case, for example ',,,' */ + if (end == path) { + i--; + path = ++end; + continue; + } + + if (end != NULL) + *end = '\0'; + else { + /* end of the string reached and no other tockens ',' */ + strscpy(fw_path_para[i], path, PATH_SIZE); + break; + } + + strscpy(fw_path_para[i], path, PATH_SIZE); + path = ++end; + } + + return 0; +} + +static int firmware_param_path_get(char *buffer, const struct kernel_param *kp) +{ + int count = 0, i; + + for (i = 0; i < CUSTOM_FW_PATH_COUNT; i++) { + if (strlen(fw_path_para[i]) != 0) + count += scnprintf(buffer + count, PATH_SIZE, "%s%s", fw_path_para[i], ","); + } + + buffer[count - 1] = '\0'; + + return count - 1; +} /* - * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH' + * Typical usage is that passing 'firmware_class.path=/vendor,/firwmare_mnt' * from kernel command line because firmware_class is generally built in - * kernel instead of module. + * kernel instead of module. ',' is used as delimiter for setting 10 + * custom paths for firmware loader. */ -module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); + +static const struct kernel_param_ops firmware_param_ops = { + .set = firmware_param_path_set, + .get = firmware_param_path_get, +}; +module_param_cb(path, &firmware_param_ops, NULL, 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); static int