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 --- drivers/pcmcia/cs.c | 3 ++- drivers/pcmcia/rsrc_mgr.c | 41 ++++++++++++++++++++++++++++++++++++++++- drivers/pcmcia/socket_sysfs.c | 30 ++++++++++++++++++++++++++++++ include/pcmcia/ss.h | 11 +++++++++++ 4 files changed, 83 insertions(+), 2 deletions(-) Index: 2.6.11-rc3+/drivers/pcmcia/cs.c =================================================================== --- 2.6.11-rc3+.orig/drivers/pcmcia/cs.c 2005-02-09 21:47:36.000000000 +0100 +++ 2.6.11-rc3+/drivers/pcmcia/cs.c 2005-02-10 20:14:06.000000000 +0100 @@ -221,6 +221,8 @@ 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 @@ 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); Index: 2.6.11-rc3+/drivers/pcmcia/rsrc_mgr.c =================================================================== --- 2.6.11-rc3+.orig/drivers/pcmcia/rsrc_mgr.c 2005-02-09 21:47:36.000000000 +0100 +++ 2.6.11-rc3+/drivers/pcmcia/rsrc_mgr.c 2005-02-10 20:14:06.000000000 +0100 @@ -59,6 +59,7 @@ { 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 @@ 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 @@ } +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); Index: 2.6.11-rc3+/drivers/pcmcia/socket_sysfs.c =================================================================== --- 2.6.11-rc3+.orig/drivers/pcmcia/socket_sysfs.c 2005-02-09 21:47:36.000000000 +0100 +++ 2.6.11-rc3+/drivers/pcmcia/socket_sysfs.c 2005-02-10 20:14:06.000000000 +0100 @@ -148,6 +148,35 @@ 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 @@ &class_device_attr_card_insert, &class_device_attr_card_eject, &class_device_attr_card_irq_mask, + &class_device_attr_available_resources_setup_done, NULL, }; Index: 2.6.11-rc3+/include/pcmcia/ss.h =================================================================== --- 2.6.11-rc3+.orig/include/pcmcia/ss.h 2005-02-09 21:47:44.000000000 +0100 +++ 2.6.11-rc3+/include/pcmcia/ss.h 2005-02-10 20:14:06.000000000 +0100 @@ -203,6 +203,17 @@ 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;