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 --- drivers/pcmcia/cs_internal.h | 1 drivers/pcmcia/ds.c | 86 +++++++++++++++++++++++++++++++++--------- drivers/pcmcia/socket_sysfs.c | 12 +++++ 3 files changed, 80 insertions(+), 19 deletions(-) Index: 2.6.11-rc3+/drivers/pcmcia/cs_internal.h =================================================================== --- 2.6.11-rc3+.orig/drivers/pcmcia/cs_internal.h 2005-02-09 21:47:36.000000000 +0100 +++ 2.6.11-rc3+/drivers/pcmcia/cs_internal.h 2005-02-10 20:25:00.000000000 +0100 @@ -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); Index: 2.6.11-rc3+/drivers/pcmcia/ds.c =================================================================== --- 2.6.11-rc3+.orig/drivers/pcmcia/ds.c 2005-02-10 20:24:58.000000000 +0100 +++ 2.6.11-rc3+/drivers/pcmcia/ds.c 2005-02-10 20:25:00.000000000 +0100 @@ -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); Index: 2.6.11-rc3+/drivers/pcmcia/socket_sysfs.c =================================================================== --- 2.6.11-rc3+.orig/drivers/pcmcia/socket_sysfs.c 2005-02-10 20:14:06.000000000 +0100 +++ 2.6.11-rc3+/drivers/pcmcia/socket_sysfs.c 2005-02-10 20:25:00.000000000 +0100 @@ -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);