[PATCHES] re-updated pcmcia_device patches

Dominik Brodowski linux at brodo.de
Thu Oct 2 19:26:35 BST 2003


On Thu, Oct 02, 2003 at 06:16:50PM +0200, Dominik Brodowski wrote:
> Updated the patches once more as I inadvertedly removed David Hinds'
> copyright (again sorry for that...)
> 
> change-ds-license
> pcmcia_device
> remove_socket_bind_t
> remove_internal_driver_use_count
> 
> Patches for 2.6.0-test6-bk-current. Please apply,

Aww, forgot to attach the patches. Sorry.

	Dominik
-------------- next part --------------
As previously discussed and ack'ed by David Hinds, change the 
license of ds.c ands.h to GPL only.

 drivers/pcmcia/ds.c |   27 +++++----------------------
 include/pcmcia/ds.h |   23 +++--------------------
 2 files changed, 8 insertions(+), 42 deletions(-)

diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-10-02 17:45:50.357404680 +0200
+++ linux/drivers/pcmcia/ds.c	2003-10-02 17:59:23.271822904 +0200
@@ -3,32 +3,15 @@
     PC Card Driver Services
     
     ds.c 1.112 2001/10/13 00:08:28
-    
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as
+    published by the Free Software Foundation.
+     
     The initial developer of the original code is David A. Hinds
     <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in
-    which case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
 ======================================================================*/
 
 #include <linux/config.h>
@@ -65,7 +48,7 @@
 
 MODULE_AUTHOR("David Hinds <dahinds at users.sourceforge.net>");
 MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
-MODULE_LICENSE("Dual MPL/GPL");
+MODULE_LICENSE("GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h	2003-10-02 17:45:58.134222424 +0200
+++ linux/include/pcmcia/ds.h	2003-10-02 18:05:12.132787976 +0200
@@ -1,30 +1,13 @@
 /*
  * ds.h 1.56 2000/06/12 21:55:40
  *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License. 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  *
  * The initial developer of the original code is David A. Hinds
  * <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use
- * your version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
  */
 
 #ifndef _LINUX_DS_H
-------------- next part --------------
Introduce a new struct pcmcia_device. So far it doesn't do anything 
useful besides showing up in the sysfs tree, but this will change soon.

The device registration is only done after the userspace carmgr 
detected a pcmcia card, found it in its database, and then tries to bind
a driver for this device. This can only properly be moved up if the PCMCIA
socket resource management is done within the kernel. And this still has
to wait for other changes...

 drivers/pcmcia/ds.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 
 include/pcmcia/ds.h |   16 ++++++++++++
 2 files changed, 82 insertions(+), 2 deletions(-)

diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-10-02 18:09:47.701895104 +0200
+++ linux/drivers/pcmcia/ds.c	2003-10-02 18:09:57.296436512 +0200
@@ -91,7 +91,12 @@
 	socket_bind_t		*bind;
 	struct device		*socket_dev;
 	struct pcmcia_socket	*parent;
+
+	/* the PCMCIA devices connected to this socket (normally one, more
+	 * for multifunction devices: */
+	struct list_head	devices_list;
 };
+static spinlock_t pcmcia_dev_list_lock = SPIN_LOCK_UNLOCKED;
 
 #define SOCKET_PRESENT		0x01
 #define SOCKET_BUSY		0x02
@@ -173,6 +178,15 @@
 }
 #endif
 
+/* pcmcia_device handling */
+
+static void pcmcia_release_dev(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	kfree(p_dev);
+}
+
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -310,9 +324,11 @@
 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;
     bind_req_t bind_req;
     int ret;
+    unsigned long flags;
 
     if (!s)
 	    return -EINVAL;
@@ -361,7 +377,36 @@
     b->instance = NULL;
     b->next = s->bind;
     s->bind = b;
