======================================================================*/
-static int pcmcia_send_event(struct pcmcia_socket *s, event_t event, int priority)
+/* NOTE: send_event needs to be called with skt->sem held. */
+
+static int send_event(struct pcmcia_socket *s, event_t event, int priority)
{
int ret;
+ if (s->state & SOCKET_CARDBUS)
+ return 0;
+
+ cs_dbg(s, 1, "send_event(event %d, pri %d, callback 0x%p)\n",
+ event, priority, s->callback);
+
if (!s->callback)
return 0;
if (!try_module_get(s->callback->owner))
return ret;
}
-
-/* NOTE: send_event needs to be called with skt->sem held. */
-
-static int send_event(struct pcmcia_socket *s, event_t event, int priority)
-{
- client_t *client = s->clients;
- int ret;
- cs_dbg(s, 1, "send_event(event %d, pri %d)\n",
- event, priority);
- ret = 0;
- if (s->state & SOCKET_CARDBUS)
- return 0;
-
- ret = pcmcia_send_event(s, event, priority);
- if (ret)
- return (ret);
-
- for (; client; client = client->next) {
- if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
- continue;
- if (client->EventMask & event) {
- ret = EVENT(client, event, priority);
- if (ret != 0)
- return ret;
- }
- }
- return ret;
-} /* send_event */
-
static void socket_remove_drivers(struct pcmcia_socket *skt)
{
client_t *client;
s->callback = c;
if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT)
- pcmcia_send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
} else
s->callback = NULL;
err:
user_info_t *user;
int req_pending, req_result;
wait_queue_head_t queue, request;
- struct work_struct removal;
socket_bind_t *bind;
struct pcmcia_socket *parent;
};
return CS_SUCCESS;
}
-static void handle_removal(void *data)
-{
- struct pcmcia_bus_socket *s = data;
- handle_event(s, CS_EVENT_CARD_REMOVAL);
- s->state &= ~DS_SOCKET_REMOVAL_PENDING;
-}
-
/*======================================================================
The card status event handler.
======================================================================*/
+static int send_event(struct pcmcia_socket *s, event_t event, int priority)
+{
+ int ret = 0;
+ client_t *client;
+
+ for (client = s->clients; client; client = client->next) {
+ if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
+ continue;
+ if (client->EventMask & event) {
+ ret = EVENT(client, event, priority);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ return ret;
+} /* send_event */
+
+
+/* Normally, the event is passed to individual drivers after
+ * informing userspace. Only for CS_EVENT_CARD_REMOVAL this
+ * is inversed to maintain historic compatibility.
+ */
+
static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
{
- struct pcmcia_bus_socket *s = skt->pcmcia;
+ struct pcmcia_bus_socket *s = skt->pcmcia;
+ int ret = 0;
- ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
- event, priority, s);
+ ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
+ event, priority, s);
- switch (event) {
-
- case CS_EVENT_CARD_REMOVAL:
- s->state &= ~DS_SOCKET_PRESENT;
- if (!(s->state & DS_SOCKET_REMOVAL_PENDING)) {
- s->state |= DS_SOCKET_REMOVAL_PENDING;
- schedule_delayed_work(&s->removal, HZ/10);
- }
- break;
-
- case CS_EVENT_CARD_INSERTION:
- s->state |= DS_SOCKET_PRESENT;
- handle_event(s, event);
- break;
+ switch (event) {
- case CS_EVENT_EJECTION_REQUEST:
- return handle_request(s, event);
- break;
+ case CS_EVENT_CARD_REMOVAL:
+ s->state &= ~DS_SOCKET_PRESENT;
+ send_event(skt, event, priority);
+ handle_event(s, event);
+ break;
- default:
- handle_event(s, event);
- break;
+ case CS_EVENT_CARD_INSERTION:
+ s->state |= DS_SOCKET_PRESENT;
+ handle_event(s, event);
+ send_event(skt, event, priority);
+ break;
+
+ case CS_EVENT_EJECTION_REQUEST:
+ ret = handle_request(s, event);
+ if (ret)
+ break;
+ ret = send_event(skt, event, priority);
+ break;
+
+ default:
+ handle_event(s, event);
+ send_event(skt, event, priority);
+ break;
}
return 0;
init_waitqueue_head(&s->request);
/* initialize data */
- INIT_WORK(&s->removal, handle_removal, s);
s->parent = socket;
/* Set up hotline to Card Services */
pccard_register_pcmcia(socket, NULL);
- flush_scheduled_work();
-
socket->pcmcia->state |= DS_SOCKET_DEAD;
pcmcia_put_bus_socket(socket->pcmcia);
socket->pcmcia = NULL;