drivers/base/firmware_class.c | 59 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 6e210802c37b..2ffcb4030065 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -55,6 +55,54 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name) return false; } +static bool fw_read_file_contents(struct file *file, struct firmware *fw) +{ + loff_t size, pos; + struct inode *inode = file->f_dentry->d_inode; + char *buf; + + if (!S_ISREG(inode->i_mode)) + return false; + size = i_size_read(inode); + buf = vmalloc(size); + if (!buf) + return false; + pos = 0; + if (vfs_read(file, buf, size, &pos) != size) { + vfree(buf); + return false; + } + fw->data = buf; + fw->size = size; + return true; +} + +static bool fw_get_filesystem_firmware(struct firmware *fw, const char *name) +{ + int i; + bool success = false; + const char *fw_path[] = { "/lib/firmware/update", "/firmware", "/lib/firmware" }; + char *path = __getname(); + +printk("Trying to load fw '%s' ", name); + for (i = 0; i < ARRAY_SIZE(fw_path); i++) { + struct file *file; + snprintf(path, PATH_MAX, "%s/%s", fw_path[i], name); + + file = filp_open(path, O_RDONLY, 0); + if (IS_ERR(file)) + continue; +printk("from file '%s' ", path); + success = fw_read_file_contents(file, fw); + filp_close(file, NULL); + if (success) + break; + } +printk(" %s.\n", success ? "Ok" : "failed"); + __putname(path); + return success; +} + static bool fw_is_builtin_firmware(const struct firmware *fw) { struct builtin_fw *b_fw; @@ -346,7 +394,11 @@ static ssize_t firmware_loading_show(struct device *dev, /* firmware holds the ownership of pages */ static void firmware_free_data(const struct firmware *fw) { - WARN_ON(!fw->priv); + /* Loaded directly? */ + if (!fw->priv) { + vfree(fw->data); + return; + } fw_free_buf(fw->priv); } @@ -709,6 +761,11 @@ _request_firmware_prepare(const struct firmware **firmware_p, const char *name, return NULL; } + if (fw_get_filesystem_firmware(firmware, name)) { + dev_dbg(device, "firmware: direct-loading firmware %s\n", name); + return NULL; + } + ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf); if (!ret) fw_priv = fw_create_instance(firmware, name, device,