-    
+
+    /* Currently, the userspace pcmcia cardmgr detects pcmcia devices. 
+     * Here this information is translated into a kernel
+     * struct pcmcia_device.
+     */
+
+    p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+    if (!p_dev)
+	    goto no_p_dev;
+    memset(p_dev, 0, sizeof(struct pcmcia_device));
+
+    p_dev->socket = s->parent;
+    p_dev->func   = bind_info->function;
+
+    p_dev->dev.bus = &pcmcia_bus_type;
+    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;
+    ret = device_register(&p_dev->dev);
+    if (ret) {
+	    kfree(p_dev);
+	    goto no_p_dev;
+    }
+    spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+    list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ no_p_dev:
+
     if (driver->attach) {
 	b->instance = driver->attach();
 	if (b->instance == NULL) {
@@ -371,7 +416,7 @@
 	    return -ENODEV;
 	}
     }
-    
+
     return 0;
 } /* bind_request */
 
@@ -447,6 +492,8 @@
 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;
 
     DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
 	  (char *)bind_info->dev_info);
@@ -467,6 +514,22 @@
     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;
+
+ found:
+    list_del(&p_dev->socket_device_list);
+    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+    device_unregister(&p_dev->dev);
+   
     return 0;
 } /* unbind_request */
 
@@ -826,6 +889,7 @@
 
 	init_waitqueue_head(&s->queue);
 	init_waitqueue_head(&s->request);
+	INIT_LIST_HEAD(&s->devices_list);
 
 	/* initialize data */
 	s->socket_dev = socket->dev.dev;
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h	2003-10-02 18:09:47.701895104 +0200
+++ linux/include/pcmcia/ds.h	2003-10-02 18:09:57.334430736 +0200
@@ -141,5 +141,21 @@
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);
 
+struct pcmcia_socket;
+
+struct pcmcia_device {
+	/* the socket and the function no [for multifunction devices]
+	   uniquely define a pcmcia_device */
+	struct pcmcia_socket	*socket;
+	u8			func; 
+
+	struct list_head	socket_device_list;
+
+	struct device		dev;
+};
+
+#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
+#define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_DS_H */
-------------- next part --------------
Remove the internal driver use_count in ds.c, as the reference counting 
is done in the module core anyways, and that reference count is available 
for cardmgr's usage by a call to module_refcount. And if 
!CONFIG_MODULE_UNLOAD, rmmod is useless anyways, so avoid that call by
cardmgr at all.

 drivers/pcmcia/ds.c |   14 ++++++++------
 include/pcmcia/ds.h |    1 -
 2 files changed, 8 insertions(+), 7 deletions(-)

diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-10-02 18:13:48.950219784 +0200
+++ linux/drivers/pcmcia/ds.c	2003-10-02 18:12:30.142200424 +0200
@@ -127,7 +127,6 @@
 	if (!driver)
 		return -EINVAL;
 
- 	driver->use_count = 0;
 	driver->drv.bus = &pcmcia_bus_type;
 
 	return driver_register(&driver->drv);
