From dc773aafed08ca2213737eeedd206f8bdbb108c1 Mon Sep 17 00:00:00 2001
From: Alessandro Rubini <rubini@gnudd.com>
Date: Tue, 24 Jul 2012 23:01:43 +0200
Subject: [PATCH] new module fmc-write-eeprom (no tlv yet)

---
 kernel/Makefile           |   1 +
 kernel/fmc-write-eeprom.c | 118 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)
 create mode 100644 kernel/fmc-write-eeprom.c

diff --git a/kernel/Makefile b/kernel/Makefile
index 0383bf7..79cc8b8 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -6,6 +6,7 @@ ccflags-y = -I$M/include
 obj-m = fmc-core.o
 obj-m += spec.o
 obj-m += fmc-trivial.o
+obj-m += fmc-write-eeprom.o
 obj-m += wr-nic.o
 
 spec-y = spec-pci.o
diff --git a/kernel/fmc-write-eeprom.c b/kernel/fmc-write-eeprom.c
new file mode 100644
index 0000000..528c296
--- /dev/null
+++ b/kernel/fmc-write-eeprom.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 CERN (www.cern.ch)
+ * Author: Alessandro Rubini <rubini@gnudd.com>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ *
+ * This work is part of the White Rabbit project, a research effort led
+ * by CERN, the European Institute for Nuclear Research.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/firmware.h>
+#include <linux/init.h>
+#include <linux/fmc.h>
+
+/*
+ * This module uses the firmware loader to program the whole or part
+ * of the FMC eeprom. The meat is in the _run functions.  However, no
+ * default file name is provided, to avoid accidental mishaps.
+ */
+static char *fwe_file;
+module_param_named(file, fwe_file, charp, 444);
+
+static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw)
+{
+	dev_err(fmc->hwdev, "not implemented yet\n");
+	return -EOPNOTSUPP;
+}
+
+static int fwe_run_bin(struct fmc_device *fmc, const struct firmware *fw)
+{
+	int ret;
+
+	dev_info(fmc->hwdev, "programming %i bytes\n", fw->size);
+	ret = fmc->op->write_ee(fmc, 0, (void *)fw->data, fw->size);
+	if (ret < 0) {
+		dev_info(fmc->hwdev, "write_eeprom: error %i\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int fwe_run(struct fmc_device *fmc, const struct firmware *fw)
+{
+	char *last4 = fwe_file + strlen(fwe_file) - 4;
+
+	if (!strcmp(last4,".tlv"))
+		return fwe_run_tlv(fmc, fw);
+	if (!strcmp(last4,".bin"))
+		return fwe_run_bin(fmc, fw);
+	dev_err(fmc->hwdev, "invalid file name \"%s\"\n", fwe_file);
+	return -EINVAL;
+}
+
+/*
+ * Programming is done at probe time. Morever, if more than one FMC
+ * card is probed for, only one is programmed. Unfortunately, it's
+ * difficult to know in advance when probing the first card if others
+ * are there.
+ */
+int fwe_probe(struct fmc_device *fmc)
+{
+	int err;
+	static int done;
+	const struct firmware *fw;
+	struct device *dev = fmc->hwdev;
+
+	if (!fwe_file) {
+		dev_err(dev, "%s: no filename given: not programming\n",
+			KBUILD_MODNAME);
+		return -ENOENT;
+	}
+	if (done) {
+		dev_err(dev, "%s: refusing to program another card\n",
+			KBUILD_MODNAME);
+		return -EAGAIN;
+	}
+	done++; /* we are starting with this board, don't do any more */
+	err = request_firmware(&fw, fwe_file, dev);
+	if (err < 0) {
+		dev_err(dev, "request firmware \"%s\": error %i\n",
+			fwe_file, err);
+		return err;
+	}
+	fwe_run(fmc, fw);
+	release_firmware(fw);
+	return 0;
+}
+
+int fwe_remove(struct fmc_device *fmc)
+{
+	return 0;
+}
+
+static struct fmc_driver fwe_drv = {
+	.driver.name = KBUILD_MODNAME,
+	.probe = fwe_probe,
+	.remove = fwe_remove,
+	/* no table, as the current match just matches everything */
+};
+
+static int fwe_init(void)
+{
+	int ret;
+
+	ret = fmc_driver_register(&fwe_drv);
+	return ret;
+}
+
+static void fwe_exit(void)
+{
+	fmc_driver_unregister(&fwe_drv);
+}
+
+module_init(fwe_init);
+module_exit(fwe_exit);
+
+MODULE_LICENSE("GPL");
-- 
GitLab