Skip to content

Commit

Permalink
firmware: allow firmware files to be built into kernel image
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Jul 10, 2008
1 parent b7a39bd commit 5658c76
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
33 changes: 31 additions & 2 deletions drivers/base/firmware_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ struct firmware_priv {
struct timer_list timeout;
};

#ifdef CONFIG_FW_LOADER
extern struct builtin_fw __start_builtin_fw[];
extern struct builtin_fw __end_builtin_fw[];
#else /* Module case. Avoid ifdefs later; it'll all optimise out */
static struct builtin_fw *__start_builtin_fw;
static struct builtin_fw *__end_builtin_fw;
#endif

static void
fw_load_abort(struct firmware_priv *fw_priv)
{
Expand Down Expand Up @@ -391,13 +399,12 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
struct device *f_dev;
struct firmware_priv *fw_priv;
struct firmware *firmware;
struct builtin_fw *builtin;
int retval;

if (!firmware_p)
return -EINVAL;

printk(KERN_INFO "firmware: requesting %s\n", name);

*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
Expand All @@ -406,6 +413,20 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
goto out;
}

for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
builtin++) {
if (strcmp(name, builtin->name))
continue;
printk(KERN_INFO "firmware: using built-in firmware %s\n",
name);
firmware->size = builtin->size;
firmware->data = builtin->data;
return 0;
}

if (uevent)
printk(KERN_INFO "firmware: requesting %s\n", name);

retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
if (retval)
goto error_kfree_fw;
Expand Down Expand Up @@ -473,8 +494,16 @@ request_firmware(const struct firmware **firmware_p, const char *name,
void
release_firmware(const struct firmware *fw)
{
struct builtin_fw *builtin;

if (fw) {
for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
builtin++) {
if (fw->data == builtin->data)
goto free_fw;
}
vfree(fw->data);
free_fw:
kfree(fw);
}
}
Expand Down
7 changes: 7 additions & 0 deletions include/asm-generic/vmlinux.lds.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@
VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \
} \
\
/* Built-in firmware blobs */ \
.builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_builtin_fw) = .; \
*(.builtin_fw) \
VMLINUX_SYMBOL(__end_builtin_fw) = .; \
} \
\
/* RapidIO route ops */ \
.rio_route : AT(ADDR(.rio_route) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_rio_route_ops) = .; \
Expand Down
21 changes: 21 additions & 0 deletions include/linux/firmware.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#ifndef _LINUX_FIRMWARE_H
#define _LINUX_FIRMWARE_H

#include <linux/module.h>
#include <linux/types.h>
#include <linux/compiler.h>

#define FIRMWARE_NAME_MAX 30
#define FW_ACTION_NOHOTPLUG 0
#define FW_ACTION_HOTPLUG 1
Expand All @@ -13,6 +16,24 @@ struct firmware {

struct device;

struct builtin_fw {
char *name;
void *data;
unsigned long size;
};

/* We have to play tricks here much like stringify() to get the
__COUNTER__ macro to be expanded as we want it */
#define __fw_concat1(x, y) x##y
#define __fw_concat(x, y) __fw_concat1(x, y)

#define DECLARE_BUILTIN_FIRMWARE(name, blob) \
DECLARE_BUILTIN_FIRMWARE_SIZE(name, &(blob), sizeof(blob))

#define DECLARE_BUILTIN_FIRMWARE_SIZE(name, blob, size) \
static const struct builtin_fw __fw_concat(__builtin_fw,__COUNTER__) \
__used __section(.builtin_fw) = { name, blob, size }

#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE))
int request_firmware(const struct firmware **fw, const char *name,
struct device *device);
Expand Down

0 comments on commit 5658c76

Please sign in to comment.