From: Dominik Brodowski <linux@dominikbrodowski.de>

Move the struct client_t inside struct pcmcia_device.  This means it gets
proper reference counting as well.  The clients list inside struct
pcmcia_socket can be removed now.

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

 25-akpm/drivers/pcmcia/bulkmem.c     |    1 
 25-akpm/drivers/pcmcia/cs.c          |    4 -
 25-akpm/drivers/pcmcia/cs_internal.h |   14 -----
 25-akpm/drivers/pcmcia/ds.c          |   88 +++++++++++------------------------
 25-akpm/include/pcmcia/ds.h          |   15 +++++
 25-akpm/include/pcmcia/ss.h          |    1 
 6 files changed, 46 insertions(+), 77 deletions(-)

diff -puN drivers/pcmcia/bulkmem.c~pcmcia-move-struct-client_t-inside-struct-pcmcia_device drivers/pcmcia/bulkmem.c
--- 25/drivers/pcmcia/bulkmem.c~pcmcia-move-struct-client_t-inside-struct-pcmcia_device	2004-12-03 18:44:45.109925448 -0800
+++ 25-akpm/drivers/pcmcia/bulkmem.c	2004-12-03 18:44:45.120923776 -0800
@@ -27,6 +27,7 @@
 #include <pcmcia/cs.h>
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
 #include "cs_internal.h"
 
 #ifdef DEBUG
diff -puN drivers/pcmcia/cs.c~pcmcia-move-struct-client_t-inside-struct-pcmcia_device drivers/pcmcia/cs.c
--- 25/drivers/pcmcia/cs.c~pcmcia-move-struct-client_t-inside-struct-pcmcia_device	2004-12-03 18:44:45.111925144 -0800
+++ 25-akpm/drivers/pcmcia/cs.c	2004-12-03 18:44:45.122923472 -0800
@@ -41,6 +41,7 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
 #include "cs_internal.h"
 
 #ifdef CONFIG_PCI
@@ -199,8 +200,6 @@ static void pcmcia_release_socket(struct
 {
 	struct pcmcia_socket *socket = class_get_devdata(class_dev);
 
-	BUG_ON(socket->clients);
-
 	complete(&socket->socket_released);
 }
 
@@ -369,7 +368,6 @@ static void shutdown_socket(struct pcmci
 	kfree(s->config);
 	s->config = NULL;
     }
-    BUG_ON(s->clients);
     free_regions(&s->a_region);
     free_regions(&s->c_region);
 
diff -puN drivers/pcmcia/cs_internal.h~pcmcia-move-struct-client_t-inside-struct-pcmcia_device drivers/pcmcia/cs_internal.h
--- 25/drivers/pcmcia/cs_internal.h~pcmcia-move-struct-client_t-inside-struct-pcmcia_device	2004-12-03 18:44:45.112924992 -0800
+++ 25-akpm/drivers/pcmcia/cs_internal.h	2004-12-03 18:44:45.123923320 -0800
@@ -18,19 +18,7 @@
 #include <linux/config.h>
 
 #define CLIENT_MAGIC 	0x51E6
-typedef struct client_t {
-    u_short		client_magic;
-    struct pcmcia_socket *Socket;
-    u_char		Function;
-    dev_info_t		dev_info;
-    u_int		Attributes;
-    u_int		state;
-    event_t		EventMask, PendingEvents;
-    int (*event_handler)(event_t event, int priority,
-			 event_callback_args_t *);
-    event_callback_args_t event_callback_args;
-    struct client_t 	*next;
-} client_t;
+typedef struct client_t client_t;
 
 /* Flags in client state */
 #define CLIENT_CONFIG_LOCKED	0x0001
diff -puN drivers/pcmcia/ds.c~pcmcia-move-struct-client_t-inside-struct-pcmcia_device drivers/pcmcia/ds.c
--- 25/drivers/pcmcia/ds.c~pcmcia-move-struct-client_t-inside-struct-pcmcia_device	2004-12-03 18:44:45.114924688 -0800
+++ 25-akpm/drivers/pcmcia/ds.c	2004-12-03 18:44:45.125923016 -0800
@@ -353,6 +353,7 @@ static void pcmcia_put_dev(struct pcmcia
 static void pcmcia_release_dev(struct device *dev)
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	ds_dbg(1, "releasing dev %p\n", p_dev);
 	pcmcia_put_bus_socket(p_dev->socket->pcmcia);
 	kfree(p_dev);
 }
@@ -427,11 +428,11 @@ static int send_event_callback(struct de
 	if (p_dev->socket != data->skt)
 		return 0;
 
-	if (p_dev->client->state & (CLIENT_UNBOUND|CLIENT_STALE))
+	if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE))
 		return 0;
 
