diff options
author | madmonkey <madfkingmonkey@gmail.com> | 2018-05-01 18:49:21 +0300 |
---|---|---|
committer | madmonkey <madfkingmonkey@gmail.com> | 2018-05-01 18:55:53 +0300 |
commit | 795013178ca07bb4907c19c32fe99e96c9ad1f35 (patch) | |
tree | 676391b45550123cd0a85953149c3840a5b1ea88 | |
parent | 4ccee6893c518c3285d315c05eeaca0f33e8382b (diff) |
firmware loader
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 74 |
2 files changed, 74 insertions, 2 deletions
@@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 4 SUBLEVEL = 112 -EXTRAVERSION = .17-madmonkey +EXTRAVERSION = .18-madmonkey NAME = Saber-toothed Squirrel # *DOCUMENTATION* diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b7a4fe58..c6db4560 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -21,6 +21,7 @@ #include <linux/firmware.h> #include <linux/slab.h> #include <linux/sched.h> +#include <linux/file.h> #define to_dev(obj) container_of(obj, struct device, kobj) @@ -28,6 +29,69 @@ MODULE_AUTHOR("Manuel Estrada Sainz"); MODULE_DESCRIPTION("Multi purpose firmware loading support"); MODULE_LICENSE("GPL"); +static const char *fw_path[] = { + "/var/lib/hakchi/rootfs/lib/firmware", + "/lib/firmware", + "/var/firmware" +}; + +/* Don't inline this: 'struct kstat' is biggish */ +static noinline long fw_file_size(struct file *file) +{ + struct kstat st; + if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) + return -1; + if (!S_ISREG(st.mode)) + return -1; + if (st.size != (long)st.size) + return -1; + return st.size; +} + +static bool fw_read_file_contents(struct file *file, struct firmware *fw) +{ + loff_t pos; + long size; + char *buf; + + size = fw_file_size(file); + if (size < 0) + return false; + 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; + char *path = __getname(); + + 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; + success = fw_read_file_contents(file, fw); + fput(file); + if (success) + break; + } + __putname(path); + return success; +} + /* Builtin firmware support */ #ifdef CONFIG_FW_LOADER @@ -199,7 +263,10 @@ static ssize_t firmware_loading_show(struct device *dev, static void firmware_free_data(const struct firmware *fw) { int i; - vunmap(fw->data); + if (fw->pages) + vunmap(fw->data); + else + vfree(fw->data); if (fw->pages) { for (i = 0; i < PFN_UP(fw->size); i++) __free_page(fw->pages[i]); @@ -492,6 +559,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; + } + fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); if (IS_ERR(fw_priv)) { release_firmware(firmware); |