
From: Dominik Brodowski <linux@dominikbrodowski.net>

PCMCIA device registration should only happen if we're quite confident
there are resources available to at least map the CIS space -- else we can't
determine manfid/cardid, whether it is a multifunction card, etc. So,
add a flag to struct pcmcia_socket which denotes that -- and also whether
resources were added the "old" adjust_resource_info way. On static sockets,
it is activated upon registration, on non-static sockets, it is set upon an
echo'ing of anything into 
/sys/class/pcmcia_socket/pcmcia_socket%n/device_possible_resources_setup_done

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

 25-akpm/drivers/pcmcia/cs.c           |    3 +-
 25-akpm/drivers/pcmcia/rsrc_mgr.c     |   41 +++++++++++++++++++++++++++++++++-
 25-akpm/drivers/pcmcia/socket_sysfs.c |   30 ++++++++++++++++++++++++
 25-akpm/include/pcmcia/ss.h           |   11 +++++++++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff -puN drivers/pcmcia/cs.c~pcmcia-mark-resource-setup-as-done drivers/pcmcia/cs.c
--- 25/drivers/pcmcia/cs.c~pcmcia-mark-resource-setup-as-done	Sun Mar  6 17:28:02 2005
+++ 25-akpm/drivers/pcmcia/cs.c	Sun Mar  6 17:28:02 2005
@@ -221,6 +221,8 @@ int pcmcia_register_socket(struct pcmcia
 
 	cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
 
+	spin_lock_init(&socket->lock);
+
 	if (socket->resource_ops->init) {
 		ret = socket->resource_ops->init(socket);
 		if (ret)
@@ -261,7 +263,6 @@ int pcmcia_register_socket(struct pcmcia
 	socket->cis_mem.speed = cis_speed;
 
 	INIT_LIST_HEAD(&socket->cis_cache);
-	spin_lock_init(&socket->lock);
 
 	init_completion(&socket->socket_released);
 	init_completion(&socket->thread_done);
diff -puN drivers/pcmcia/rsrc_mgr.c~pcmcia-mark-resource-setup-as-done drivers/pcmcia/rsrc_mgr.c
--- 25/drivers/pcmcia/rsrc_mgr.c~pcmcia-mark-resource-setup-as-done	Sun Mar  6 17:28:02 2005
+++ 25-akpm/drivers/pcmcia/rsrc_mgr.c	Sun Mar  6 17:28:02 2005
@@ -59,6 +59,7 @@ int pcmcia_adjust_resource_info(adjust_t
 {
 	struct pcmcia_socket *s;
 	int ret = CS_UNSUPPORTED_FUNCTION;
+	unsigned long flags;
 
 	down_read(&pcmcia_socket_list_rwsem);
 	list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
@@ -66,8 +67,30 @@ int pcmcia_adjust_resource_info(adjust_t
 		if (adj->Resource == RES_IRQ)
 			ret = adjust_irq(s, adj);
 
-		else if (s->resource_ops->adjust_resource)
+		else if (s->resource_ops->adjust_resource) {
+
+			/* you can't use the old interface if the new
+			 * one was used before */
+			spin_lock_irqsave(&s->lock, flags);
+			if ((s->resource_setup_done) &&
+			    !(s->resource_setup_old)) {
+				spin_unlock_irqrestore(&s->lock, flags);
+				continue;
+			} else if (!(s->resource_setup_old))
+				s->resource_setup_old = 1;
+			spin_unlock_irqrestore(&s->lock, flags);
+
 			ret = s->resource_ops->adjust_resource(s, adj);
+			if (!ret) {
+				/* as there's no way we know this is the
+				 * last call to adjust_resource_info, we
+				 * always need to assume this is the latest
+				 * one... */
+				spin_lock_irqsave(&s->lock, flags);
+				s->resource_setup_done = 1;
+				spin_unlock_irqrestore(&s->lock, flags);
+			}
+		}
 	}
 	up_read(&pcmcia_socket_list_rwsem);
 
@@ -113,12 +136,28 @@ void release_resource_db(struct pcmcia_s
 }
 
 
+static int static_init(struct pcmcia_socket *s)
+{
+	unsigned long flags;
+
+	/* the good thing about SS_CAP_STATIC_MAP sockets is
+	 * that they don't need a resource database */
+
+	spin_lock_irqsave(&s->lock, flags);
+	s->resource_setup_done = 1;
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return 0;
+}
+
+
 struct pccard_resource_ops pccard_static_ops = {
 	.validate_mem = NULL,
 	.adjust_io_region = NULL,
 	.find_io = NULL,
 	.find_mem = NULL,
 	.adjust_resource = NULL,
+	.init = static_init,
 	.exit = NULL,
 };
 EXPORT_SYMBOL(pccard_static_ops);
diff -puN drivers/pcmcia/socket_sysfs.c~pcmcia-mark-resource-setup-as-done drivers/pcmcia/socket_sysfs.c
--- 25/drivers/pcmcia/socket_sysfs.c~pcmcia-mark-resource-setup-as-done	Sun Mar  6 17:28:02 2005
+++ 25-akpm/drivers/pcmcia/socket_sysfs.c	Sun Mar  6 17:28:02 2005
@@ -148,6 +148,35 @@ static ssize_t pccard_store_irq_mask(str
 static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
 
 
+static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+{
+	struct pcmcia_socket *s = to_socket(dev);
+	return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
+}
+
+static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+{
+	unsigned long flags;
+	struct pcmcia_socket *s = to_socket(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	spin_lock_irqsave(&s->lock, flags);
+	if (!s->resource_setup_done) {
+		s->resource_setup_done = 1;
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		/* later on, a call which starts PCMCIA device registration will be added here */
+		return count;
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return count;
+}
+static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+
+
 static struct class_device_attribute *pccard_socket_attributes[] = {
 	&class_device_attr_card_type,
 	&class_device_attr_card_voltage,
@@ -156,6 +185,7 @@ static struct class_device_attribute *pc
 	&class_device_attr_card_insert,
 	&class_device_attr_card_eject,
 	&class_device_attr_card_irq_mask,
+	&class_device_attr_available_resources_setup_done,
 	NULL,
 };
 
diff -puN include/pcmcia/ss.h~pcmcia-mark-resource-setup-as-done include/pcmcia/ss.h
--- 25/include/pcmcia/ss.h~pcmcia-mark-resource-setup-as-done	Sun Mar  6 17:28:02 2005
+++ 25-akpm/include/pcmcia/ss.h	Sun Mar  6 17:28:02 2005
@@ -203,6 +203,17 @@ struct pcmcia_socket {
 	u_char				pci_irq;
 	struct pci_dev *		cb_dev;
 
+
+	/* socket setup is done so resources should be able to be allocated. Only
+	 * if set to 1, calls to find_{io,mem}_region are handled, and insertion
+	 * events are actually managed by the PCMCIA layer.*/
+	u8				resource_setup_done:1;
+
+	/* is set to one if resource setup is done using adjust_resource_info() */
+	u8				resource_setup_old:1;
+
+	u8				reserved:6;
+
 	/* socket operations */
 	struct pccard_operations *	ops;
 	struct pccard_resource_ops *	resource_ops;
_
