summary refs log tree commit diff
path: root/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-14 16:54:07 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-14 16:54:07 -0700
commit5a86102248592e178a9023359ccf7f0e489d8e35 (patch)
tree9e5fdb9aafca687fa412f7c034f2cfbb834b8567 /include
parent85082fd7cbe3173198aac0eb5e85ab1edcc6352c (diff)
parent751851af7aae9b8bd5a60b3897209081fbc18b2b (diff)
downloadlinux-5a86102248592e178a9023359ccf7f0e489d8e35.tar.gz
Merge branch 'for-2.6.27' of git://git.infradead.org/users/dwmw2/firmware-2.6
* 'for-2.6.27' of git://git.infradead.org/users/dwmw2/firmware-2.6: (64 commits)
  firmware: convert sb16_csp driver to use firmware loader exclusively
  dsp56k: use request_firmware
  edgeport-ti: use request_firmware()
  edgeport: use request_firmware()
  vicam: use request_firmware()
  dabusb: use request_firmware()
  cpia2: use request_firmware()
  ip2: use request_firmware()
  firmware: convert Ambassador ATM driver to request_firmware()
  whiteheat: use request_firmware()
  ti_usb_3410_5052: use request_firmware()
  emi62: use request_firmware()
  emi26: use request_firmware()
  keyspan_pda: use request_firmware()
  keyspan: use request_firmware()
  ttusb-budget: use request_firmware()
  kaweth: use request_firmware()
  smctr: use request_firmware()
  firmware: convert ymfpci driver to use firmware loader exclusively
  firmware: convert maestro3 driver to use firmware loader exclusively
  ...

Fix up trivial conflicts with BKL removal in drivers/char/dsp56k.c and
drivers/char/ip2/ip2main.c manually.
Diffstat (limited to 'include')
-rw-r--r--include/asm-generic/vmlinux.lds.h7
-rw-r--r--include/linux/firmware.h23
-rw-r--r--include/linux/ihex.h74
3 files changed, 103 insertions, 1 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bf2851f93937..b20409404c7d 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -88,6 +88,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) = .;		\
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 6c7eff2ebada..c8ecf5b2a207 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -1,18 +1,39 @@
 #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
 
 struct firmware {
 	size_t size;
-	u8 *data;
+	const u8 *data;
 };
 
 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);
diff --git a/include/linux/ihex.h b/include/linux/ihex.h
new file mode 100644
index 000000000000..2baace2788a7
--- /dev/null
+++ b/include/linux/ihex.h
@@ -0,0 +1,74 @@
+/*
+ * Compact binary representation of ihex records. Some devices need their
+ * firmware loaded in strange orders rather than a single big blob, but
+ * actually parsing ihex-as-text within the kernel seems silly. Thus,...
+ */
+
+#ifndef __LINUX_IHEX_H__
+#define __LINUX_IHEX_H__
+
+#include <linux/types.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+
+/* Intel HEX files actually limit the length to 256 bytes, but we have
+   drivers which would benefit from using separate records which are
+   longer than that, so we extend to 16 bits of length */
+struct ihex_binrec {
+	__be32 addr;
+	__be16 len;
+	uint8_t data[0];
+} __attribute__((aligned(4)));
+
+/* Find the next record, taking into account the 4-byte alignment */
+static inline const struct ihex_binrec *
+ihex_next_binrec(const struct ihex_binrec *rec)
+{
+	int next = ((be16_to_cpu(rec->len) + 5) & ~3) - 2;
+	rec = (void *)&rec->data[next];
+
+	return be16_to_cpu(rec->len) ? rec : NULL;
+}
+
+/* Check that ihex_next_binrec() won't take us off the end of the image... */
+static inline int ihex_validate_fw(const struct firmware *fw)
+{
+	const struct ihex_binrec *rec;
+	size_t ofs = 0;
+
+	while (ofs <= fw->size - sizeof(*rec)) {
+		rec = (void *)&fw->data[ofs];
+
+		/* Zero length marks end of records */
+		if (!be16_to_cpu(rec->len))
+			return 0;
+
+		/* Point to next record... */
+		ofs += (sizeof(*rec) + be16_to_cpu(rec->len) + 3) & ~3;
+	}
+	return -EINVAL;
+}
+
+/* Request firmware and validate it so that we can trust we won't
+ * run off the end while reading records... */
+static inline int request_ihex_firmware(const struct firmware **fw,
+					const char *fw_name,
+					struct device *dev)
+{
+	const struct firmware *lfw;
+	int ret;
+
+	ret = request_firmware(&lfw, fw_name, dev);
+	if (ret)
+		return ret;
+	ret = ihex_validate_fw(lfw);
+	if (ret) {
+		dev_err(dev, "Firmware \"%s\" not valid IHEX records\n",
+			fw_name);
+		release_firmware(lfw);
+		return ret;
+	}
+	*fw = lfw;
+	return 0;
+}
+#endif /* __LINUX_IHEX_H__ */