-	if (p_dev->client->EventMask & data->event)
-		return EVENT(p_dev->client, data->event, data->priority);
+	if (p_dev->client.EventMask & data->event)
+		return EVENT(&p_dev->client, data->event, data->priority);
 
 	return 0;
 }
@@ -556,10 +557,10 @@ static int bind_request(struct pcmcia_bu
 {
 	struct pcmcia_driver *p_drv;
 	struct pcmcia_device *p_dev, *tmp_dev;
-	client_t *client;
 	unsigned long flags;
 	int ret = 0;
 
+	s = pcmcia_get_bus_socket(s);
 	if (!s)
 		return -EINVAL;
 
@@ -567,25 +568,10 @@ static int bind_request(struct pcmcia_bu
 	       (char *)bind_info->dev_info);
 
 	p_drv = get_pcmcia_driver(&bind_info->dev_info);
-	if (!p_drv)
-		return -EINVAL;
-
-	if (!try_module_get(p_drv->owner))
-		return -EINVAL;
-
-	client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL);
-	if (!client) {
-		ret = -ENOMEM;
+	if ((!p_drv) || (!try_module_get(p_drv->owner))) {
+		ret = -EINVAL;
 		goto err_put;
 	}
-	memset(client, 0, sizeof(client_t));
-
-	client->client_magic = CLIENT_MAGIC;
-	client->Socket = s->parent;
-	client->Function = bind_info->function;
-	client->state = CLIENT_UNBOUND;
-	client->next = s->parent->clients;
-	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
@@ -595,20 +581,12 @@ static int bind_request(struct pcmcia_bu
 	p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
 	if (!p_dev) {
 		ret = -ENOMEM;
-		goto err_free_client;
+		goto err_put_module;
 	}
 	memset(p_dev, 0, sizeof(struct pcmcia_device));
 
-	s = pcmcia_get_bus_socket(s);
- 	if (!s) {
-		ret = -ENODEV;
-		kfree(p_dev);
-		goto err_free_client;
-	}
-
 	p_dev->socket = s->parent;
 	p_dev->func   = bind_info->function;
-	p_dev->client = client;
 
 	p_dev->dev.bus = &pcmcia_bus_type;
 	p_dev->dev.parent = s->parent->dev.dev;
@@ -616,11 +594,17 @@ static int bind_request(struct pcmcia_bu
 	sprintf (p_dev->dev.bus_id, "pcmcia%d.%d", p_dev->socket->sock, p_dev->func);
 	p_dev->dev.driver = &p_drv->drv;
 
+	/* compat */
+	p_dev->client.client_magic = CLIENT_MAGIC;
+	p_dev->client.Socket = s->parent;
+	p_dev->client.Function = bind_info->function;
+	p_dev->client.state = CLIENT_UNBOUND;
+	strlcpy(p_dev->client.dev_info, p_drv->drv.name, DEV_NAME_LEN);
+
 	ret = device_register(&p_dev->dev);
 	if (ret) {
 		kfree(p_dev);
-		pcmcia_put_bus_socket(s);
-		goto err_free_client;
+		goto err_put_module;
 	}
 
 	/*
@@ -640,15 +624,11 @@ static int bind_request(struct pcmcia_bu
 	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-	/* finally here the parent client is registered */
-	s->parent->clients = client;
-
 	if (p_drv->attach) {
 		p_dev->instance = p_drv->attach();
-		if (!p_dev->instance) {
+		if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
 			printk(KERN_NOTICE "ds: unable to create instance "
 			       "of '%s'!\n", (char *)bind_info->dev_info);
-			/* FIXME: client isn't freed here */
 			ret = -ENODEV;
 			goto err_unregister;
 		}
@@ -658,11 +638,14 @@ static int bind_request(struct pcmcia_bu
 
  err_unregister:
 	device_unregister(&p_dev->dev);
- err_free_client:
-	kfree(client);
- err_put:
 	module_put(p_drv->owner);
 	return (ret);
+
+ err_put_module:
+	module_put(p_drv->owner);
+ err_put:
+	pcmcia_put_bus_socket(s);
+	return (ret);
 } /* bind_request */
 
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
@@ -688,11 +671,11 @@ int pcmcia_register_client(client_handle
 			continue;
 		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 		list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) {
-			if ((p_dev->client->state & CLIENT_UNBOUND) &&
-			    (!strcmp(p_dev->client->dev_info, (char *)req->dev_info))) {
+			if ((p_dev->client.state & CLIENT_UNBOUND) &&
+			    (!strcmp(p_dev->client.dev_info, (char *)req->dev_info))) {
 				p_dev = pcmcia_get_dev(p_dev);
 				if (p_dev)
-					client = p_dev->client;
+					client = &p_dev->client;
 				spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 				goto found;
 			}
@@ -751,7 +734,6 @@ int pcmcia_register_client(client_handle
 	}
 
 	up(&s->skt_sem);
-	pcmcia_put_dev(p_dev); /* FIXME: put in deregister_client. */
 	return CS_SUCCESS;
 
  out_no_resource:
@@ -873,7 +855,7 @@ static int unbind_request(struct pcmcia_
 		}
 		p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
 		list_del(&p_dev->socket_device_list);
-		p_dev->client->state |= CLIENT_STALE;
+		p_dev->client.state |= CLIENT_STALE;
 		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
 		/* detach the "instance" */
@@ -892,10 +874,9 @@ static int unbind_request(struct pcmcia_
 
 int pcmcia_deregister_client(client_handle_t handle)
 {
-	client_t **client;
 	struct pcmcia_socket *s;
-	u_long flags;
 	int i;
+	struct pcmcia_device *p_dev = handle_to_pdev(handle);
 
 	if (CHECK_HANDLE(handle))
 		return CS_BAD_HANDLE;
@@ -910,18 +891,9 @@ int pcmcia_deregister_client(client_hand
 			goto warn_out;
 
 	if (handle->state & CLIENT_STALE) {
-		spin_lock_irqsave(&s->lock, flags);
-		client = &s->clients;
-		while ((*client) && ((*client) != handle))
-			client = &(*client)->next;
-		if (*client == NULL) {
-			spin_unlock_irqrestore(&s->lock, flags);
-			return CS_BAD_HANDLE;
-		}
-		*client = handle->next;
 		handle->client_magic = 0;
-		kfree(handle);
-		spin_unlock_irqrestore(&s->lock, flags);
+		handle->state &= ~CLIENT_STALE;
+		pcmcia_put_dev(p_dev);
 	} else {
 		handle->state = CLIENT_UNBOUND;
 		handle->event_handler = NULL;
diff -puN include/pcmcia/ds.h~pcmcia-move-struct-client_t-inside-struct-pcmcia_device include/pcmcia/ds.h
--- 25/include/pcmcia/ds.h~pcmcia-move-struct-client_t-inside-struct-pcmcia_device	2004-12-03 18:44:45.115924536 -0800
+++ 25-akpm/include/pcmcia/ds.h	2004-12-03 18:44:45.125923016 -0800
@@ -128,7 +128,6 @@ typedef struct dev_link_t {
 
 
 struct pcmcia_socket;
-struct client_t;
 
 extern struct bus_type pcmcia_bus_type;
 
@@ -154,7 +153,18 @@ struct pcmcia_device {
 	/* deprecated, a cleaned up version will be moved into this
 	   struct soon */
 	dev_link_t		*instance;
-	struct client_t		*client;
+	struct client_t {
+		u_short			client_magic;
+		struct pcmcia_socket	*Socket;
+		u_char			Function;
+		dev_info_t		dev_info;
+		u_int			Attributes;
+		u_int			state;
+		event_t			EventMask, PendingEvents;
+		int (*event_handler)	(event_t event, int priority,
+					 event_callback_args_t *);
+		event_callback_args_t 	event_callback_args;
+	}			client;
 
 	struct device		dev;
 };
@@ -162,6 +172,7 @@ struct pcmcia_device {
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
 #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
 
+#define handle_to_pdev(handle) container_of(handle, struct pcmcia_device, client);
 
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);
diff -puN include/pcmcia/ss.h~pcmcia-move-struct-client_t-inside-struct-pcmcia_device include/pcmcia/ss.h
--- 25/include/pcmcia/ss.h~pcmcia-move-struct-client_t-inside-struct-pcmcia_device	2004-12-03 18:44:45.117924232 -0800
+++ 25-akpm/include/pcmcia/ss.h	2004-12-03 18:44:45.126922864 -0800
@@ -153,7 +153,6 @@ struct pcmcia_socket {
 	u_int				state;
 	u_short				functions;
 	u_short				lock_count;
-	client_handle_t			clients;
 	pccard_mem_map			cis_mem;
 	void __iomem 			*cis_virt;
 	struct config_t			*config;
_