diff options
-rw-r--r-- | drivers/base/firmware_class.c | 33 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 7 | ||||
-rw-r--r-- | include/linux/firmware.h | 21 |
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 | ||
53 | extern struct builtin_fw __start_builtin_fw[]; | ||
54 | extern struct builtin_fw __end_builtin_fw[]; | ||
55 | #else /* Module case. Avoid ifdefs later; it'll all optimise out */ | ||
56 | static struct builtin_fw *__start_builtin_fw; | ||
57 | static struct builtin_fw *__end_builtin_fw; | ||
58 | #endif | ||
59 | |||
52 | static void | 60 | static void |
53 | fw_load_abort(struct firmware_priv *fw_priv) | 61 | fw_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, | |||
473 | void | 494 | void |
474 | release_firmware(const struct firmware *fw) | 495 | release_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 | ||
14 | struct device; | 17 | struct device; |
15 | 18 | ||
19 | struct 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)) |
17 | int request_firmware(const struct firmware **fw, const char *name, | 38 | int request_firmware(const struct firmware **fw, const char *name, |
18 | struct device *device); | 39 | struct device *device); |