aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/ds.c
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2005-06-27 19:28:14 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-27 21:03:08 -0400
commitdaa9517d9eccc3598b2b0cdfa0b016ae4a4fcdce (patch)
treee62d4533e29344a9e0259020e8e3818ecb6f220e /drivers/pcmcia/ds.c
parent90829cfe1df2466c98a831f6c44f71026665cec1 (diff)
[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>
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r--drivers/pcmcia/ds.c71
1 files changed, 67 insertions, 4 deletions
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 */
311static 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
353static 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
300static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); 363static 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) {