
From: Dominik Brodowski <linux@dominikbrodowski.de>

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.

Signed-off-by: Dominik Brodowski <linux@brodo.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/pcmcia/cs.c |   41 +++++----------------
 25-akpm/drivers/pcmcia/ds.c |   84 ++++++++++++++++++++++++++------------------
 2 files changed, 60 insertions(+), 65 deletions(-)

diff -puN drivers/pcmcia/cs.c~pcmcia-call-device-drivers-from-ds-not-from-cs drivers/pcmcia/cs.c
--- 25/drivers/pcmcia/cs.c~pcmcia-call-device-drivers-from-ds-not-from-cs	2004-12-03 18:44:23.110269904 -0800
+++ 25-akpm/drivers/pcmcia/cs.c	2004-12-03 18:44:23.118268688 -0800
@@ -401,10 +401,18 @@ static void shutdown_socket(struct pcmci
 ======================================================================*/
 
 
-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 @@ static int pcmcia_send_event(struct pcmc
 	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 @@ int pccard_register_pcmcia(struct pcmcia
 		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 -puN drivers/pcmcia/ds.c~pcmcia-call-device-drivers-from-ds-not-from-cs drivers/pcmcia/ds.c
--- 25/drivers/pcmcia/ds.c~pcmcia-call-device-drivers-from-ds-not-from-cs	2004-12-03 18:44:23.112269600 -0800
+++ 25-akpm/drivers/pcmcia/ds.c	2004-12-03 18:44:23.120268384 -0800
@@ -117,7 +117,6 @@ struct pcmcia_bus_socket {
 	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;
 };
@@ -471,48 +470,68 @@ static int handle_request(struct pcmcia_
     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;
@@ -1099,7 +1118,6 @@ static int __devinit pcmcia_bus_add_sock
 	init_waitqueue_head(&s->request);
 
 	/* initialize data */
-	INIT_WORK(&s->removal, handle_removal, s);
 	s->parent = socket;
 
 	/* Set up hotline to Card Services */
@@ -1128,8 +1146,6 @@ static void pcmcia_bus_remove_socket(str
 
 	pccard_register_pcmcia(socket, NULL);
 
-	flush_scheduled_work();
-
 	socket->pcmcia->state |= DS_SOCKET_DEAD;
 	pcmcia_put_bus_socket(socket->pcmcia);
 	socket->pcmcia = NULL;
_
