diff options
-rw-r--r-- | drivers/pcmcia/Kconfig | 14 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 71 |
2 files changed, 81 insertions, 4 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 14e4124e1523..22f7e8ca6584 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -58,6 +58,20 @@ config PCMCIA | |||
58 | 58 | ||
59 | If unsure, say Y. | 59 | If unsure, say Y. |
60 | 60 | ||
61 | config PCMCIA_LOAD_CIS | ||
62 | bool "Load CIS updates from userspace (EXPERIMENTAL)" | ||
63 | depends on PCMCIA && EXPERIMENTAL | ||
64 | select FW_LOADER | ||
65 | default y | ||
66 | help | ||
67 | Some PCMCIA cards require an updated Card Information Structure (CIS) | ||
68 | to be loaded from userspace to work correctly. If you say Y here, | ||
69 | and your userspace is arranged correctly, this will be loaded | ||
70 | automatically using the in-kernel firmware loader and the hotplug | ||
71 | subsystem, instead of relying on cardmgr from pcmcia-cs to do so. | ||
72 | |||
73 | If unsure, say Y. | ||
74 | |||
61 | config CARDBUS | 75 | config CARDBUS |
62 | bool "32-bit CardBus support" | 76 | bool "32-bit CardBus support" |
63 | depends on PCI | 77 | depends on PCI |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 19b7dacdbe7a..5c88ff8e7d7e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/kref.h> | 36 | #include <linux/kref.h> |
37 | #include <linux/workqueue.h> | 37 | #include <linux/workqueue.h> |
38 | #include <linux/crc32.h> | 38 | #include <linux/crc32.h> |
39 | #include <linux/firmware.h> | ||
39 | 40 | ||
40 | #include <asm/atomic.h> | 41 | #include <asm/atomic.h> |
41 | 42 | ||
@@ -295,6 +296,68 @@ static inline void pcmcia_check_driver(struct pcmcia_driver *p_drv) { | |||
295 | } | 296 | } |
296 | #endif | 297 | #endif |
297 | 298 | ||
299 | |||
300 | #ifdef CONFIG_PCMCIA_LOAD_CIS | ||
301 | |||
302 | /** | ||
303 | * pcmcia_load_firmware - load CIS from userspace if device-provided is broken | ||
304 | * @dev - the pcmcia device which needs a CIS override | ||
305 | * @filename - requested filename in /lib/firmware/cis/ | ||
306 | * | ||
307 | * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if | ||
308 | * the one provided by the card is broken. The firmware files reside in | ||
309 | * /lib/firmware/cis/ in userspace. | ||
310 | */ | ||
311 | static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | ||
312 | { | ||
313 | struct pcmcia_socket *s = dev->socket; | ||
314 | const struct firmware *fw; | ||
315 | char path[20]; | ||
316 | int ret=-ENOMEM; | ||
317 | cisdump_t *cis; | ||
318 | |||
319 | if (!filename) | ||
320 | return -EINVAL; | ||
321 | |||
322 | ds_dbg(1, "trying to load firmware %s\n", filename); | ||
323 | |||
324 | if (strlen(filename) > 14) | ||
325 | return -EINVAL; | ||
326 | |||
327 | snprintf(path, 20, "%s", filename); | ||
328 | |||
329 | if (request_firmware(&fw, path, &dev->dev) == 0) { | ||
330 | if (fw->size >= CISTPL_MAX_CIS_SIZE) | ||
331 | goto release; | ||
332 | |||
333 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | ||
334 | if (!cis) | ||
335 | goto release; | ||
336 | |||
337 | memset(cis, 0, sizeof(cisdump_t)); | ||
338 | |||
339 | cis->Length = fw->size + 1; | ||
340 | memcpy(cis->Data, fw->data, fw->size); | ||
341 | |||
342 | if (!pcmcia_replace_cis(s, cis)) | ||
343 | ret = 0; | ||
344 | } | ||
345 | release: | ||
346 | release_firmware(fw); | ||
347 | |||
348 | return (ret); | ||
349 | } | ||
350 | |||
351 | #else /* !CONFIG_PCMCIA_LOAD_CIS */ | ||
352 | |||
353 | static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | ||
354 | { | ||
355 | return -ENODEV; | ||
356 | } | ||
357 | |||
358 | #endif | ||
359 | |||
360 | |||
298 | /*======================================================================*/ | 361 | /*======================================================================*/ |
299 | 362 | ||
300 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); | 363 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); |
@@ -739,11 +802,11 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, | |||
739 | } | 802 | } |
740 | 803 | ||
741 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { | 804 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { |
742 | if (!dev->socket->fake_cis) { | 805 | if (!dev->socket->fake_cis) |
743 | /* FIXME: evaluate using firmware helpers to | 806 | pcmcia_load_firmware(dev, did->cisfile); |
744 | * automagically load it from userspace */ | 807 | |
808 | if (!dev->socket->fake_cis) | ||
745 | return 0; | 809 | return 0; |
746 | } | ||
747 | } | 810 | } |
748 | 811 | ||
749 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { | 812 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { |