aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2008-05-23 08:52:42 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-07-10 09:30:13 -0400
commit5658c769443d543728b6c5c673dffc2df8676317 (patch)
tree539477c713c5d231fd3112e4bd8ae8aff4acefa7
parentb7a39bd0afc4021e8ad2b1189e884551e147427f (diff)
firmware: allow firmware files to be built into kernel image
Some drivers have their own hacks to bypass the kernel's firmware loader and build their firmware into the kernel; this renders those unnecessary. Other drivers don't use the firmware loader at all, because they always want the firmware to be available. This allows them to start using the firmware loader. A third set of drivers already use the firmware loader, but can't be used without help from userspace, which sometimes requires an initrd. This allows them to work in a static kernel. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--drivers/base/firmware_class.c33
-rw-r--r--include/asm-generic/vmlinux.lds.h7
-rw-r--r--include/linux/firmware.h21
3 files changed, 59 insertions, 2 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 264b3a2cd860..b0be1d18fee2 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -49,6 +49,14 @@ struct firmware_priv {
49 struct timer_list timeout; 49 struct timer_list timeout;
50}; 50};
51 51
52#ifdef CONFIG_FW_LOADER
53extern struct builtin_fw __start_builtin_fw[];
54extern struct builtin_fw __end_builtin_fw[];
55#else /* Module case. Avoid ifdefs later; it'll all optimise out */
56static struct builtin_fw *__start_builtin_fw;
57static struct builtin_fw *__end_builtin_fw;
58#endif
59
52static void 60static void
53fw_load_abort(struct firmware_priv *fw_priv) 61fw_load_abort(struct firmware_priv *fw_priv)
54{ 62{
@@ -391,13 +399,12 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
391 struct device *f_dev; 399 struct device *f_dev;
392 struct firmware_priv *fw_priv; 400 struct firmware_priv *fw_priv;
393 struct firmware *firmware; 401 struct firmware *firmware;
402 struct builtin_fw *builtin;
394 int retval; 403 int retval;
395 404
396 if (!firmware_p) 405 if (!firmware_p)
397 return -EINVAL; 406 return -EINVAL;
398 407
399 printk(KERN_INFO "firmware: requesting %s\n", name);
400
401 *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); 408 *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
402 if (!firmware) { 409 if (!firmware) {
403 printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", 410 printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
@@ -406,6 +413,20 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
406 goto out; 413 goto out;
407 } 414 }
408 415
416 for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
417 builtin++) {
418 if (strcmp(name, builtin->name))
419 continue;
420 printk(KERN_INFO "firmware: using built-in firmware %s\n",
421 name);
422 firmware->size = builtin->size;
423 firmware->data = builtin->data;
424 return 0;
425 }
426
427 if (uevent)
428 printk(KERN_INFO "firmware: requesting %s\n", name);
429
409 retval = fw_setup_device(firmware, &f_dev, name, device, uevent); 430 retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
410 if (retval) 431 if (retval)
411 goto error_kfree_fw; 432 goto error_kfree_fw;
@@ -473,8 +494,16 @@ request_firmware(const struct firmware **firmware_p, const char *name,
473void 494void
474release_firmware(const struct firmware *fw) 495release_firmware(const struct firmware *fw)
475{ 496{
497 struct builtin_fw *builtin;
498
476 if (fw) { 499 if (fw) {
500 for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
501 builtin++) {
502 if (fw->data == builtin->data)
503 goto free_fw;
504 }
477 vfree(fw->data); 505 vfree(fw->data);
506 free_fw:
478 kfree(fw); 507 kfree(fw);
479 } 508 }
480} 509}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f054778e916c..8d71a40625f3 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -86,6 +86,13 @@
86 VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ 86 VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \
87 } \ 87 } \
88 \ 88 \
89 /* Built-in firmware blobs */ \
90 .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
91 VMLINUX_SYMBOL(__start_builtin_fw) = .; \
92 *(.builtin_fw) \
93 VMLINUX_SYMBOL(__end_builtin_fw) = .; \
94 } \
95 \
89 /* RapidIO route ops */ \ 96 /* RapidIO route ops */ \
90 .rio_route : AT(ADDR(.rio_route) - LOAD_OFFSET) { \ 97 .rio_route : AT(ADDR(.rio_route) - LOAD_OFFSET) { \
91 VMLINUX_SYMBOL(__start_rio_route_ops) = .; \ 98 VMLINUX_SYMBOL(__start_rio_route_ops) = .; \
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 88718d60153c..c8ecf5b2a207 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -1,7 +1,10 @@
1#ifndef _LINUX_FIRMWARE_H 1#ifndef _LINUX_FIRMWARE_H
2#define _LINUX_FIRMWARE_H 2#define _LINUX_FIRMWARE_H
3
3#include <linux/module.h> 4#include <linux/module.h>
4#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/compiler.h>
7
5#define FIRMWARE_NAME_MAX 30 8#define FIRMWARE_NAME_MAX 30
6#define FW_ACTION_NOHOTPLUG 0 9#define FW_ACTION_NOHOTPLUG 0
7#define FW_ACTION_HOTPLUG 1 10#define FW_ACTION_HOTPLUG 1
@@ -13,6 +16,24 @@ struct firmware {
13 16
14struct device; 17struct device;
15 18
19struct builtin_fw {
20 char *name;
21 void *data;
22 unsigned long size;
23};
24
25/* We have to play tricks here much like stringify() to get the
26 __COUNTER__ macro to be expanded as we want it */
27#define __fw_concat1(x, y) x##y
28#define __fw_concat(x, y) __fw_concat1(x, y)
29
30#define DECLARE_BUILTIN_FIRMWARE(name, blob) \
31 DECLARE_BUILTIN_FIRMWARE_SIZE(name, &(blob), sizeof(blob))
32
33#define DECLARE_BUILTIN_FIRMWARE_SIZE(name, blob, size) \
34 static const struct builtin_fw __fw_concat(__builtin_fw,__COUNTER__) \
35 __used __section(.builtin_fw) = { name, blob, size }
36
16#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE)) 37#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE))
17int request_firmware(const struct firmware **fw, const char *name, 38int request_firmware(const struct firmware **fw, const char *name,
18 struct device *device); 39 struct device *device);