@@ -149,10 +148,15 @@
 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
 {
 	char **p = d;
-	struct pcmcia_driver *p_dev = container_of(driver, 
+	struct pcmcia_driver *p_drv = container_of(driver, 
 						   struct pcmcia_driver, drv);
-
-	*p += sprintf(*p, "%-24.24s 1 %d\n", driver->name, p_dev->use_count);
+	*p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name, 
+#ifdef CONFIG_MODULE_UNLOAD
+		      module_refcount(p_drv->owner)
+#else
+		      1
+#endif
+		);
 	d = (void *) p;
 
 	return 0;
@@ -390,7 +394,6 @@
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
 	/* try to create an "instance"... */
-	p_drv->use_count++;
 	if (p_drv->attach) {
 		p_dev->instance = p_drv->attach();
 		if (!p_dev->instance) {
@@ -514,7 +517,6 @@
 	/* 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);
 	}
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h	2003-10-02 18:13:48.950219784 +0200
+++ linux/include/pcmcia/ds.h	2003-10-02 18:12:30.178194952 +0200
@@ -127,7 +127,6 @@
 extern struct bus_type pcmcia_bus_type;
 
 struct pcmcia_driver {
-	int			use_count;
 	dev_link_t		*(*attach)(void);
 	void			(*detach)(dev_link_t *);
 	struct module		*owner;
-------------- next part --------------
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 
bind_request and unbind_request.

 drivers/pcmcia/ds.c |  279 +++++++++++++++++++++++++---------------------------
 include/pcmcia/ds.h |    4
 2 files changed, 139 insertions(+), 144 deletions(-)

diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-10-02 18:11:11.457162368 +0200
+++ linux/drivers/pcmcia/ds.c	2003-10-02 18:11:17.863188504 +0200
@@ -61,13 +61,6 @@
 
 /*====================================================================*/
 
-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
@@ -88,8 +81,7 @@
 	int			req_pending, req_result;
 	wait_queue_head_t	queue, request;
 	struct work_struct	removal;
-	socket_bind_t		*bind;
-	struct device		*socket_dev;
+
 	struct pcmcia_socket	*parent;
 
 	/* the PCMCIA devices connected to this socket (normally one, more
@@ -323,109 +315,114 @@
 
 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;
-    bind_req_t bind_req;
-    int ret;
-    unsigned long flags;
+	struct pcmcia_driver	*p_drv;
+	struct pcmcia_device	*p_dev;
+	bind_req_t		bind_req;
+	int			ret;
+	unsigned long		flags;
 
-    if (!s)
-	    return -EINVAL;
+	if (!s)
+		return -EINVAL;
 
-    DEBUG(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;
-    }
-
-    if (!try_module_get(driver->owner))
-	    return -EINVAL;
-
-    bind_req.Socket = s->parent;
-    bind_req.Function = bind_info->function;
-    bind_req.dev_info = (dev_info_t *) driver->drv.name;
-    ret = pcmcia_bind_device(&bind_req);
-    if (ret != CS_SUCCESS) {
-	cs_error(NULL, BindDevice, ret);
-	printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
-	       (char *)dev_info, s->parent->sock);
-	module_put(driver->owner);
-	return -ENODEV;
-    }
+	DEBUG(2, "bind_request(%d, '%s')\n", s->parent->sock,
+	      (char *)bind_info->dev_info);
 
-    /* Add binding to list for this socket */
-    driver->use_count++;
-    b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
-    if (!b) 
-    {
-    	driver->use_count--;
-	module_put(driver->owner);
-	return -ENOMEM;    
-    }
-    b->driver = driver;
-    b->function = bind_info->function;
-    b->instance = NULL;
-    b->next = s->bind;
-    s->bind = b;
-
-    /* Currently, the userspace pcmcia cardmgr detects pcmcia devices. 
-     * Here this information is translated into a kernel
-     * struct pcmcia_device.
-     */
+	/* find the driver which shall be bound to this device */
+	p_drv = get_pcmcia_driver(&bind_info->dev_info);
+	if (!p_drv)
+		return -EINVAL;
+	if (!try_module_get(p_drv->owner))
+		return -EINVAL;
 
-    p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
-    if (!p_dev)
-	    goto no_p_dev;
-    memset(p_dev, 0, sizeof(struct pcmcia_device));
-
-    p_dev->socket = s->parent;
-    p_dev->func   = bind_info->function;
-
-    p_dev->dev.bus = &pcmcia_bus_type;
-    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;
-    ret = device_register(&p_dev->dev);
-    if (ret) {
-	    kfree(p_dev);
-	    goto no_p_dev;
-    }
-    spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-    list_add_tail(&p_dev->socket_device_list, &s->devices_list);
-    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+	/* verify that no such device exists at the moment. */
+	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) {
+			spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+			bind_info->instance = p_dev->instance;
+			ret = -EBUSY;
+			goto err_put;
+		}
+	}
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+	/* pcmcia-cs bind -- will be unified soon */
+	bind_req.Socket = s->parent;
+	bind_req.Function = bind_info->function;
+	bind_req.dev_info = (dev_info_t *) p_drv->drv.name;
+	ret = pcmcia_bind_device(&bind_req);
+	if (ret != CS_SUCCESS) {
+		cs_error(NULL, BindDevice, ret);
+		printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
+		       (char *)dev_info, s->parent->sock);
+		ret = -ENODEV;
+		goto err_put;
+	}
 
