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 | 28 ++++++++++++++++++++++++++++ drivers/pcmcia/socket_sysfs.c | 30 ++++++++++++++++++++++++++++++ include/pcmcia/ss.h | 13 +++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- linux-original/drivers/pcmcia/cs.c 2004-11-09 23:31:23.553568376 +0100 +++ linux/drivers/pcmcia/cs.c 2004-11-09 23:32:26.869942824 +0100 @@ -217,6 +217,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) @@ -257,7 +259,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); diff -ruN linux-original/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c --- linux-original/drivers/pcmcia/rsrc_mgr.c 2004-11-09 23:30:43.732622080 +0100 +++ linux/drivers/pcmcia/rsrc_mgr.c 2004-11-09 23:30:24.044615112 +0100 @@ -240,6 +240,18 @@ } up_read(&pcmcia_socket_list_rwsem); + /* 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... */ + if (ret != CS_UNSUPPORTED_FUNCTION) { + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + s->resource_setup_old = 1; + s->resource_setup_done = 1; + spin_unlock_irqrestore(&s->lock, flags); + } + return (ret); } EXPORT_SYMBOL(pcmcia_adjust_resource_info); @@ -282,12 +294,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); diff -ruN linux-original/drivers/pcmcia/socket_sysfs.c linux/drivers/pcmcia/socket_sysfs.c --- linux-original/drivers/pcmcia/socket_sysfs.c 2004-11-09 23:30:43.733621928 +0100 +++ linux/drivers/pcmcia/socket_sysfs.c 2004-11-09 23:30:24.045614960 +0100 @@ -122,6 +122,35 @@ static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); +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 ? "no" : "yes"); +} + +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 */ + } + spin_unlock_irqrestore(&s->lock, flags); + + return count; +} +static CLASS_DEVICE_ATTR(device_possible_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, @@ -129,6 +158,7 @@ &class_device_attr_card_vcc, &class_device_attr_card_insert, &class_device_attr_card_eject, + &class_device_attr_device_possible_resources_setup_done, NULL, }; diff -ruN linux-original/include/pcmcia/ss.h linux/include/pcmcia/ss.h --- linux-original/include/pcmcia/ss.h 2004-11-09 23:31:23.555568072 +0100 +++ linux/include/pcmcia/ss.h 2004-11-09 23:30:24.045614960 +0100 @@ -164,6 +164,7 @@ /* Maximum number of memory windows per socket */ #define MAX_WIN 4 + struct config_t; struct region_t; struct pcmcia_callback; @@ -205,6 +206,18 @@ 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:7; + + /* socket operations */ struct pccard_operations * ops; struct pccard_resource_ops * resource_ops;