diff options
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 86 |
1 files changed, 40 insertions, 46 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index ad93ebd7b2a2..041eee43fd8d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
25 | #include <linux/kref.h> | 25 | #include <linux/kref.h> |
26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
27 | #include <linux/slab.h> | ||
27 | 28 | ||
28 | #include <pcmcia/cs_types.h> | 29 | #include <pcmcia/cs_types.h> |
29 | #include <pcmcia/cs.h> | 30 | #include <pcmcia/cs.h> |
@@ -334,7 +335,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le | |||
334 | 335 | ||
335 | mutex_lock(&s->ops_mutex); | 336 | mutex_lock(&s->ops_mutex); |
336 | list_del(&p_dev->socket_device_list); | 337 | list_del(&p_dev->socket_device_list); |
337 | p_dev->_removed = 1; | ||
338 | mutex_unlock(&s->ops_mutex); | 338 | mutex_unlock(&s->ops_mutex); |
339 | 339 | ||
340 | dev_dbg(&p_dev->dev, "unregistering device\n"); | 340 | dev_dbg(&p_dev->dev, "unregistering device\n"); |
@@ -509,8 +509,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu | |||
509 | p_dev->device_no = (s->device_count++); | 509 | p_dev->device_no = (s->device_count++); |
510 | mutex_unlock(&s->ops_mutex); | 510 | mutex_unlock(&s->ops_mutex); |
511 | 511 | ||
512 | /* max of 2 devices per card */ | 512 | /* max of 2 PFC devices */ |
513 | if (p_dev->device_no >= 2) | 513 | if ((p_dev->device_no >= 2) && (function == 0)) |
514 | goto err_free; | ||
515 | |||
516 | /* max of 4 devices overall */ | ||
517 | if (p_dev->device_no >= 4) | ||
514 | goto err_free; | 518 | goto err_free; |
515 | 519 | ||
516 | p_dev->socket = s; | 520 | p_dev->socket = s; |
@@ -649,14 +653,7 @@ static int pcmcia_requery_callback(struct device *dev, void * _data) | |||
649 | 653 | ||
650 | static void pcmcia_requery(struct pcmcia_socket *s) | 654 | static void pcmcia_requery(struct pcmcia_socket *s) |
651 | { | 655 | { |
652 | int present, has_pfc; | 656 | int has_pfc; |
653 | |||
654 | mutex_lock(&s->ops_mutex); | ||
655 | present = s->pcmcia_state.present; | ||
656 | mutex_unlock(&s->ops_mutex); | ||
657 | |||
658 | if (!present) | ||
659 | return; | ||
660 | 657 | ||
661 | if (s->functions == 0) { | 658 | if (s->functions == 0) { |
662 | pcmcia_card_add(s); | 659 | pcmcia_card_add(s); |
@@ -682,12 +679,10 @@ static void pcmcia_requery(struct pcmcia_socket *s) | |||
682 | new_funcs = mfc.nfn; | 679 | new_funcs = mfc.nfn; |
683 | else | 680 | else |
684 | new_funcs = 1; | 681 | new_funcs = 1; |
685 | if (old_funcs > new_funcs) { | 682 | if (old_funcs != new_funcs) { |
683 | /* we need to re-start */ | ||
686 | pcmcia_card_remove(s, NULL); | 684 | pcmcia_card_remove(s, NULL); |
687 | pcmcia_card_add(s); | 685 | pcmcia_card_add(s); |
688 | } else if (new_funcs > old_funcs) { | ||
689 | s->functions = new_funcs; | ||
690 | pcmcia_device_add(s, 1); | ||
691 | } | 686 | } |
692 | } | 687 | } |
693 | 688 | ||
@@ -723,6 +718,8 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | |||
723 | struct pcmcia_socket *s = dev->socket; | 718 | struct pcmcia_socket *s = dev->socket; |
724 | const struct firmware *fw; | 719 | const struct firmware *fw; |
725 | int ret = -ENOMEM; | 720 | int ret = -ENOMEM; |
721 | cistpl_longlink_mfc_t mfc; | ||
722 | int old_funcs, new_funcs = 1; | ||
726 | 723 | ||
727 | if (!filename) | 724 | if (!filename) |
728 | return -EINVAL; | 725 | return -EINVAL; |
@@ -745,6 +742,14 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | |||
745 | goto release; | 742 | goto release; |
746 | } | 743 | } |
747 | 744 | ||
745 | /* we need to re-start if the number of functions changed */ | ||
746 | old_funcs = s->functions; | ||
747 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, | ||
748 | &mfc)) | ||
749 | new_funcs = mfc.nfn; | ||
750 | |||
751 | if (old_funcs != new_funcs) | ||
752 | ret = -EBUSY; | ||
748 | 753 | ||
749 | /* update information */ | 754 | /* update information */ |
750 | pcmcia_device_query(dev); | 755 | pcmcia_device_query(dev); |
@@ -815,11 +820,12 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, | |||
815 | } | 820 | } |
816 | 821 | ||
817 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { | 822 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { |
818 | if (dev->device_no != did->device_no) | 823 | dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n"); |
819 | return 0; | ||
820 | mutex_lock(&dev->socket->ops_mutex); | 824 | mutex_lock(&dev->socket->ops_mutex); |
821 | dev->socket->pcmcia_state.has_pfc = 1; | 825 | dev->socket->pcmcia_state.has_pfc = 1; |
822 | mutex_unlock(&dev->socket->ops_mutex); | 826 | mutex_unlock(&dev->socket->ops_mutex); |
827 | if (dev->device_no != did->device_no) | ||
828 | return 0; | ||
823 | } | 829 | } |
824 | 830 | ||
825 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { | 831 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { |
@@ -830,7 +836,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, | |||
830 | 836 | ||
831 | /* if this is a pseudo-multi-function device, | 837 | /* if this is a pseudo-multi-function device, |
832 | * we need explicit matches */ | 838 | * we need explicit matches */ |
833 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) | 839 | if (dev->socket->pcmcia_state.has_pfc) |
834 | return 0; | 840 | return 0; |
835 | if (dev->device_no) | 841 | if (dev->device_no) |
836 | return 0; | 842 | return 0; |
@@ -853,10 +859,8 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, | |||
853 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { | 859 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { |
854 | dev_dbg(&dev->dev, "device needs a fake CIS\n"); | 860 | dev_dbg(&dev->dev, "device needs a fake CIS\n"); |
855 | if (!dev->socket->fake_cis) | 861 | if (!dev->socket->fake_cis) |
856 | pcmcia_load_firmware(dev, did->cisfile); | 862 | if (pcmcia_load_firmware(dev, did->cisfile)) |
857 | 863 | return 0; | |
858 | if (!dev->socket->fake_cis) | ||
859 | return 0; | ||
860 | } | 864 | } |
861 | 865 | ||
862 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { | 866 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { |
@@ -1249,9 +1253,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1249 | 1253 | ||
1250 | switch (event) { | 1254 | switch (event) { |
1251 | case CS_EVENT_CARD_REMOVAL: | 1255 | case CS_EVENT_CARD_REMOVAL: |
1252 | mutex_lock(&s->ops_mutex); | 1256 | atomic_set(&skt->present, 0); |
1253 | s->pcmcia_state.present = 0; | ||
1254 | mutex_unlock(&s->ops_mutex); | ||
1255 | pcmcia_card_remove(skt, NULL); | 1257 | pcmcia_card_remove(skt, NULL); |
1256 | handle_event(skt, event); | 1258 | handle_event(skt, event); |
1257 | mutex_lock(&s->ops_mutex); | 1259 | mutex_lock(&s->ops_mutex); |
@@ -1260,9 +1262,9 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1260 | break; | 1262 | break; |
1261 | 1263 | ||
1262 | case CS_EVENT_CARD_INSERTION: | 1264 | case CS_EVENT_CARD_INSERTION: |
1265 | atomic_set(&skt->present, 1); | ||
1263 | mutex_lock(&s->ops_mutex); | 1266 | mutex_lock(&s->ops_mutex); |
1264 | s->pcmcia_state.has_pfc = 0; | 1267 | s->pcmcia_state.has_pfc = 0; |
1265 | s->pcmcia_state.present = 1; | ||
1266 | destroy_cis_cache(s); /* to be on the safe side... */ | 1268 | destroy_cis_cache(s); /* to be on the safe side... */ |
1267 | mutex_unlock(&s->ops_mutex); | 1269 | mutex_unlock(&s->ops_mutex); |
1268 | pcmcia_card_add(skt); | 1270 | pcmcia_card_add(skt); |
@@ -1281,6 +1283,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1281 | destroy_cis_cache(skt); | 1283 | destroy_cis_cache(skt); |
1282 | kfree(skt->fake_cis); | 1284 | kfree(skt->fake_cis); |
1283 | skt->fake_cis = NULL; | 1285 | skt->fake_cis = NULL; |
1286 | s->functions = 0; | ||
1284 | mutex_unlock(&s->ops_mutex); | 1287 | mutex_unlock(&s->ops_mutex); |
1285 | /* now, add the new card */ | 1288 | /* now, add the new card */ |
1286 | ds_event(skt, CS_EVENT_CARD_INSERTION, | 1289 | ds_event(skt, CS_EVENT_CARD_INSERTION, |
@@ -1302,7 +1305,13 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1302 | return 0; | 1305 | return 0; |
1303 | } /* ds_event */ | 1306 | } /* ds_event */ |
1304 | 1307 | ||
1305 | 1308 | /* | |
1309 | * NOTE: This is racy. There's no guarantee the card will still be | ||
1310 | * physically present, even if the call to this function returns | ||
1311 | * non-NULL. Furthermore, the device driver most likely is unbound | ||
1312 | * almost immediately, so the timeframe where pcmcia_dev_present | ||
1313 | * returns NULL is probably really really small. | ||
1314 | */ | ||
1306 | struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) | 1315 | struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) |
1307 | { | 1316 | { |
1308 | struct pcmcia_device *p_dev; | 1317 | struct pcmcia_device *p_dev; |
@@ -1312,22 +1321,9 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) | |||
1312 | if (!p_dev) | 1321 | if (!p_dev) |
1313 | return NULL; | 1322 | return NULL; |
1314 | 1323 | ||
1315 | mutex_lock(&p_dev->socket->ops_mutex); | 1324 | if (atomic_read(&p_dev->socket->present) != 0) |
1316 | if (!p_dev->socket->pcmcia_state.present) | 1325 | ret = p_dev; |
1317 | goto out; | ||
1318 | |||
1319 | if (p_dev->socket->pcmcia_state.dead) | ||
1320 | goto out; | ||
1321 | 1326 | ||
1322 | if (p_dev->_removed) | ||
1323 | goto out; | ||
1324 | |||
1325 | if (p_dev->suspended) | ||
1326 | goto out; | ||
1327 | |||
1328 | ret = p_dev; | ||
1329 | out: | ||
1330 | mutex_unlock(&p_dev->socket->ops_mutex); | ||
1331 | pcmcia_put_dev(p_dev); | 1327 | pcmcia_put_dev(p_dev); |
1332 | return ret; | 1328 | return ret; |
1333 | } | 1329 | } |
@@ -1377,6 +1373,8 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev, | |||
1377 | return ret; | 1373 | return ret; |
1378 | } | 1374 | } |
1379 | 1375 | ||
1376 | atomic_set(&socket->present, 0); | ||
1377 | |||
1380 | return 0; | 1378 | return 0; |
1381 | } | 1379 | } |
1382 | 1380 | ||
@@ -1388,10 +1386,6 @@ static void pcmcia_bus_remove_socket(struct device *dev, | |||
1388 | if (!socket) | 1386 | if (!socket) |
1389 | return; | 1387 | return; |
1390 | 1388 | ||
1391 | mutex_lock(&socket->ops_mutex); | ||
1392 | socket->pcmcia_state.dead = 1; | ||
1393 | mutex_unlock(&socket->ops_mutex); | ||
1394 | |||
1395 | pccard_register_pcmcia(socket, NULL); | 1389 | pccard_register_pcmcia(socket, NULL); |
1396 | 1390 | ||
1397 | /* unregister any unbound devices */ | 1391 | /* unregister any unbound devices */ |