[PATCH 8/13] pcmcia: unified device removal code path
Dominik Brodowski
linux at dominikbrodowski.net
Wed Sep 7 17:37:34 EDT 2005
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 <linux at dominikbrodowski.net>
---
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);
More information about the linux-pcmcia
mailing list