[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: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
90829cfe1d
commit
daa9517d9e
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user