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)
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 *socket)
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);
......
......@@ -59,6 +59,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
{
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 *adj)
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_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 = {
.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);
......@@ -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 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 *pccard_socket_attributes[] = {
&class_device_attr_card_insert,
&class_device_attr_card_eject,
&class_device_attr_card_irq_mask,
&class_device_attr_available_resources_setup_done,
NULL,
};
......
......@@ -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;
......
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