All of lore.kernel.org
 help / color / mirror / Atom feed
From: Russell King <rmk@arm.linux.org.uk>
To: Paul Fulghum <paulkf@microgate.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Re: PCMCIA 2.5.X sleeping from illegal context
Date: Mon, 12 May 2003 23:48:28 +0100	[thread overview]
Message-ID: <20030512234828.C17227@flint.arm.linux.org.uk> (raw)
In-Reply-To: <1052742964.1467.3.camel@doobie>; from paulkf@microgate.com on Mon, May 12, 2003 at 07:36:05AM -0500

On Mon, May 12, 2003 at 07:36:05AM -0500, Paul Fulghum wrote:
> On Mon, 2003-05-12 at 16:07, Alan Cox wrote:
> > On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> > > The 2.5.X PCMCIA kernel support seems to have a problem
> > > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
> > 
> > Does this still happen with all the patches Russell King posted
> > that everyone else is ignoring ?
> 
> I don't know, I've been ignoring them :-)
> 
> Seriously, are they centralized someplace or
> should I scan back and try to extract them
> from the lk archive? Do you know about when
> they were posted?

Try this one.  Its a slightly updated version from the one I sent earlier.

diff -u /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs.c	Sat Apr 26 23:00:59 2003
+++ linux/drivers/pcmcia/cs.c	Sat Apr 26 23:07:24 2003
@@ -302,11 +302,8 @@
     
 ======================================================================*/
 
-static int setup_socket(socket_info_t *);
-static void shutdown_socket(socket_info_t *);
-static void reset_socket(socket_info_t *);
-static void unreset_socket(socket_info_t *);
-static void parse_events(void *info, u_int events);
+static int pccardd(void *__skt);
+void pcmcia_unregister_socket(struct class_device *dev);
 
 #define to_class_data(dev) dev->class_data
 
@@ -317,7 +314,7 @@
 {
 	struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
 	socket_info_t *s_info;
-	unsigned int i, j;
+	unsigned int i, j, ret;
 
 	if (!cls_d)
 		return -EINVAL;
@@ -330,6 +327,7 @@
 	memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
 
 	cls_d->s_info = s_info;
+	ret = 0;
 
 	/* socket initialization */
 	for (i = 0; i < cls_d->nsock; i++) {
@@ -344,7 +342,7 @@
 		s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
 		INIT_LIST_HEAD(&s->cis_cache);
 		spin_lock_init(&s->lock);
-    
+
 		/* TBD: remove usage of socket_table, use class_for_each_dev instead */
 		for (j = 0; j < sockets; j++)
 			if (socket_table[j] == NULL) break;
@@ -353,6 +351,20 @@
 
 		init_socket(s);
 		s->ss_entry->inquire_socket(s->sock, &s->cap);
+
+		init_completion(&s->thread_done);
+		init_waitqueue_head(&s->thread_wait);
+		init_MUTEX(&s->skt_sem);
+		spin_lock_init(&s->thread_lock);
+		ret = kernel_thread(pccardd, s, CLONE_KERNEL);
+		if (ret < 0) {
+			pcmcia_unregister_socket(class_dev);
+			break;
+		}
+
+		wait_for_completion(&s->thread_done);
+		BUG_ON(!s->thread);
+
 #ifdef CONFIG_PROC_FS
 		if (proc_pccard) {
 			char name[3];
@@ -368,7 +380,7 @@
 		}
 #endif
 	}
-	return 0;
+	return ret;
 } /* pcmcia_register_socket */
 
 
@@ -407,8 +419,12 @@
 			remove_proc_entry(name, proc_pccard);
 		}
 #endif
-		
-		shutdown_socket(s);
+		if (s->thread) {
+			init_completion(&s->thread_done);
+			s->thread = NULL;
+			wake_up(&s->thread_wait);
+			wait_for_completion(&s->thread_done);
+		}
 		release_cis_mem(s);
 		while (s->clients) {
 			client = s->clients;
@@ -450,15 +466,6 @@
 
 static int send_event(socket_info_t *s, event_t event, int priority);
 
-/*
- * Sleep for n_cs centiseconds (1 cs = 1/100th of a second)
- */
-static void cs_sleep(unsigned int n_cs)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout( (n_cs * HZ + 99) / 100);
-}
-
 static void shutdown_socket(socket_info_t *s)
 {
     client_t **c;
@@ -505,132 +512,6 @@
     free_regions(&s->c_region);
 } /* shutdown_socket */
 
-/*
- * Return zero if we think the card isn't actually present
- */
-static int setup_socket(socket_info_t *s)
-{
-	int val, ret;
-	int setup_timeout = 100;
-
-	/* Wait for "not pending" */
-	for (;;) {
-		get_socket_status(s, &val);
-		if (!(val & SS_PENDING))
-			break;
-		if (--setup_timeout) {
-			cs_sleep(10);
-			continue;
-		}
-		printk(KERN_NOTICE "cs: socket %p voltage interrogation"
-			" timed out\n", s);
-		ret = 0;
-		goto out;
-	}
-
-	if (val & SS_DETECT) {
-		DEBUG(1, "cs: setup_socket(%p): applying power\n", s);
-		s->state |= SOCKET_PRESENT;
-		s->socket.flags &= SS_DEBOUNCED;
-		if (val & SS_3VCARD)
-		    s->socket.Vcc = s->socket.Vpp = 33;
-		else if (!(val & SS_XVCARD))
-		    s->socket.Vcc = s->socket.Vpp = 50;
-		else {
-		    printk(KERN_NOTICE "cs: socket %p: unsupported "
-			   "voltage key\n", s);
-		    s->socket.Vcc = 0;
-		}
-		if (val & SS_CARDBUS) {
-		    s->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
-		    printk(KERN_NOTICE "cs: unsupported card type detected!\n");
-#endif
-		}
-		set_socket(s, &s->socket);
-		cs_sleep(vcc_settle);
-		reset_socket(s);
-		ret = 1;
-	} else {
-		DEBUG(0, "cs: setup_socket(%p): no card!\n", s);
-		ret = 0;
-	}
-out:
-	return ret;
-} /* setup_socket */
-
-/*======================================================================
-
-    Reset_socket() and unreset_socket() handle hard resets.  Resets
-    have several causes: card insertion, a call to reset_socket, or
-    recovery from a suspend/resume cycle.  Unreset_socket() sends
-    a CS event that matches the cause of the reset.
-    
-======================================================================*/
-
-static void reset_socket(socket_info_t *s)
-{
-    DEBUG(1, "cs: resetting socket %p\n", s);
-    s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
-    set_socket(s, &s->socket);
-    udelay((long)reset_time);
-    s->socket.flags &= ~SS_RESET;
-    set_socket(s, &s->socket);
-    cs_sleep(unreset_delay);
-    unreset_socket(s);
-} /* reset_socket */
-
-#define EVENT_MASK \
-(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
-
-static void unreset_socket(socket_info_t *s)
-{
-	int setup_timeout = unreset_limit;
-	int val;
-
-	/* Wait for "ready" */
-	for (;;) {
-		get_socket_status(s, &val);
-		if (val & SS_READY)
-			break;
-		DEBUG(2, "cs: socket %d not ready yet\n", s->sock);
-		if (--setup_timeout) {
-			cs_sleep(unreset_check);
-			continue;
-		}
-		printk(KERN_NOTICE "cs: socket %p timed out during"
-			" reset.  Try increasing setup_delay.\n", s);
-		s->state &= ~EVENT_MASK;
-		return;
-	}
-
-	DEBUG(1, "cs: reset done on socket %p\n", s);
-	if (s->state & SOCKET_SUSPEND) {
-	    s->state &= ~EVENT_MASK;
-	    if (verify_cis_cache(s) != 0)
-		parse_events(s, SS_DETECT);
-	    else
-		send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
-	} else if (s->state & SOCKET_SETUP_PENDING) {
-#ifdef CONFIG_CARDBUS
-	    if (s->state & SOCKET_CARDBUS) {
-		cb_alloc(s);
-		s->state |= SOCKET_CARDBUS_CONFIG;
-	    }
-#endif
-	    send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
-	    s->state &= ~SOCKET_SETUP_PENDING;
-	} else {
-	    send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
-	    if (s->reset_handle) { 
-		    s->reset_handle->event_callback_args.info = NULL;
-		    EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
-			  CS_EVENT_PRI_LOW);
-	    }
-	    s->state &= ~EVENT_MASK;
-	}
-} /* unreset_socket */
-
 /*======================================================================
 
     The central event handler.  Send_event() sends an event to all
@@ -661,61 +542,266 @@
     return ret;
 } /* send_event */
 
-static void do_shutdown(socket_info_t *s)
+static void pcmcia_error(socket_info_t *skt, const char *fmt, ...)
 {
-    client_t *client;
-    if (s->state & SOCKET_SHUTDOWN_PENDING)
-	return;
-    s->state |= SOCKET_SHUTDOWN_PENDING;
-    send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
-    for (client = s->clients; client; client = client->next)
-	if (!(client->Attributes & INFO_MASTER_CLIENT))
-	    client->state |= CLIENT_STALE;
-    if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
-	DEBUG(0, "cs: flushing pending setup\n");
-	s->state &= ~EVENT_MASK;
-    }
-    cs_sleep(shutdown_delay);
-    s->state &= ~SOCKET_PRESENT;
-    shutdown_socket(s);
+	static char buf[128];
+	va_list ap;
+	int len;
+
+	va_start(ap, fmt);
+	len = vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+	buf[len] = '\0';
+
+	printk(KERN_ERR "PCMCIA: socket %p: %s", skt, buf);
+}
+
+#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100)
+
+static void socket_remove_drivers(socket_info_t *skt)
+{
+	client_t *client;
+
+	send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+
+	for (client = skt->clients; client; client = client->next)
+		if (!(client->Attributes & INFO_MASTER_CLIENT))
+			client->state |= CLIENT_STALE;
+}
+
+static void socket_shutdown(socket_info_t *skt)
+{
+	socket_remove_drivers(skt);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(shutdown_delay));
+	skt->state &= ~SOCKET_PRESENT;
+	shutdown_socket(skt);
+}
+
+static int socket_reset(socket_info_t *skt)
+{
+	int status, i;
+
+	skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+	set_socket(skt, &skt->socket);
+	udelay((long)reset_time);
+
+	skt->socket.flags &= ~SS_RESET;
+	set_socket(skt, &skt->socket);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(unreset_delay));
+	for (i = 0; i < unreset_limit; i++) {
+		get_socket_status(skt, &status);
+
+		if (!(status & SS_DETECT))
+			return CS_NO_CARD;
+
+		if (status & SS_READY)
+			return CS_SUCCESS;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(cs_to_timeout(unreset_check));
+	}
+
+	pcmcia_error(skt, "time out after reset.\n");
+	return CS_GENERAL_FAILURE;
+}
+
+static int socket_setup(socket_info_t *skt, int initial_delay)
+{
+	int status, i;
+
+	get_socket_status(skt, &status);
+	if (!(status & SS_DETECT))
+		return CS_NO_CARD;
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(initial_delay));
+
+	for (i = 0; i < 100; i++) {
+		get_socket_status(skt, &status);
+		if (!(status & SS_DETECT))
+			return CS_NO_CARD;
+
+		if (!(status & SS_PENDING))
+			break;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(cs_to_timeout(10));
+	}
+
+	if (status & SS_PENDING) {
+		pcmcia_error(skt, "voltage interrogation timed out.\n");
+		return CS_GENERAL_FAILURE;
+	}
+
+	if (status & SS_CARDBUS) {
+		skt->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+		pcmcia_error(skt, "cardbus cards are not supported.\n");
+		return CS_BAD_TYPE;
+#endif
+	}
+
+	/*
+	 * Decode the card voltage requirements, and apply power to the card.
+	 */
+	if (status & SS_3VCARD)
+		skt->socket.Vcc = skt->socket.Vpp = 33;
+	else if (!(status & SS_XVCARD))
+		skt->socket.Vcc = skt->socket.Vpp = 50;
+	else {
+		pcmcia_error(skt, "unsupported voltage key.\n");
+		return CS_BAD_TYPE;
+	}
+	skt->state |= SOCKET_PRESENT;
+	skt->socket.flags = SS_DEBOUNCED;
+	set_socket(skt, &skt->socket);
+
+	/*
+	 * Wait "vcc_settle" for the supply to stabilise.
+	 */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(vcc_settle));
+
+	return socket_reset(skt);
+}
+
+/*
+ * Handle card insertion.  Setup the socket, reset the card,
+ * and then tell the rest of PCMCIA that a card is present.
+ */
+static int socket_insert(socket_info_t *skt)
+{
+	int ret;
+
+	ret = socket_setup(skt, setup_delay);
+	if (ret == CS_SUCCESS) {
+#ifdef CONFIG_CARDBUS
+		if (skt->state & SOCKET_CARDBUS) {
+			cb_alloc(skt);
+			skt->state |= SOCKET_CARDBUS_CONFIG;
+		}
+#endif
+		send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+		skt->socket.flags &= ~SS_DEBOUNCED;
+	} else
+		socket_shutdown(skt);
+
+	return ret;
+}
+
+static int socket_suspend(socket_info_t *skt)
+{
+	if (skt->state & SOCKET_SUSPEND)
+		return CS_IN_USE;
+
+	send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+	suspend_socket(skt);
+	skt->state |= SOCKET_SUSPEND;
+
+	return CS_SUCCESS;
+}
+
+/*
+ * Resume a socket.  If a card is present, verify its CIS against
+ * our cached copy.  If they are different, the card has been
+ * replaced, and we need to tell the drivers.
+ */
+static int socket_resume(socket_info_t *skt)
+{
+	int ret;
+
+	if (!(skt->state & SOCKET_SUSPEND))
+		return CS_IN_USE;
+
+	init_socket(skt);
+
+	ret = socket_setup(skt, resume_delay);
+	if (ret == CS_SUCCESS) {
+		/*
+		 * FIXME: need a better check here for cardbus cards.
+		 */
+		if (verify_cis_cache(skt) != 0) {
+			socket_remove_drivers(skt);
+			destroy_cis_cache(skt);
+			send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+		} else {
+			send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+		}
+		skt->socket.flags &= ~SS_DEBOUNCED;
+	} else
+		socket_shutdown(skt);
+
+	skt->state &= ~SOCKET_SUSPEND;
+
+	return CS_SUCCESS;
+}
+
+static int pccardd(void *__skt)
+{
+	socket_info_t *skt = __skt;
+	DECLARE_WAITQUEUE(wait, current);
+
+	daemonize("pccardd");
+	skt->thread = current;
+	complete(&skt->thread_done);
+
+	add_wait_queue(&skt->thread_wait, &wait);
+	for (;;) {
+		unsigned long flags;
+		unsigned int events;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&skt->thread_lock, flags);
+		events = skt->thread_events;
+		skt->thread_events = 0;
+		spin_unlock_irqrestore(&skt->thread_lock, flags);
+
+		if (events) {
+			down(&skt->skt_sem);
+			if (events & SS_DETECT && !(skt->state & SOCKET_SUSPEND)) {
+				int status;
+
+				get_socket_status(skt, &status);
+				if ((skt->state & SOCKET_PRESENT) &&
+				     !(status & SS_DETECT))
+					socket_shutdown(skt);
+				if (status & SS_DETECT)
+					socket_insert(skt);
+			}
+			if (events & SS_BATDEAD)
+				send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+			if (events & SS_BATWARN)
+				send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+			if (events & SS_READY)
+				send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+			up(&skt->skt_sem);
+			continue;
+		}
+
+		schedule();
+		if (!skt->thread)
+			break;
+	}
+	remove_wait_queue(&skt->thread_wait, &wait);
+
+	socket_shutdown(skt);
+
+	complete_and_exit(&skt->thread_done, 0);
 }
 
 static void parse_events(void *info, u_int events)
 {
-    socket_info_t *s = info;
-    if (events & SS_DETECT) {
-	int status;
-
-	get_socket_status(s, &status);
-	if ((s->state & SOCKET_PRESENT) &&
-	    (!(s->state & SOCKET_SUSPEND) ||
-	     !(status & SS_DETECT)))
-	    do_shutdown(s);
-	if (status & SS_DETECT) {
-	    if (s->state & SOCKET_SETUP_PENDING) {
-		DEBUG(1, "cs: delaying pending setup\n");
-		return;
-	    }
-	    s->state |= SOCKET_SETUP_PENDING;
-	    if (s->state & SOCKET_SUSPEND)
-		cs_sleep(resume_delay);
-	    else
-		cs_sleep(setup_delay);
-	    s->socket.flags |= SS_DEBOUNCED;
-	    if (setup_socket(s) == 0)
-		s->state &= ~SOCKET_SETUP_PENDING;
-	    s->socket.flags &= ~SS_DEBOUNCED;
-	}
-    }
-    if (events & SS_BATDEAD)
-	send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
-    if (events & SS_BATWARN)
-	send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
-    if (events & SS_READY) {
-	if (!(s->state & SOCKET_RESET_PENDING))
-	    send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
-	else DEBUG(1, "cs: ready change during reset\n");
-    }
+	socket_info_t *s = info;
+
+	spin_lock(&s->thread_lock);
+	s->thread_events |= events;
+	spin_unlock(&s->thread_lock);
+
+	wake_up(&s->thread_wait);
 } /* parse_events */
 
 /*======================================================================
@@ -727,27 +813,18 @@
     
 ======================================================================*/
 
-void pcmcia_suspend_socket (socket_info_t *s)
+void pcmcia_suspend_socket (socket_info_t *skt)
 {
-    if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)) {
-	send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
-	suspend_socket(s);
-	s->state |= SOCKET_SUSPEND;
-    }
+	down(&skt->skt_sem);
+	socket_suspend(skt);
+	up(&skt->skt_sem);
 }
 
-void pcmcia_resume_socket (socket_info_t *s)
+void pcmcia_resume_socket (socket_info_t *skt)
 {
-    int	stat;
-
-    /* Do this just to reinitialize the socket */
-    init_socket(s);
-    get_socket_status(s, &stat);
-
-    /* If there was or is a card here, we need to do something
-    about it... but parse_events will sort it all out. */
-    if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
-	parse_events(s, SS_DETECT);
+	down(&skt->skt_sem);
+	socket_resume(skt);
+	up(&skt->skt_sem);
 }
 
 
@@ -1461,15 +1538,8 @@
 
     s = socket_table[ns];
     if (++s->real_clients == 1) {
-	int status;
 	register_callback(s, &parse_events, s);
-	get_socket_status(s, &status);
-	if ((status & SS_DETECT) &&
-	    !(s->state & SOCKET_SETUP_PENDING)) {
-	    s->state |= SOCKET_SETUP_PENDING;
-	    if (setup_socket(s) == 0)
-		    s->state &= ~SOCKET_SETUP_PENDING;
-	}
+	parse_events(s, SS_DETECT);
     }
 
     *handle = client;
