pcmcia_dev_present is in and by itself buggy. Add a note specifying
why it is broken, and replace the broken locking -- taking a mutex
is a bad idea in IRQ context, from which this function is rarely
called -- by an atomic_t.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
mutex_lock(&s->ops_mutex);
list_del(&p_dev->socket_device_list);
mutex_lock(&s->ops_mutex);
list_del(&p_dev->socket_device_list);
mutex_unlock(&s->ops_mutex);
dev_dbg(&p_dev->dev, "unregistering device\n");
mutex_unlock(&s->ops_mutex);
dev_dbg(&p_dev->dev, "unregistering device\n");
static void pcmcia_requery(struct pcmcia_socket *s)
{
static void pcmcia_requery(struct pcmcia_socket *s)
{
- int present, has_pfc;
-
- mutex_lock(&s->ops_mutex);
- present = s->pcmcia_state.present;
- mutex_unlock(&s->ops_mutex);
-
- if (!present)
- return;
if (s->functions == 0) {
pcmcia_card_add(s);
if (s->functions == 0) {
pcmcia_card_add(s);
switch (event) {
case CS_EVENT_CARD_REMOVAL:
switch (event) {
case CS_EVENT_CARD_REMOVAL:
- mutex_lock(&s->ops_mutex);
- s->pcmcia_state.present = 0;
- mutex_unlock(&s->ops_mutex);
+ atomic_set(&skt->present, 0);
pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
mutex_lock(&s->ops_mutex);
pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
mutex_lock(&s->ops_mutex);
break;
case CS_EVENT_CARD_INSERTION:
break;
case CS_EVENT_CARD_INSERTION:
+ atomic_set(&skt->present, 1);
mutex_lock(&s->ops_mutex);
s->pcmcia_state.has_pfc = 0;
mutex_lock(&s->ops_mutex);
s->pcmcia_state.has_pfc = 0;
- s->pcmcia_state.present = 1;
destroy_cis_cache(s); /* to be on the safe side... */
mutex_unlock(&s->ops_mutex);
pcmcia_card_add(skt);
destroy_cis_cache(s); /* to be on the safe side... */
mutex_unlock(&s->ops_mutex);
pcmcia_card_add(skt);
return 0;
} /* ds_event */
return 0;
} /* ds_event */
+/*
+ * NOTE: This is racy. There's no guarantee the card will still be
+ * physically present, even if the call to this function returns
+ * non-NULL. Furthermore, the device driver most likely is unbound
+ * almost immediately, so the timeframe where pcmcia_dev_present
+ * returns NULL is probably really really small.
+ */
struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
{
struct pcmcia_device *p_dev;
- mutex_lock(&p_dev->socket->ops_mutex);
- if (!p_dev->socket->pcmcia_state.present)
- goto out;
+ if (atomic_read(&p_dev->socket->present) != 0)
+ ret = p_dev;
- if (p_dev->socket->pcmcia_state.dead)
- goto out;
-
- if (p_dev->_removed)
- goto out;
-
- if (p_dev->suspended)
- goto out;
-
- ret = p_dev;
- out:
- mutex_unlock(&p_dev->socket->ops_mutex);
pcmcia_put_dev(p_dev);
return ret;
}
pcmcia_put_dev(p_dev);
return ret;
}
+ atomic_set(&socket->present, 0);
+
- mutex_lock(&socket->ops_mutex);
- socket->pcmcia_state.dead = 1;
- mutex_unlock(&socket->ops_mutex);
-
pccard_register_pcmcia(socket, NULL);
/* unregister any unbound devices */
pccard_register_pcmcia(socket, NULL);
/* unregister any unbound devices */
#ifdef __KERNEL__
#include <linux/device.h>
#include <pcmcia/ss.h>
#ifdef __KERNEL__
#include <linux/device.h>
#include <pcmcia/ss.h>
/*
* PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus
/*
* PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus
config_req_t conf;
window_handle_t win;
config_req_t conf;
window_handle_t win;
- /* Is the device suspended, or in the process of
- * being removed? */
+ /* Is the device suspended? */
/* Flags whether io, irq, win configurations were
* requested, and whether the configuration is "locked" */
/* Flags whether io, irq, win configurations were
* requested, and whether the configuration is "locked" */
u16 has_card_id:1;
u16 has_func_id:1;
u16 has_card_id:1;
u16 has_func_id:1;
/* 16-bit state: */
struct {
/* 16-bit state: */
struct {
- /* PCMCIA card is present in socket */
- u8 present:1;
/* "master" ioctl is used */
u8 busy:1;
/* "master" ioctl is used */
u8 busy:1;
- /* pcmcia module is being unloaded */
- u8 dead:1;
/* the PCMCIA card consists of two pseudo devices */
u8 has_pfc:1;
/* the PCMCIA card consists of two pseudo devices */
u8 has_pfc:1;
+ /* non-zero if PCMCIA card is present */
+ atomic_t present;
#ifdef CONFIG_PCMCIA_IOCTL
struct user_info_t *user;
#ifdef CONFIG_PCMCIA_IOCTL
struct user_info_t *user;