Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit daa9517d authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds
Browse files

[PATCH] pcmcia: request CIS via firmware interface



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: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 90829cfe
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -58,6 +58,20 @@ config PCMCIA


	   If unsure, say Y.
	   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
config CARDBUS
	bool "32-bit CardBus support"	
	bool "32-bit CardBus support"	
	depends on PCI
	depends on PCI
+67 −4
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/kref.h>
#include <linux/kref.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/firmware.h>


#include <asm/atomic.h>
#include <asm/atomic.h>


@@ -295,6 +296,68 @@ static inline void pcmcia_check_driver(struct pcmcia_driver *p_drv) {
}
}
#endif
#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);
static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
@@ -739,12 +802,12 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
	}
	}


	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
		if (!dev->socket->fake_cis) {
		if (!dev->socket->fake_cis)
			/* FIXME: evaluate using firmware helpers to
			pcmcia_load_firmware(dev, did->cisfile);
			 * automagically load it from userspace */

		if (!dev->socket->fake_cis)
			return 0;
			return 0;
	}
	}
	}


	if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
	if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
		int i;
		int i;