@@ -2022,30 +2092,44 @@
 
 int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
 {
-    int i, ret;
-    socket_info_t *s;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
-    if (s->state & SOCKET_RESET_PENDING)
-	return CS_IN_USE;
-    s->state |= SOCKET_RESET_PENDING;
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: resetting socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		if (skt->state & SOCKET_SUSPEND) {
+			ret = CS_IN_USE;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			ret = CS_UNSUPPORTED_FUNCTION;
+			break;
+		}
 
-    ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
-    if (ret != 0) {
-	s->state &= ~SOCKET_RESET_PENDING;
-	handle->event_callback_args.info = (void *)(u_long)ret;
-	EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
-    } else {
-	DEBUG(1, "cs: resetting socket %d\n", i);
-	send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
-	s->reset_handle = handle;
-	reset_socket(s);
-    }
-    return CS_SUCCESS;
+		ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+		if (ret == 0) {
+			send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+			if (socket_reset(skt) == CS_SUCCESS)
+				send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+		}
+
+		handle->event_callback_args.info = (void *)(u_long)ret;
+		EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+
+		ret = CS_SUCCESS;
+	} while (0);
+	up(&skt->skt_sem);
+
+	return ret;
 } /* reset_card */
 
 /*======================================================================
@@ -2057,42 +2141,56 @@
 
 int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
 {
-    int i;
-    socket_info_t *s;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
-    if (s->state & SOCKET_SUSPEND)
-	return CS_IN_USE;
-
-    DEBUG(1, "cs: suspending socket %d\n", i);
-    send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
-    suspend_socket(s);
-    s->state |= SOCKET_SUSPEND;
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: suspending socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			ret = CS_UNSUPPORTED_FUNCTION;
+			break;
+		}
+		ret = socket_suspend(skt);
+	} while (0);
+	up(&skt->skt_sem);
 
-    return CS_SUCCESS;
+	return ret;
 } /* suspend_card */
 
 int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
 {
-    int i;
-    socket_info_t *s;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
-    if (!(s->state & SOCKET_SUSPEND))
-	return CS_IN_USE;
-
-    DEBUG(1, "cs: waking up socket %d\n", i);
-    setup_socket(s);
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: waking up socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			ret = CS_UNSUPPORTED_FUNCTION;
+			break;
+		}
+		ret = socket_resume(skt);
+	} while (0);
+	up(&skt->skt_sem);
 
