aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pcmcia/ds.c54
-rw-r--r--include/pcmcia/ds.h7
-rw-r--r--include/pcmcia/ss.h8
3 files changed, 24 insertions, 45 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 4014cf8e4a26..508f94a2a78d 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -335,7 +335,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
335 335
336 mutex_lock(&s->ops_mutex); 336 mutex_lock(&s->ops_mutex);
337 list_del(&p_dev->socket_device_list); 337 list_del(&p_dev->socket_device_list);
338 p_dev->_removed = 1;
339 mutex_unlock(&s->ops_mutex); 338 mutex_unlock(&s->ops_mutex);
340 339
341 dev_dbg(&p_dev->dev, "unregistering device\n"); 340 dev_dbg(&p_dev->dev, "unregistering device\n");
@@ -654,14 +653,7 @@ static int pcmcia_requery_callback(struct device *dev, void * _data)
654 653
655static void pcmcia_requery(struct pcmcia_socket *s) 654static void pcmcia_requery(struct pcmcia_socket *s)
656{ 655{
657 int present, has_pfc; 656 int has_pfc;
658
659 mutex_lock(&s->ops_mutex);
660 present = s->pcmcia_state.present;
661 mutex_unlock(&s->ops_mutex);
662
663 if (!present)
664 return;
665 657
666 if (s->functions == 0) { 658 if (s->functions == 0) {
667 pcmcia_card_add(s); 659 pcmcia_card_add(s);
@@ -828,11 +820,12 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
828 } 820 }
829 821
830 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { 822 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
831 if (dev->device_no != did->device_no) 823 dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
832 return 0;
833 mutex_lock(&dev->socket->ops_mutex); 824 mutex_lock(&dev->socket->ops_mutex);
834 dev->socket->pcmcia_state.has_pfc = 1; 825 dev->socket->pcmcia_state.has_pfc = 1;
835 mutex_unlock(&dev->socket->ops_mutex); 826 mutex_unlock(&dev->socket->ops_mutex);
827 if (dev->device_no != did->device_no)
828 return 0;
836 } 829 }
837 830
838 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { 831 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
@@ -843,7 +836,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
843 836
844 /* if this is a pseudo-multi-function device, 837 /* if this is a pseudo-multi-function device,
845 * we need explicit matches */ 838 * we need explicit matches */
846 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) 839 if (dev->socket->pcmcia_state.has_pfc)
847 return 0; 840 return 0;
848 if (dev->device_no) 841 if (dev->device_no)
849 return 0; 842 return 0;
@@ -1260,9 +1253,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
1260 1253
1261 switch (event) { 1254 switch (event) {
1262 case CS_EVENT_CARD_REMOVAL: 1255 case CS_EVENT_CARD_REMOVAL:
1263 mutex_lock(&s->ops_mutex); 1256 atomic_set(&skt->present, 0);
1264 s->pcmcia_state.present = 0;
1265 mutex_unlock(&s->ops_mutex);
1266 pcmcia_card_remove(skt, NULL); 1257 pcmcia_card_remove(skt, NULL);
1267 handle_event(skt, event); 1258 handle_event(skt, event);
1268 mutex_lock(&s->ops_mutex); 1259 mutex_lock(&s->ops_mutex);
@@ -1271,9 +1262,9 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
1271 break; 1262 break;
1272 1263
1273 case CS_EVENT_CARD_INSERTION: 1264 case CS_EVENT_CARD_INSERTION:
1265 atomic_set(&skt->present, 1);
1274 mutex_lock(&s->ops_mutex); 1266 mutex_lock(&s->ops_mutex);
1275 s->pcmcia_state.has_pfc = 0; 1267 s->pcmcia_state.has_pfc = 0;
1276 s->pcmcia_state.present = 1;
1277 destroy_cis_cache(s); /* to be on the safe side... */ 1268 destroy_cis_cache(s); /* to be on the safe side... */
1278 mutex_unlock(&s->ops_mutex); 1269 mutex_unlock(&s->ops_mutex);
1279 pcmcia_card_add(skt); 1270 pcmcia_card_add(skt);
@@ -1313,7 +1304,13 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
1313 return 0; 1304 return 0;
1314} /* ds_event */ 1305} /* ds_event */
1315 1306
1316 1307/*
1308 * NOTE: This is racy. There's no guarantee the card will still be
1309 * physically present, even if the call to this function returns
1310 * non-NULL. Furthermore, the device driver most likely is unbound
1311 * almost immediately, so the timeframe where pcmcia_dev_present
1312 * returns NULL is probably really really small.
1313 */
1317struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) 1314struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
1318{ 1315{
1319 struct pcmcia_device *p_dev; 1316 struct pcmcia_device *p_dev;
@@ -1323,22 +1320,9 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
1323 if (!p_dev) 1320 if (!p_dev)
1324 return NULL; 1321 return NULL;
1325 1322
1326 mutex_lock(&p_dev->socket->ops_mutex); 1323 if (atomic_read(&p_dev->socket->present) != 0)
1327 if (!p_dev->socket->pcmcia_state.present) 1324 ret = p_dev;
1328 goto out;
1329
1330 if (p_dev->socket->pcmcia_state.dead)
1331 goto out;
1332 1325
1333 if (p_dev->_removed)
1334 goto out;
1335
1336 if (p_dev->suspended)
1337 goto out;
1338
1339 ret = p_dev;
1340 out:
1341 mutex_unlock(&p_dev->socket->ops_mutex);
1342 pcmcia_put_dev(p_dev); 1326 pcmcia_put_dev(p_dev);
1343 return ret; 1327 return ret;
1344} 1328}
@@ -1388,6 +1372,8 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
1388 return ret; 1372 return ret;
1389 } 1373 }
1390 1374
1375 atomic_set(&socket->present, 0);
1376
1391 return 0; 1377 return 0;
1392} 1378}
1393 1379
@@ -1399,10 +1385,6 @@ static void pcmcia_bus_remove_socket(struct device *dev,
1399 if (!socket) 1385 if (!socket)
1400 return; 1386 return;
1401 1387
1402 mutex_lock(&socket->ops_mutex);
1403 socket->pcmcia_state.dead = 1;
1404 mutex_unlock(&socket->ops_mutex);
1405
1406 pccard_register_pcmcia(socket, NULL); 1388 pccard_register_pcmcia(socket, NULL);
1407 1389
1408 /* unregister any unbound devices */ 1390 /* unregister any unbound devices */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index d57847f2f6c1..aab3c13dc310 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -26,6 +26,7 @@
26#ifdef __KERNEL__ 26#ifdef __KERNEL__
27#include <linux/device.h> 27#include <linux/device.h>
28#include <pcmcia/ss.h> 28#include <pcmcia/ss.h>
29#include <asm/atomic.h>
29 30
30/* 31/*
31 * PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus 32 * PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus
@@ -94,10 +95,8 @@ struct pcmcia_device {
94 config_req_t conf; 95 config_req_t conf;
95 window_handle_t win; 96 window_handle_t win;
96 97
97 /* Is the device suspended, or in the process of 98 /* Is the device suspended? */
98 * being removed? */
99 u16 suspended:1; 99 u16 suspended:1;
100 u16 _removed:1;
101 100
102 /* Flags whether io, irq, win configurations were 101 /* Flags whether io, irq, win configurations were
103 * requested, and whether the configuration is "locked" */ 102 * requested, and whether the configuration is "locked" */
@@ -115,7 +114,7 @@ struct pcmcia_device {
115 u16 has_card_id:1; 114 u16 has_card_id:1;
116 u16 has_func_id:1; 115 u16 has_func_id:1;
117 116
118 u16 reserved:3; 117 u16 reserved:4;
119 118
120 u8 func_id; 119 u8 func_id;
121 u16 manf_id; 120 u16 manf_id;
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 2e488b60bc76..344705cb42f4 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -224,18 +224,16 @@ struct pcmcia_socket {
224 224
225 /* 16-bit state: */ 225 /* 16-bit state: */
226 struct { 226 struct {
227 /* PCMCIA card is present in socket */
228 u8 present:1;
229 /* "master" ioctl is used */ 227 /* "master" ioctl is used */
230 u8 busy:1; 228 u8 busy:1;
231 /* pcmcia module is being unloaded */
232 u8 dead:1;
233 /* the PCMCIA card consists of two pseudo devices */ 229 /* the PCMCIA card consists of two pseudo devices */
234 u8 has_pfc:1; 230 u8 has_pfc:1;
235 231
236 u8 reserved:4; 232 u8 reserved:6;
237 } pcmcia_state; 233 } pcmcia_state;
238 234
235 /* non-zero if PCMCIA card is present */
236 atomic_t present;
239 237
240#ifdef CONFIG_PCMCIA_IOCTL 238#ifdef CONFIG_PCMCIA_IOCTL
241 struct user_info_t *user; 239 struct user_info_t *user;