- no_p_dev:
+	/* Currently, the userspace pcmcia cardmgr detects pcmcia devices. 
+	 * Here this information is translated into a kernel
+	 * struct pcmcia_device.
+	 */
 
-    if (driver->attach) {
-	b->instance = driver->attach();
-	if (b->instance == NULL) {
-	    printk(KERN_NOTICE "ds: unable to create instance "
-		   "of '%s'!\n", (char *)bind_info->dev_info);
-	    module_put(driver->owner);
-	    return -ENODEV;
+	p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+	if (!p_dev) {
+		ret = -ENOMEM;
+		goto err_put;
 	}
-    }
+	memset(p_dev, 0, sizeof(struct pcmcia_device));
 
-    return 0;
+	p_dev->socket = s->parent;
+	p_dev->func   = bind_info->function;
+
+	p_dev->dev.bus = &pcmcia_bus_type;
+	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 = &p_drv->drv;
+	ret = device_register(&p_dev->dev);
+	if (ret) {
+		ret = -ENODEV;
+		kfree(p_dev);
+		goto err_put;
+	}
+	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+	/* try to create an "instance"... */
+	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);
+			ret = -ENODEV;
+			goto err_unreg;
+		}
+	}
+
+	return 0;
+
+
+ err_unreg:
+	spin_lock_irqsave(&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);
+
+ err_put:
+	module_put(p_drv->owner);
+	return (ret);
 } /* bind_request */
 
 /*====================================================================*/
 
 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;
+    struct pcmcia_device *p_dev;
+    unsigned long flags;
 
 #ifdef CONFIG_CARDBUS
     /*
@@ -463,19 +460,23 @@
     }
 #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))
+    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 -ENODEV;
+
+ found:
+    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+    if ((p_dev->instance == NULL) ||
+	(p_dev->instance->state & DEV_CONFIG_PENDING))
 	return -EAGAIN;
     if (first)
-	node = b->instance->dev;
+	node = p_dev->instance->dev;
     else
-	for (node = b->instance->dev; node; node = node->next)
+	for (node = p_dev->instance->dev; node; node = node->next)
 	    if (node == bind_info->next) break;
     if (node == NULL) return -ENODEV;
 
@@ -491,46 +492,37 @@
 
 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;
-
-    DEBUG(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)
+	struct pcmcia_device	*p_dev;
+	struct pcmcia_driver	*p_drv;
+	unsigned long		flags;
+
+	DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
+	      (char *)bind_info->dev_info);
+
+	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 -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;
 
  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);
-   
-    return 0;
+	/* 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);
+
+	device_unregister(&p_dev->dev);
+
+	return 0;
 } /* unbind_request */
 
 /*======================================================================
@@ -892,7 +884,6 @@
 	INIT_LIST_HEAD(&s->devices_list);
 
 	/* initialize data */
-	s->socket_dev = socket->dev.dev;
 	INIT_WORK(&s->removal, handle_removal, s);
 	s->parent = socket;
 
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h	2003-10-02 18:11:11.497156288 +0200
+++ linux/include/pcmcia/ds.h	2003-10-02 18:11:17.901182728 +0200
@@ -151,6 +151,10 @@
 
 	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;
 };
 


More information about the linux-pcmcia mailing list