-    return CS_SUCCESS;
+	return ret;
 } /* resume_card */
 
 /*======================================================================
@@ -2103,57 +2201,58 @@
 
 int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
 {
-    int i, ret;
-    socket_info_t *s;
-    u_long flags;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: user eject request on socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
 
-    DEBUG(1, "cs: user eject request on socket %d\n", i);
+		ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+		if (ret != 0)
+			break;
 
-    ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
-    if (ret != 0)
-	return ret;
+		socket_shutdown(skt);
+		ret = CS_SUCCESS;
+	} while (0);
+	up(&skt->skt_sem);
 
-    spin_lock_irqsave(&s->lock, flags);
-    do_shutdown(s);
-    spin_unlock_irqrestore(&s->lock, flags);
-    
-    return CS_SUCCESS;
-    
+	return ret;
 } /* eject_card */
 
 int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
 {
-    int i, status;
-    socket_info_t *s;
-    u_long flags;
-    
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (s->state & SOCKET_PRESENT)
-	return CS_IN_USE;
-
-    DEBUG(1, "cs: user insert request on socket %d\n", i);
+	socket_info_t *skt;
+	int ret;
 
-    spin_lock_irqsave(&s->lock, flags);
-    if (!(s->state & SOCKET_SETUP_PENDING)) {
-	s->state |= SOCKET_SETUP_PENDING;
-	spin_unlock_irqrestore(&s->lock, flags);
-	get_socket_status(s, &status);
-	if ((status & SS_DETECT) == 0 || (setup_socket(s) == 0)) {
-	    s->state &= ~SOCKET_SETUP_PENDING;
-	    return CS_NO_CARD;
-	}
-    } else
-	spin_unlock_irqrestore(&s->lock, flags);
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: user insert request on socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (skt->state & SOCKET_PRESENT) {
+			ret = CS_IN_USE;
+			break;
+		}
+		if (socket_insert(skt) == CS_NO_CARD) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		ret = CS_SUCCESS;
+	} while (0);
+	up(&skt->skt_sem);
 
-    return CS_SUCCESS;
+	return ret;
 } /* insert_card */
 
 /*======================================================================
diff -u /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs_internal.h	Sat Apr 26 23:01:03 2003
+++ linux/drivers/pcmcia/cs_internal.h	Sat Apr 26 21:34:59 2003
@@ -133,7 +133,6 @@
     u_short			lock_count;
     client_handle_t		clients;
     u_int			real_clients;
-    client_handle_t		reset_handle;
     pccard_mem_map		cis_mem;
     u_char			*cis_virt;
     config_t			*config;
@@ -155,6 +154,14 @@
 #ifdef CONFIG_PROC_FS
     struct proc_dir_entry	*proc;
 #endif
+
+    struct semaphore		skt_sem;	/* protects socket h/w state */
+
+    struct task_struct		*thread;
+    struct completion		thread_done;
+    wait_queue_head_t		thread_wait;
+    spinlock_t			thread_lock;	/* protects thread_events */
+    unsigned int		thread_events;
 } socket_info_t;
 
 /* Flags in config state */

-- 
Russell King (rmk@arm.linux.org.uk)                The developer of ARM Linux
             http://www.arm.linux.org.uk/personal/aboutme.html


  reply	other threads:[~2003-05-12 22:38 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-05-12 21:35 PCMCIA 2.5.X sleeping from illegal context Paul Fulghum
2003-05-12 21:07 ` Alan Cox
2003-05-12 12:36   ` Paul Fulghum
2003-05-12 22:48     ` Russell King [this message]
2003-05-13 15:23       ` Paul Fulghum
2003-05-13 16:00         ` David Hinds
2003-05-12 22:31   ` Russell King
2003-05-12 23:16     ` Felipe Alfaro Solana
2003-05-12 23:36       ` Richard B. Johnson
2003-05-12 23:52         ` Paul Fulghum
2003-05-13 13:37         ` Alan Cox
2003-05-13 23:33           ` Andrew Morton
2003-05-14 13:25             ` Henning P. Schmiedehausen
2003-05-13  2:07       ` Thomas Molina
2003-05-13  0:36         ` Felipe Alfaro Solana
2003-05-12 23:11   ` Felipe Alfaro Solana
2003-05-12 22:06 ` David Hinds
2003-05-12 12:37   ` Paul Fulghum
2003-05-12 22:44 ` Andrew Morton
2003-05-12 23:10   ` David Hinds

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030512234828.C17227@flint.arm.linux.org.uk \
    --to=rmk@arm.linux.org.uk \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    --cc=paulkf@microgate.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.