aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2006-11-06 21:52:16 -0500
committerDominik Brodowski <linux@dominikbrodowski.net>2006-12-04 20:09:15 -0500
commit1d2c90425d5b0dcbf4a0fab2053d5087758b76a0 (patch)
tree7c8aaa01b60e81843a3ca4124ccd9ea916fca145
parent3e022d0c77e159a59d3ebfc44ad76a05202c2a6b (diff)
[PATCH] pcmcia: multifunction card handling fixes
s->functions needs to be initialized earlier, for the "let's see how high it increases" approach means that pcmcia_request_irq() (which makes use of this value) is confused, and might request an exclusive IRQ first even though it is not supposed to. Also, a CIS override autoloaded using the firmware loader may allow for the use of more or less functions in a multifunction card. Therefore, we may need to schedule a call to add this second function later on, or simply remove the other function (it's always the first -valid- function which reaches this codepath). Many thanks to Fabrice Bellet for debugging and testing patches. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
-rw-r--r--drivers/pcmcia/ds.c153
-rw-r--r--include/pcmcia/ss.h5
2 files changed, 90 insertions, 68 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7f6e94cd067a..da7ceb523b48 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -231,65 +231,6 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
231} 231}
232 232
233 233
234#ifdef CONFIG_PCMCIA_LOAD_CIS
235
236/**
237 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
238 * @dev - the pcmcia device which needs a CIS override
239 * @filename - requested filename in /lib/firmware/
240 *
241 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
242 * the one provided by the card is broken. The firmware files reside in
243 * /lib/firmware/ in userspace.
244 */
245static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
246{
247 struct pcmcia_socket *s = dev->socket;
248 const struct firmware *fw;
249 char path[20];
250 int ret=-ENOMEM;
251 cisdump_t *cis;
252
253 if (!filename)
254 return -EINVAL;
255
256 ds_dbg(1, "trying to load firmware %s\n", filename);
257
258 if (strlen(filename) > 14)
259 return -EINVAL;
260
261 snprintf(path, 20, "%s", filename);
262
263 if (request_firmware(&fw, path, &dev->dev) == 0) {
264 if (fw->size >= CISTPL_MAX_CIS_SIZE)
265 goto release;
266
267 cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
268 if (!cis)
269 goto release;
270
271 cis->Length = fw->size + 1;
272 memcpy(cis->Data, fw->data, fw->size);
273
274 if (!pcmcia_replace_cis(s, cis))
275 ret = 0;
276 }
277 release:
278 release_firmware(fw);
279
280 return (ret);
281}
282
283#else /* !CONFIG_PCMCIA_LOAD_CIS */
284
285static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
286{
287 return -ENODEV;
288}
289
290#endif
291
292
293/*======================================================================*/ 234/*======================================================================*/
294 235
295 236
@@ -356,10 +297,11 @@ static void pcmcia_release_dev(struct device *dev)
356 kfree(p_dev); 297 kfree(p_dev);
357} 298}
358 299
359static void pcmcia_add_pseudo_device(struct pcmcia_socket *s) 300static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc)
360{ 301{
361 if (!s->pcmcia_state.device_add_pending) { 302 if (!s->pcmcia_state.device_add_pending) {
362 s->pcmcia_state.device_add_pending = 1; 303 s->pcmcia_state.device_add_pending = 1;
304 s->pcmcia_state.mfc_pfc = mfc;
363 schedule_work(&s->device_add); 305 schedule_work(&s->device_add);
364 } 306 }
365 return; 307 return;
@@ -400,7 +342,7 @@ static int pcmcia_device_probe(struct device * dev)
400 did = p_dev->dev.driver_data; 342 did = p_dev->dev.driver_data;
401 if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && 343 if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
402 (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) 344 (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
403 pcmcia_add_pseudo_device(p_dev->socket); 345 pcmcia_add_device_later(p_dev->socket, 0);
404 346
405 put_module: 347 put_module:
406 if (ret) 348 if (ret)
@@ -598,8 +540,6 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
598 p_dev->socket = s; 540 p_dev->socket = s;
599 p_dev->device_no = (s->device_count++); 541 p_dev->device_no = (s->device_count++);
600 p_dev->func = function; 542 p_dev->func = function;
601 if (s->functions <= function)
602 s->functions = function + 1;
603 543
604 p_dev->dev.bus = &pcmcia_bus_type; 544 p_dev->dev.bus = &pcmcia_bus_type;
605 p_dev->dev.parent = s->dev.dev; 545 p_dev->dev.parent = s->dev.dev;
@@ -690,6 +630,7 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
690 no_funcs = mfc.nfn; 630 no_funcs = mfc.nfn;
691 else 631 else
692 no_funcs = 1; 632 no_funcs = 1;
633 s->functions = no_funcs;
693 634
694 for (i=0; i < no_funcs; i++) 635 for (i=0; i < no_funcs; i++)
695 pcmcia_device_add(s, i); 636 pcmcia_device_add(s, i);
@@ -698,11 +639,12 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
698} 639}
699 640
700 641
701static void pcmcia_delayed_add_pseudo_device(void *data) 642static void pcmcia_delayed_add_device(void *data)
702{ 643{
703 struct pcmcia_socket *s = data; 644 struct pcmcia_socket *s = data;
704 pcmcia_device_add(s, 0); 645 pcmcia_device_add(s, s->pcmcia_state.mfc_pfc);
705 s->pcmcia_state.device_add_pending = 0; 646 s->pcmcia_state.device_add_pending = 0;
647 s->pcmcia_state.mfc_pfc = 0;
706} 648}
707 649
708static int pcmcia_requery(struct device *dev, void * _data) 650static int pcmcia_requery(struct device *dev, void * _data)
@@ -751,6 +693,85 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis)
751 printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n"); 693 printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n");
752} 694}
753 695
696#ifdef CONFIG_PCMCIA_LOAD_CIS
697
698/**
699 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
700 * @dev - the pcmcia device which needs a CIS override
701 * @filename - requested filename in /lib/firmware/
702 *
703 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
704 * the one provided by the card is broken. The firmware files reside in
705 * /lib/firmware/ in userspace.
706 */
707static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
708{
709 struct pcmcia_socket *s = dev->socket;
710 const struct firmware *fw;
711 char path[20];
712 int ret = -ENOMEM;
713 int no_funcs;
714 int old_funcs;
715 cisdump_t *cis;
716 cistpl_longlink_mfc_t mfc;
717
718 if (!filename)
719 return -EINVAL;
720
721 ds_dbg(1, "trying to load firmware %s\n", filename);
722
723 if (strlen(filename) > 14)
724 return -EINVAL;
725
726 snprintf(path, 20, "%s", filename);
727
728 if (request_firmware(&fw, path, &dev->dev) == 0) {
729 if (fw->size >= CISTPL_MAX_CIS_SIZE)
730 goto release;
731
732 cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
733 if (!cis)
734 goto release;
735
736 cis->Length = fw->size + 1;
737 memcpy(cis->Data, fw->data, fw->size);
738
739 if (!pcmcia_replace_cis(s, cis))
740 ret = 0;
741
742 /* update information */
743 pcmcia_device_query(dev);
744
745 /* does this cis override add or remove functions? */
746 old_funcs = s->functions;
747
748 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
749 no_funcs = mfc.nfn;
750 else
751 no_funcs = 1;
752 s->functions = no_funcs;
753
754 if (old_funcs > no_funcs)
755 pcmcia_card_remove(s, dev);
756 else if (no_funcs > old_funcs)
757 pcmcia_add_device_later(s, 1);
758 }
759 release:
760 release_firmware(fw);
761
762 return (ret);
763}
764
765#else /* !CONFIG_PCMCIA_LOAD_CIS */
766
767static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
768{
769 return -ENODEV;
770}
771
772#endif
773
774
754static inline int pcmcia_devmatch(struct pcmcia_device *dev, 775static inline int pcmcia_devmatch(struct pcmcia_device *dev,
755 struct pcmcia_device_id *did) 776 struct pcmcia_device_id *did)
756{ 777{
@@ -1250,7 +1271,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
1250 init_waitqueue_head(&socket->queue); 1271 init_waitqueue_head(&socket->queue);
1251#endif 1272#endif
1252 INIT_LIST_HEAD(&socket->devices_list); 1273 INIT_LIST_HEAD(&socket->devices_list);
1253 INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket); 1274 INIT_WORK(&socket->device_add, pcmcia_delayed_add_device, socket);
1254 memset(&socket->pcmcia_state, 0, sizeof(u8)); 1275 memset(&socket->pcmcia_state, 0, sizeof(u8));
1255 socket->device_count = 0; 1276 socket->device_count = 0;
1256 1277
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index ede639812f8a..623a0fc0dae1 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -262,9 +262,10 @@ struct pcmcia_socket {
262 u8 present:1, /* PCMCIA card is present in socket */ 262 u8 present:1, /* PCMCIA card is present in socket */
263 busy:1, /* "master" ioctl is used */ 263 busy:1, /* "master" ioctl is used */
264 dead:1, /* pcmcia module is being unloaded */ 264 dead:1, /* pcmcia module is being unloaded */
265 device_add_pending:1, /* a pseudo-multifunction-device 265 device_add_pending:1, /* a multifunction-device
266 * add event is pending */ 266 * add event is pending */
267 reserved:4; 267 mfc_pfc:1, /* the pending event adds a mfc (1) or pfc (0) */
268 reserved:3;
268 } pcmcia_state; 269 } pcmcia_state;
269 270
270 struct work_struct device_add; /* for adding further pseudo-multifunction 271 struct work_struct device_add; /* for adding further pseudo-multifunction