From: Dominik Brodowski 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 Signed-off-by: Andrew Morton --- 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 2005-02-10 19:39:15.000000000 -0800 +++ 25-akpm/drivers/pcmcia/cs.c 2005-02-10 19:39:15.000000000 -0800 @@ -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 2005-02-10 19:39:15.000000000 -0800 +++ 25-akpm/drivers/pcmcia/rsrc_mgr.c 2005-02-10 19:39:15.000000000 -0800 @@ -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 2005-02-10 19:39:15.000000000 -0800 +++ 25-akpm/drivers/pcmcia/socket_sysfs.c 2005-02-10 19:39:15.000000000 -0800 @@ -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 2005-02-10 19:39:15.000000000 -0800 +++ 25-akpm/include/pcmcia/ss.h 2005-02-10 19:39:15.000000000 -0800 @@ -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; _