Unify the "detach" and REMOVAL_EVENT handlers to one "remove" function, and convert pcnet_cs.c as an example. Old functionality is preserved, for the moment. Signed-off-by: Dominik Brodowski --- Documentation/pcmcia/driver-changes.txt | 3 drivers/net/pcmcia/pcnet_cs.c | 48 ++++++--------- drivers/pcmcia/ds.c | 97 ++++++++++++++++++++------------ include/pcmcia/ds.h | 2 4 files changed, 87 insertions(+), 63 deletions(-) Index: 2.6.13-git4/drivers/net/pcmcia/pcnet_cs.c =================================================================== --- 2.6.13-git4.orig/drivers/net/pcmcia/pcnet_cs.c +++ 2.6.13-git4/drivers/net/pcmcia/pcnet_cs.c @@ -121,7 +121,7 @@ static int setup_dma_config(dev_link_t * int stop_pg); static dev_link_t *pcnet_attach(void); -static void pcnet_detach(dev_link_t *); +static void pcnet_detach(struct pcmcia_device *p_dev); static dev_info_t dev_info = "pcnet_cs"; static dev_link_t *dev_list; @@ -280,7 +280,7 @@ static dev_link_t *pcnet_attach(void) ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); - pcnet_detach(link); + pcnet_detach(link->handle); return NULL; } @@ -296,31 +296,29 @@ static dev_link_t *pcnet_attach(void) ======================================================================*/ -static void pcnet_detach(dev_link_t *link) +static void pcnet_detach(struct pcmcia_device *p_dev) { - struct net_device *dev = link->priv; - dev_link_t **linkp; - - DEBUG(0, "pcnet_detach(0x%p)\n", link); + dev_link_t *link = dev_to_instance(p_dev); + struct net_device *dev = link->priv; + dev_link_t **linkp; - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; + DEBUG(0, "pcnet_detach(0x%p)\n", link); - if (link->dev) - unregister_netdev(dev); + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; - if (link->state & DEV_CONFIG) - pcnet_release(link); + if (link->dev) + unregister_netdev(dev); - if (link->handle) - pcmcia_deregister_client(link->handle); + if (link->state & DEV_CONFIG) + pcnet_release(link); - /* Unlink device structure, free bits */ - *linkp = link->next; - free_netdev(dev); + /* Unlink device structure, free bits */ + *linkp = link->next; + free_netdev(dev); } /* pcnet_detach */ /*====================================================================== @@ -817,16 +815,10 @@ static int pcnet_event(event_t event, in event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; DEBUG(2, "pcnet_event(0x%06x)\n", event); switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) - netif_device_detach(dev); - break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; pcnet_config(link); @@ -1850,7 +1842,7 @@ static struct pcmcia_driver pcnet_driver }, .attach = pcnet_attach, .event = pcnet_event, - .detach = pcnet_detach, + .remove = pcnet_detach, .owner = THIS_MODULE, .id_table = pcnet_ids, .suspend = pcnet_suspend, Index: 2.6.13-git4/drivers/pcmcia/ds.c =================================================================== --- 2.6.13-git4.orig/drivers/pcmcia/ds.c +++ 2.6.13-git4/drivers/pcmcia/ds.c @@ -57,8 +57,6 @@ module_param_named(pc_debug, ds_pc_debug spinlock_t pcmcia_dev_list_lock; -static int unbind_request(struct pcmcia_socket *s); - /*====================================================================*/ /* code which was in cs.c before */ @@ -205,7 +203,7 @@ static void pcmcia_check_driver(struct p unsigned int i; u32 hash; - if (!p_drv->attach || !p_drv->event || !p_drv->detach) + if (!p_drv->attach || !p_drv->event || !p_drv->remove) printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " "function\n", p_drv->drv.name); @@ -399,13 +397,42 @@ static int pcmcia_device_remove(struct d { struct pcmcia_device *p_dev; struct pcmcia_driver *p_drv; + int i; /* detach the "instance" */ p_dev = to_pcmcia_dev(dev); p_drv = to_pcmcia_drv(dev->driver); + /* the likely, new path */ + if (p_drv && p_drv->remove) { + p_drv->remove(p_dev); + + /* check for proper unloading */ + if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) + printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", + p_drv->drv.name); + + for (i = 0; i < MAX_WIN; i++) + if (p_dev->state & CLIENT_WIN_REQ(i)) + printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", + p_drv->drv.name); + + /* undo pcmcia_register_client */ + p_dev->state = CLIENT_UNBOUND; + pcmcia_put_dev(p_dev); + + /* references from pcmcia_probe_device */ + pcmcia_put_dev(p_dev); + module_put(p_drv->owner); + + return 0; + } + + /* old path */ if (p_drv) { if ((p_drv->detach) && (p_dev->instance)) { + printk(KERN_INFO "pcmcia: using deprecated detach mechanism. Fix the driver!\n"); + p_drv->detach(p_dev->instance); /* from pcmcia_probe_device */ put_device(&p_dev->dev); @@ -417,6 +444,36 @@ static int pcmcia_device_remove(struct d } +/* + * Removes a PCMCIA card from the device tree and socket list. + */ +static void pcmcia_card_remove(struct pcmcia_socket *s) +{ + struct pcmcia_device *p_dev; + unsigned long flags; + + ds_dbg(2, "unbind_request(%d)\n", s->sock); + + s->device_count = 0; + + for (;;) { + /* unregister all pcmcia_devices registered with this socket*/ + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + if (list_empty(&s->devices_list)) { + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + return; + } + p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); + list_del(&p_dev->socket_device_list); + p_dev->state |= CLIENT_STALE; + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + + device_unregister(&p_dev->dev); + } + + return; +} /* unbind_request */ + /* * pcmcia_device_query -- determine information about a pcmcia device @@ -1056,8 +1113,8 @@ static int ds_event(struct pcmcia_socket case CS_EVENT_CARD_REMOVAL: s->pcmcia_state.present = 0; - send_event(skt, event, priority); - unbind_request(skt); + send_event(skt, event, priority); + pcmcia_card_remove(skt); handle_event(skt, event); break; @@ -1174,36 +1231,6 @@ int pcmcia_register_client(struct pcmcia EXPORT_SYMBOL(pcmcia_register_client); -/* unbind _all_ devices attached to a given pcmcia_bus_socket. The - * drivers have been called with EVENT_CARD_REMOVAL before. - */ -static int unbind_request(struct pcmcia_socket *s) -{ - struct pcmcia_device *p_dev; - unsigned long flags; - - ds_dbg(2, "unbind_request(%d)\n", s->sock); - - s->device_count = 0; - - for (;;) { - /* unregister all pcmcia_devices registered with this socket*/ - spin_lock_irqsave(&pcmcia_dev_list_lock, flags); - if (list_empty(&s->devices_list)) { - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - return 0; - } - p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); - list_del(&p_dev->socket_device_list); - p_dev->state |= CLIENT_STALE; - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - - device_unregister(&p_dev->dev); - } - - return 0; -} /* unbind_request */ - int pcmcia_deregister_client(struct pcmcia_device *p_dev) { struct pcmcia_socket *s; Index: 2.6.13-git4/include/pcmcia/ds.h =================================================================== --- 2.6.13-git4.orig/include/pcmcia/ds.h +++ 2.6.13-git4/include/pcmcia/ds.h @@ -138,6 +138,8 @@ struct pcmcia_driver { event_callback_args_t *); void (*detach)(dev_link_t *); + void (*remove) (struct pcmcia_device *dev); + int (*suspend) (struct pcmcia_device *dev); int (*resume) (struct pcmcia_device *dev); Index: 2.6.13-git4/Documentation/pcmcia/driver-changes.txt =================================================================== --- 2.6.13-git4.orig/Documentation/pcmcia/driver-changes.txt +++ 2.6.13-git4/Documentation/pcmcia/driver-changes.txt @@ -1,5 +1,8 @@ This file details changes in 2.6 which affect PCMCIA card driver authors: +* Unify detach and REMOVAL event code (as of 2.6.14) + void (*remove) (struct pcmcia_device *dev); + * Move suspend, resume and reset out of event handler (as of 2.6.14) int (*suspend) (struct pcmcia_device *dev); int (*resume) (struct pcmcia_device *dev);