DEBUG(1, "cs: shutdown_socket(%p)\n", s);
/* Blank out the socket state */
- s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING;
+ s->state &= SOCKET_PRESENT|SOCKET_INUSE;
s->socket = dead_socket;
s->ops->init(s);
s->irq.AssignedIRQ = s->irq.Config = 0;
pcmcia_error(skt, "unsupported voltage key.\n");
return CS_BAD_TYPE;
}
- skt->state |= SOCKET_PRESENT;
skt->socket.flags = SS_DEBOUNCED;
skt->ops->set_socket(skt, &skt->socket);
{
int ret;
- if (!try_module_get(skt->owner))
+ if (!cs_socket_get(skt))
return CS_NO_CARD;
ret = socket_setup(skt, setup_delay);
if (ret == CS_SUCCESS) {
+ skt->state |= SOCKET_PRESENT;
#ifdef CONFIG_CARDBUS
if (skt->state & SOCKET_CARDBUS) {
cb_alloc(skt);
skt->socket.flags &= ~SS_DEBOUNCED;
} else {
socket_shutdown(skt);
- module_put(skt->owner);
+ cs_socket_put(skt);
}
return ret;
}
skt->socket.flags &= ~SS_DEBOUNCED;
} else {
- unsigned int old_state = skt->state;
socket_shutdown(skt);
- if (old_state & SOCKET_PRESENT)
- module_put(skt->owner);
+ cs_socket_put(skt);
}
skt->state &= ~SOCKET_SUSPEND;
static void socket_remove(struct pcmcia_socket *skt)
{
socket_shutdown(skt);
- module_put(skt->owner);
+ cs_socket_put(skt);
}
/*
/*====================================================================*/
-int pcmcia_deregister_client(client_handle_t handle)
+int pcmcia_deregister_clientR(client_handle_t handle)
{
client_t **client;
struct pcmcia_socket *s;
status->CardState |= CS_EVENT_PM_SUSPEND;
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- if (s->state & SOCKET_SETUP_PENDING)
- status->CardState |= CS_EVENT_CARD_INSERTION;
/* Get info from the PRR, if necessary */
if (handle->Function == BIND_FN_ALL) {
if (client == NULL)
return CS_OUT_OF_RESOURCE;
+ /*
+ * Prevent this racing with a card insertion.
+ */
+ down(&s->skt_sem);
*handle = client;
client->state &= ~CLIENT_UNBOUND;
client->Socket = s;
s->config = kmalloc(sizeof(config_t) * s->functions,
GFP_KERNEL);
if (!s->config)
- return CS_OUT_OF_RESOURCE;
+ goto out_no_resource;
memset(s->config, 0, sizeof(config_t) * s->functions);
}
client, client->Socket, client->dev_info);
if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
- if ((s->state & SOCKET_PRESENT) &&
- !(s->state & SOCKET_SETUP_PENDING)) {
+
+ if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
if (client->EventMask & CS_EVENT_CARD_INSERTION)
EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
else
client->PendingEvents |= CS_EVENT_CARD_INSERTION;
}
+
+ up(&s->skt_sem);
return CS_SUCCESS;
+
+ out_no_resource:
+ up(&s->skt_sem);
+ return CS_OUT_OF_RESOURCE;
} /* register_client */
/*====================================================================*/
/* Flags in socket state */
#define SOCKET_PRESENT 0x0008
-#define SOCKET_SETUP_PENDING 0x0010
+#define SOCKET_INUSE 0x0010
#define SOCKET_SHUTDOWN_PENDING 0x0020
#define SOCKET_RESET_PENDING 0x0040
#define SOCKET_SUSPEND 0x0080
#define SOCKET_CARDBUS 0x8000
#define SOCKET_CARDBUS_CONFIG 0x10000
+static inline int cs_socket_get(struct pcmcia_socket *skt)
+{
+ int ret;
+
+ WARN_ON(skt->state & SOCKET_INUSE);
+
+ ret = try_module_get(skt->owner);
+ if (ret)
+ skt->state |= SOCKET_INUSE;
+ return ret;
+}
+
+static inline void cs_socket_put(struct pcmcia_socket *skt)
+{
+ if (skt->state & SOCKET_INUSE) {
+ skt->state &= ~SOCKET_INUSE;
+ module_put(skt->owner);
+ }
+}
+
#define CHECK_HANDLE(h) \
(((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))