
From: Dominik Brodowski <linux@dominikbrodowski.de>

Remove struct socket_bind_t by moving "dev_link_t *instance" to struct
pcmcia_device, and transforming all users of socket_bind_t to use struct
pcmcia_device instead.  Also, CodingStyle updates for get_device_info and
unbind_request.

Signed-off-by: Dominik Brodowski <linux@brodo.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/pcmcia/ds.c |  302 +++++++++++++++++++++++---------------------
 25-akpm/include/pcmcia/ds.h |    4 
 2 files changed, 165 insertions(+), 141 deletions(-)

diff -puN drivers/pcmcia/ds.c~pcmcia-remove-socket_bind_t-use-pcmcia_devices-instead drivers/pcmcia/ds.c
--- 25/drivers/pcmcia/ds.c~pcmcia-remove-socket_bind_t-use-pcmcia_devices-instead	2004-12-03 18:44:28.112509448 -0800
+++ 25-akpm/drivers/pcmcia/ds.c	2004-12-03 18:44:28.121508080 -0800
@@ -71,13 +71,6 @@ module_param_named(pc_debug, ds_pc_debug
 
 /*====================================================================*/
 
-typedef struct socket_bind_t {
-    struct pcmcia_driver	*driver;
-    u_char		function;
-    dev_link_t		*instance;
-    struct socket_bind_t *next;
-} socket_bind_t;
-
 /* Device user information */
 #define MAX_EVENTS	32
 #define USER_MAGIC	0x7ea4
@@ -99,7 +92,6 @@ struct pcmcia_bus_socket {
 	user_info_t		*user;
 	int			req_pending, req_result;
 	wait_queue_head_t	queue, request;
-	socket_bind_t		*bind;
 	struct pcmcia_socket	*parent;
 
 	/* the PCMCIA devices connected to this socket (normally one, more
@@ -335,6 +327,20 @@ static int proc_read_drivers(char *buf, 
 
 /* pcmcia_device handling */
 
+static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
+{
+	struct device *tmp_dev;
+	tmp_dev = get_device(&p_dev->dev);
+	if (!tmp_dev)
+		return NULL;
+	return to_pcmcia_dev(tmp_dev);
+}
+
+static void pcmcia_put_dev(struct pcmcia_device *p_dev)
+{
+	put_device(&p_dev->dev);
+}
+
 static void pcmcia_release_dev(struct device *dev)
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
@@ -504,37 +510,29 @@ static int bind_mtd(struct pcmcia_bus_so
 
 static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
-	struct pcmcia_driver *driver;
-	struct pcmcia_device *p_dev;
-	socket_bind_t *b;
+	struct pcmcia_driver *p_drv;
+	struct pcmcia_device *p_dev, *tmp_dev;
 	client_t *client;
 	unsigned long flags;
+	int ret = 0;
 
 	if (!s)
 		return -EINVAL;
 
 	ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock,
 	       (char *)bind_info->dev_info);
-	driver = get_pcmcia_driver(&bind_info->dev_info);
-	if (!driver)
-		return -EINVAL;
 
-	for (b = s->bind; b; b = b->next)
-		if ((driver == b->driver) &&
-		    (bind_info->function == b->function))
-			break;
-	if (b != NULL) {
-		bind_info->instance = b->instance;
-		return -EBUSY;
-	}
+	p_drv = get_pcmcia_driver(&bind_info->dev_info);
+	if (!p_drv)
+		return -EINVAL;
 
-	if (!try_module_get(driver->owner))
+	if (!try_module_get(p_drv->owner))
 		return -EINVAL;
 
 	client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL);
 	if (!client) {
-		module_put(driver->owner);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_put;
 	}
 	memset(client, 0, sizeof(client_t));
 
@@ -543,21 +541,7 @@ static int bind_request(struct pcmcia_bu
 	client->Function = bind_info->function;
 	client->state = CLIENT_UNBOUND;
 	client->next = s->parent->clients;
-	strlcpy(client->dev_info, driver->drv.name, DEV_NAME_LEN);
-	s->parent->clients = client;
-
-	/* Add binding to list for this socket */
-	b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
-	if (!b)
-	{
-		module_put(driver->owner);
-		return -ENOMEM;
-	}
-	b->driver = driver;
-	b->function = bind_info->function;
-	b->instance = NULL;
-	b->next = s->bind;
-	s->bind = b;
+	strlcpy(client->dev_info, p_drv->drv.name, DEV_NAME_LEN);
 
 	/* Currently, the userspace pcmcia cardmgr detects pcmcia devices.
 	 * Here this information is translated into a kernel
@@ -566,8 +550,8 @@ static int bind_request(struct pcmcia_bu
 
 	p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
 	if (!p_dev) {
-		/* FIXME: client isn't freed here */
-		goto no_p_dev;
+		ret = -ENOMEM;
+		goto err_free_client;
 	}
 	memset(p_dev, 0, sizeof(struct pcmcia_device));
 
@@ -578,31 +562,55 @@ static int bind_request(struct pcmcia_bu
 	p_dev->dev.parent = s->parent->dev.dev;
 	p_dev->dev.release = pcmcia_release_dev;
 	sprintf (p_dev->dev.bus_id, "pcmcia%d.%d", p_dev->socket->sock, p_dev->func);
-	p_dev->dev.driver = &driver->drv;
-	if (device_register(&p_dev->dev)) {
-		/* FIXME: client isn't freed here */
+	p_dev->dev.driver = &p_drv->drv;
+
+	ret = device_register(&p_dev->dev);
+	if (ret) {
 		kfree(p_dev);
-		goto no_p_dev;
+		goto err_free_client;
 	}
+
+	/*
+	 * Add to the list in pcmcia_bus_socket. Also, assert that no
+	 * such device exists at the moment.
+	 */
+
 	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+	list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) {
+		if (tmp_dev->func == bind_info->function) {
+			spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+			bind_info->instance = tmp_dev->instance;
+			ret = -EBUSY;
+			goto err_unregister;
+		}
+	}
 	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
- no_p_dev:
+	/* finally here the parent client is registered */
+	s->parent->clients = client;
 
-	driver->use_count++;
-	if (driver->attach) {
-		b->instance = driver->attach();
-		if (b->instance == NULL) {
+	p_drv->use_count++;
+	if (p_drv->attach) {
+		p_dev->instance = p_drv->attach();
+		if (!p_dev->instance) {
 			printk(KERN_NOTICE "ds: unable to create instance "
 			       "of '%s'!\n", (char *)bind_info->dev_info);
-			module_put(driver->owner);
 			/* FIXME: client isn't freed here */
-			return -ENODEV;
+			ret = -ENODEV;
+			goto err_unregister;
 		}
 	}
     
 	return 0;
+
+ err_unregister:
+	device_unregister(&p_dev->dev);
+ err_free_client:
+	kfree(client);
+ err_put:
+	module_put(p_drv->owner);
+	return (ret);
 } /* bind_request */
 
 /*====================================================================*/
@@ -611,113 +619,125 @@ extern struct pci_bus *pcmcia_lookup_bus
 
 static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
 {
-    socket_bind_t *b;
-    dev_node_t *node;
+	dev_node_t *node;
+	struct pcmcia_device *p_dev;
+	unsigned long flags;
+	int ret = 0;
 
 #ifdef CONFIG_CARDBUS
-    /*
-     * Some unbelievably ugly code to associate the PCI cardbus
-     * device and its driver with the PCMCIA "bind" information.
-     */
-    {
-	struct pci_bus *bus;
+	/*
+	 * Some unbelievably ugly code to associate the PCI cardbus
+	 * device and its driver with the PCMCIA "bind" information.
+	 */
+	{
+		struct pci_bus *bus;
 
-	bus = pcmcia_lookup_bus(s->parent);
-	if (bus) {
-	    	struct list_head *list;
-		struct pci_dev *dev = NULL;
-		
-		list = bus->devices.next;
-		while (list != &bus->devices) {
-			struct pci_dev *pdev = pci_dev_b(list);
-			list = list->next;
+		bus = pcmcia_lookup_bus(s->parent);
+		if (bus) {
+			struct list_head *list;
+			struct pci_dev *dev = NULL;
+
+			list = bus->devices.next;
+			while (list != &bus->devices) {
+				struct pci_dev *pdev = pci_dev_b(list);
+				list = list->next;
+
+				if (first) {
+					dev = pdev;
+					break;
+				}
 
-			if (first) {
-				dev = pdev;
-				break;
+				/* Try to handle "next" here some way? */
+			}
+			if (dev && dev->driver) {
+				strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
+				bind_info->major = 0;
+				bind_info->minor = 0;
+				bind_info->next = NULL;
+				return 0;
 			}
-
-			/* Try to handle "next" here some way? */
-		}
-		if (dev && dev->driver) {
-			strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
-			bind_info->major = 0;
-			bind_info->minor = 0;
-			bind_info->next = NULL;
-			return 0;
 		}
 	}
-    }
 #endif
 
-    for (b = s->bind; b; b = b->next)
-	if ((strcmp((char *)b->driver->drv.name,
-		    (char *)bind_info->dev_info) == 0) &&
-	    (b->function == bind_info->function))
-	    break;
-    if (b == NULL) return -ENODEV;
-    if ((b->instance == NULL) ||
-	(b->instance->state & DEV_CONFIG_PENDING))
-	return -EAGAIN;
-    if (first)
-	node = b->instance->dev;
-    else
-	for (node = b->instance->dev; node; node = node->next)
-	    if (node == bind_info->next) break;
-    if (node == NULL) return -ENODEV;
-
-    strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
-    bind_info->major = node->major;
-    bind_info->minor = node->minor;
-    bind_info->next = node->next;
-    
-    return 0;
+	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 = pcmcia_get_dev(p_dev);
+			if (!p_dev)
+				continue;
+			goto found;
+		}
+	}
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+	return -ENODEV;
+
+ found:
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+	if ((!p_dev->instance) ||
+	    (p_dev->instance->state & DEV_CONFIG_PENDING)) {
+		ret = -EAGAIN;
+		goto err_put;
+	}
+
+	if (first)
+		node = p_dev->instance->dev;
+	else
+		for (node = p_dev->instance->dev; node; node = node->next)
+			if (node == bind_info->next)
+				break;
+	if (!node) {
+		ret = -ENODEV;
+		goto err_put;
+	}
+
+	strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+	bind_info->major = node->major;
+	bind_info->minor = node->minor;
+	bind_info->next = node->next;
+
+ err_put:
+	pcmcia_put_dev(p_dev);
+	return (ret);
 } /* get_device_info */
 
 /*====================================================================*/
 
 static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
-    socket_bind_t **b, *c;
-    struct pcmcia_device *p_dev;
-    unsigned long flags;
-
-    ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock,
-	  (char *)bind_info->dev_info);
-    for (b = &s->bind; *b; b = &(*b)->next)
-	if ((strcmp((char *)(*b)->driver->drv.name,
-		    (char *)bind_info->dev_info) == 0) &&
-	    ((*b)->function == bind_info->function))
-	    break;
-    if (*b == NULL)
-	return -ENODEV;
-    
-    c = *b;
-    c->driver->use_count--;
-    if (c->driver->detach) {
-	if (c->instance)
-	    c->driver->detach(c->instance);
-    }
-    module_put(c->driver->owner);
-    *b = c->next;
-    kfree(c);
-
-    /* unregister the pcmcia_device */
-    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)
-		    goto found;
-    }
-    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-    return 0;
+	struct pcmcia_device	*p_dev;
+	struct pcmcia_driver	*p_drv;
+	unsigned long		flags;
+
+	ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock,
+	       (char *)bind_info->dev_info);
+
+	/* unregister the pcmcia_device */
+	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)
+			goto found;
+	}
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+	return 0;
 
  found:
