Commit 0efb3841 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] pcmcia: mark resource setup as done

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: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a0710322
...@@ -221,6 +221,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) ...@@ -221,6 +221,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
spin_lock_init(&socket->lock);
if (socket->resource_ops->init) { if (socket->resource_ops->init) {
ret = socket->resource_ops->init(socket); ret = socket->resource_ops->init(socket);
if (ret) if (ret)
...@@ -261,7 +263,6 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) ...@@ -261,7 +263,6 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
socket->cis_mem.speed = cis_speed; socket->cis_mem.speed = cis_speed;
INIT_LIST_HEAD(&socket->cis_cache); INIT_LIST_HEAD(&socket->cis_cache);
spin_lock_init(&socket->lock);
init_completion(&socket->socket_released); init_completion(&socket->socket_released);
init_completion(&socket->thread_done); init_completion(&socket->thread_done);
......
...@@ -59,6 +59,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj) ...@@ -59,6 +59,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
{ {
struct pcmcia_socket *s; struct pcmcia_socket *s;
int ret = CS_UNSUPPORTED_FUNCTION; int ret = CS_UNSUPPORTED_FUNCTION;
unsigned long flags;
down_read(&pcmcia_socket_list_rwsem); down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(s, &pcmcia_socket_list, socket_list) { list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
...@@ -66,8 +67,30 @@ int pcmcia_adjust_resource_info(adjust_t *adj) ...@@ -66,8 +67,30 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
if (adj->Resource == RES_IRQ) if (adj->Resource == RES_IRQ)
ret = adjust_irq(s, adj); 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); 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); up_read(&pcmcia_socket_list_rwsem);
...@@ -113,12 +136,28 @@ void release_resource_db(struct pcmcia_socket *s) ...@@ -113,12 +136,28 @@ void release_resource_db(struct pcmcia_socket *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 = { struct pccard_resource_ops pccard_static_ops = {
.validate_mem = NULL, .validate_mem = NULL,
.adjust_io_region = NULL, .adjust_io_region = NULL,
.find_io = NULL, .find_io = NULL,
.find_mem = NULL, .find_mem = NULL,
.adjust_resource = NULL, .adjust_resource = NULL,
.init = static_init,
.exit = NULL, .exit = NULL,
}; };
EXPORT_SYMBOL(pccard_static_ops); EXPORT_SYMBOL(pccard_static_ops);
...@@ -148,6 +148,35 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, ...@@ -148,6 +148,35 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf,
static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); 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[] = { static struct class_device_attribute *pccard_socket_attributes[] = {
&class_device_attr_card_type, &class_device_attr_card_type,
&class_device_attr_card_voltage, &class_device_attr_card_voltage,
...@@ -156,6 +185,7 @@ static struct class_device_attribute *pccard_socket_attributes[] = { ...@@ -156,6 +185,7 @@ static struct class_device_attribute *pccard_socket_attributes[] = {
&class_device_attr_card_insert, &class_device_attr_card_insert,
&class_device_attr_card_eject, &class_device_attr_card_eject,
&class_device_attr_card_irq_mask, &class_device_attr_card_irq_mask,
&class_device_attr_available_resources_setup_done,
NULL, NULL,
}; };
......
...@@ -203,6 +203,17 @@ struct pcmcia_socket { ...@@ -203,6 +203,17 @@ struct pcmcia_socket {
u_char pci_irq; u_char pci_irq;
struct pci_dev * cb_dev; 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 */ /* socket operations */
struct pccard_operations * ops; struct pccard_operations * ops;
struct pccard_resource_ops * resource_ops; struct pccard_resource_ops * resource_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment