
From: Dominik Brodowski <linux@dominikbrodowski.net>

Use the firmware method to load replacement CIS tables.  It is recommended
that the /lib/firmware/cis/ points to /etc/pcmcia/cis or the other way round
so that both old-style cardmgr and new-style hotplug/firmware can access these
"overwrite" files

Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/pcmcia/Kconfig |   14 ++++++++
 25-akpm/drivers/pcmcia/ds.c    |   71 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 81 insertions(+), 4 deletions(-)

diff -puN drivers/pcmcia/ds.c~pcmcia-request-cis-via-firmware-interface drivers/pcmcia/ds.c
--- 25/drivers/pcmcia/ds.c~pcmcia-request-cis-via-firmware-interface	Sun Mar  6 17:28:08 2005
+++ 25-akpm/drivers/pcmcia/ds.c	Sun Mar  6 17:28:08 2005
@@ -36,6 +36,7 @@
 #include <linux/kref.h>
 #include <linux/workqueue.h>
 #include <linux/crc32.h>
+#include <linux/firmware.h>
 
 #include <asm/atomic.h>
 
@@ -295,6 +296,68 @@ static inline void pcmcia_check_driver(s
 }
 #endif
 
+
+#ifdef CONFIG_PCMCIA_LOAD_CIS
+
+/**
+ * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
+ * @dev - the pcmcia device which needs a CIS override
+ * @filename - requested filename in /lib/firmware/cis/
+ *
+ * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
+ * the one provided by the card is broken. The firmware files reside in
+ * /lib/firmware/cis/ in userspace.
+ */
+static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
+{
+	struct pcmcia_socket *s = dev->socket;
+	const struct firmware *fw;
+	char path[20];
+	int ret=-ENOMEM;
+	cisdump_t *cis;
+
+	if (!filename)
+		return -EINVAL;
+
+	ds_dbg(1, "trying to load firmware %s\n", filename);
+
+	if (strlen(filename) > 14)
+		return -EINVAL;
+
+	snprintf(path, 20, "%s", filename);
+
+	if (request_firmware(&fw, path, &dev->dev) == 0) {
+		if (fw->size >= CISTPL_MAX_CIS_SIZE)
+			goto release;
+
+		cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+		if (!cis)
+			goto release;
+
+		memset(cis, 0, sizeof(cisdump_t));
+
+		cis->Length = fw->size + 1;
+		memcpy(cis->Data, fw->data, fw->size);
+
+		if (!pcmcia_replace_cis(s, cis))
+			ret = 0;
+	}
+ release:
+	release_firmware(fw);
+
+	return (ret);
+}
+
+#else /* !CONFIG_PCMCIA_LOAD_CIS */
+
+static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
+{
+	return -ENODEV;
+}
+
+#endif
+
+
 /*======================================================================*/
 
 static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
@@ -739,11 +802,11 @@ static inline int pcmcia_devmatch(struct
 	}
 
 	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
-		if (!dev->socket->fake_cis) {
-			/* FIXME: evaluate using firmware helpers to
-			 * automagically load it from userspace */
+		if (!dev->socket->fake_cis)
+			pcmcia_load_firmware(dev, did->cisfile);
+
+		if (!dev->socket->fake_cis)
 			return 0;
-		}
 	}
 
 	if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
diff -puN drivers/pcmcia/Kconfig~pcmcia-request-cis-via-firmware-interface drivers/pcmcia/Kconfig
--- 25/drivers/pcmcia/Kconfig~pcmcia-request-cis-via-firmware-interface	Sun Mar  6 17:28:08 2005
+++ 25-akpm/drivers/pcmcia/Kconfig	Sun Mar  6 17:28:08 2005
@@ -58,6 +58,20 @@ config PCMCIA
 
 	   If unsure, say Y.
 
+config PCMCIA_LOAD_CIS
+	bool "Load CIS updates from userspace (EXPERIMENTAL)"
+	depends on PCMCIA && EXPERIMENTAL
+	select FW_LOADER
+	default y
+	help
+	  Some PCMCIA cards require an updated Card Information Structure (CIS)
+	  to be loaded from userspace to work correctly. If you say Y here,
+	  and your userspace is arranged correctly, this will be loaded
+	  automatically using the in-kernel firmware loader and the hotplug
+	  subsystem, instead of relying on cardmgr from pcmcia-cs to do so.
+
+	  If unsure, say Y.
+
 config CARDBUS
 	bool "32-bit CardBus support"	
 	depends on PCI
_
