ChangeSet 1.2065.3.19, 2005/03/12 08:25:46-08:00, [EMAIL PROTECTED]
[PATCH] pcmcia: add pcmcia devices autonomously
Add pcmcia devices without cardmgr's interaction
If it's a "static" socket or the non-static socket has all its
resources set
up, there's no reason why the PCMCIA core can't detect and set up pcmcia
devices without cardmgr's interaction. Matching is still done in
userspace,
though; and if the PCMCIA core misses something, cardmgr can still add
devices...
Signed-off-by: Dominik Brodowski <[EMAIL PROTECTED]>
Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
cs_internal.h | 1
ds.c | 86 +++++++++++++++++++++++++++++++++++++++++++++------------
socket_sysfs.c | 12 +++++++
3 files changed, 80 insertions(+), 19 deletions(-)
diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
--- a/drivers/pcmcia/cs_internal.h 2005-03-12 21:28:36 -08:00
+++ b/drivers/pcmcia/cs_internal.h 2005-03-12 21:28:36 -08:00
@@ -159,6 +159,7 @@
struct pcmcia_callback{
struct module *owner;
int (*event) (struct pcmcia_socket *s, event_t event, int
priority);
+ int (*resources_done) (struct pcmcia_socket *s);
};
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c 2005-03-12 21:28:36 -08:00
+++ b/drivers/pcmcia/ds.c 2005-03-12 21:28:36 -08:00
@@ -497,6 +497,37 @@
}
+static int pcmcia_card_add(struct pcmcia_socket *s)
+{
+ cisinfo_t cisinfo;
+ cistpl_longlink_mfc_t mfc;
+ unsigned int no_funcs, i;
+ int ret = 0;
+
+ if (!(s->resource_setup_done))
+ return -EAGAIN; /* try again, but later... */
+
+ pcmcia_validate_mem(s);
+ ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
+ if (ret || !cisinfo.Chains) {
+ ds_dbg(0, "invalid CIS or invalid resources\n");
+ return -ENODEV;
+ }
+
+ if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
+ no_funcs = mfc.nfn;
+ else
+ no_funcs = 1;
+
+ /* this doesn't handle multifunction devices on one pcmcia function
+ * yet. */
+ for (i=0; i < no_funcs; i++)
+ pcmcia_device_add(s->pcmcia, i);
+
+ return (ret);
+}
+
+
static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
@@ -630,8 +661,8 @@
case CS_EVENT_CARD_INSERTION:
s->state |= DS_SOCKET_PRESENT;
+ pcmcia_card_add(skt);
handle_event(s, event);
- send_event(skt, event, priority);
break;
case CS_EVENT_EJECTION_REQUEST:
@@ -699,18 +730,35 @@
goto err_put_driver;
}
- /* if there's already a device registered, and it was registered
- * by userspace before, we need to return the "instance". Therefore,
- * we need to set the cardmgr flag */
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- if ((p_dev->func == bind_info->function) &&
- (p_dev->dev.driver == &p_drv->drv) &&
- (p_dev->cardmgr)) {
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- bind_info->instance = p_dev->instance;
- ret = -EBUSY;
- goto err_put_module;
+ list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+ if (p_dev->func == bind_info->function) {
+ if ((p_dev->dev.driver == &p_drv->drv)) {
+ if (p_dev->cardmgr) {
+ /* if there's already a device
+ * registered, and it was registered
+ * by userspace before, we need to
+ * return the "instance". */
+
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ bind_info->instance = p_dev->instance;
+ ret = -EBUSY;
+ goto err_put_module;
+ } else {
+ /* the correct driver managed to bind
+ * itself magically to the correct
+ * device. */
+
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ p_dev->cardmgr = p_drv;
+ ret = 0;
+ goto err_put_module;
+ }
+ } else if (!p_dev->dev.driver) {
+ /* there's already a device available where
+ * no device has been bound to yet. So we don't
+ * need to register a device! */
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock,
flags);
+ goto rescan;
+ }
}
}
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
@@ -720,9 +768,16 @@
ret = -EIO;
goto err_put_module;
}
+
+rescan:
p_dev->cardmgr = p_drv;
+ /*
+ * Prevent this racing with a card insertion.
+ */
+ down(&s->parent->skt_sem);
bus_rescan_devices(&pcmcia_bus_type);
+ up(&s->parent->skt_sem);
/* check whether the driver indeed matched. I don't care if this
* is racy or not, because it can only happen on cardmgr access
@@ -792,10 +847,6 @@
pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference
from bind_device */
- /*
- * Prevent this racing with a card insertion.
- */
- down(&s->skt_sem);
*handle = client;
client->state &= ~CLIENT_UNBOUND;
client->Socket = s;
@@ -832,11 +883,9 @@
EVENT(client, CS_EVENT_CARD_INSERTION,
CS_EVENT_PRI_LOW);
}
- up(&s->skt_sem);
return CS_SUCCESS;
out_no_resource:
- up(&s->skt_sem);
pcmcia_put_dev(p_dev);
return CS_OUT_OF_RESOURCE;
} /* register_client */
@@ -1418,6 +1467,7 @@
/* Set up hotline to Card Services */
s->callback.owner = THIS_MODULE;
s->callback.event = &ds_event;
+ s->callback.resources_done = &pcmcia_card_add;
socket->pcmcia = s;
ret = pccard_register_pcmcia(socket, &s->callback);
diff -Nru a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
--- a/drivers/pcmcia/socket_sysfs.c 2005-03-12 21:28:36 -08:00
+++ b/drivers/pcmcia/socket_sysfs.c 2005-03-12 21:28:36 -08:00
@@ -167,7 +167,17 @@
s->resource_setup_done = 1;
spin_unlock_irqrestore(&s->lock, flags);
- /* later on, a call which starts PCMCIA device registration
will be added here */
+ down(&s->skt_sem);
+ if ((s->callback) &&
+ (s->state & SOCKET_PRESENT) &&
+ !(s->state & SOCKET_CARDBUS)) {
+ if (try_module_get(s->callback->owner)) {
+ s->callback->resources_done(s);
+ module_put(s->callback->owner);
+ }
+ }
+ up(&s->skt_sem);
+
return count;
}
spin_unlock_irqrestore(&s->lock, flags);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html