Call the PCMCIA 16-bit device drivers from ds.c instead of cs.c. Also, remove the delayed handling of CS_REMOVAL events, but keep the ordering the same as it used to be due to the delay. drivers/pcmcia/cs.c | 41 ++++++------------------- drivers/pcmcia/ds.c | 84 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 60 insertions(+), 65 deletions(-) diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- linux-original/drivers/pcmcia/cs.c 2004-11-13 13:34:50.201592992 +0100 +++ linux/drivers/pcmcia/cs.c 2004-11-13 13:34:40.227109344 +0100 @@ -401,10 +401,18 @@ ======================================================================*/ -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)) @@ -417,35 +425,6 @@ 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; @@ -1404,7 +1383,7 @@ 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: diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c --- linux-original/drivers/pcmcia/ds.c 2004-11-13 13:34:50.203592688 +0100 +++ linux/drivers/pcmcia/ds.c 2004-11-13 13:34:40.230108888 +0100 @@ -117,7 +117,6 @@ 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; }; @@ -473,48 +472,68 @@ 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; @@ -1101,7 +1120,6 @@ init_waitqueue_head(&s->request); /* initialize data */ - INIT_WORK(&s->removal, handle_removal, s); s->parent = socket; /* Set up hotline to Card Services */ @@ -1130,8 +1148,6 @@ pccard_register_pcmcia(socket, NULL); - flush_scheduled_work(); - socket->pcmcia->state |= DS_SOCKET_DEAD; pcmcia_put_bus_socket(socket->pcmcia); socket->pcmcia = NULL;