-    list_del(&p_dev->socket_device_list);
-    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+	list_del(&p_dev->socket_device_list);
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-    device_unregister(&p_dev->dev);
+	/* detach the "instance" */
+	p_drv = to_pcmcia_drv(p_dev->dev.driver);
+	if (p_drv) {
+		p_drv->use_count--;
+		if ((p_drv->detach) && (p_dev->instance))
+			p_drv->detach(p_dev->instance);
+		module_put(p_drv->owner);
+	}
 
-    return 0;
+	device_unregister(&p_dev->dev);
+
+	return 0;
 } /* unbind_request */
 
 /*======================================================================
diff -puN include/pcmcia/ds.h~pcmcia-remove-socket_bind_t-use-pcmcia_devices-instead include/pcmcia/ds.h
--- 25/include/pcmcia/ds.h~pcmcia-remove-socket_bind_t-use-pcmcia_devices-instead	2004-12-03 18:44:28.114509144 -0800
+++ 25-akpm/include/pcmcia/ds.h	2004-12-03 18:44:28.122507928 -0800
@@ -151,6 +151,10 @@ struct pcmcia_device {
 
 	struct list_head	socket_device_list;
 
+	/* deprecated, a cleaned up version will be moved into this
+	   struct soon */
+	dev_link_t		*instance;
+
 	struct device		dev;
 };
 
_
