[PATCHES] pcmcia: two more ds.c patches

Dominik Brodowski linux at brodo.de
Sun Jun 22 11:24:38 BST 2003


... which are based on the earlier ds_device patch. Finally, we're doing 
something useful with struct pcmcia_device:

pcmcia_ds_bind_probe: 	replace socket_bind_t with struct pcmcia_device
pcmcia_ds_sysfs_output:	add some sysfs output.

	Dominik

based on / requires:
	pcmcia_ds_no_sleep
	pcmcia_ds_license
	pcmcia_ds_resources_1ab
	pcmcia_ds_device
-------------- next part --------------
Replace pcmcia_bind_device and pcmcia_unbind_device with more generic
->probe and ->remove callbacks which may be called from an in-kernel
matching function as well. A cardmgr compatibility layer makes sure
that existing setups work.

 drivers/pcmcia/ds.c |  241 +++++++++++++++++++++++++++++-----------------------
 include/pcmcia/ds.h |    3
 2 files changed, 141 insertions(+), 103 deletions(-)

diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-06-22 08:28:19.000000000 +0200
+++ linux/drivers/pcmcia/ds.c	2003-06-22 08:27:34.000000000 +0200
@@ -63,13 +63,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
@@ -89,7 +82,7 @@
 	user_info_t		*user;
 	int			req_pending, req_result;
 	wait_queue_head_t	queue, request;
-	socket_bind_t		*bind;
+
 	struct device		*socket_dev;
 	struct pcmcia_socket	*parent;
 
@@ -137,6 +130,10 @@
 static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
 static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr);
 
+static int pcmcia_device_probe(struct device *dev);
+static int pcmcia_device_remove(struct device *dev);
+
+
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
  *
@@ -149,6 +146,8 @@
 
  	driver->use_count = 0;
 	driver->drv.bus = &pcmcia_bus_type;
+	driver->drv.probe = pcmcia_device_probe;
+	driver->drv.remove = pcmcia_device_remove;
 
 	return driver_register(&driver->drv);
 }
@@ -190,6 +189,71 @@
 }
 #endif
 
+
+/********************* generic probe/remove callbacks ***********************/
+
+
+static int pcmcia_device_probe(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver *p_drv = to_pcmcia_drv(dev->driver);
+	struct pcmcia_socket *s = p_dev->socket;
+	int ret = 0;
+	bind_req_t bind_req;
+    
+	DEBUG(0, "ds: pcmcia_device_probe()");
+
+	bind_req.Socket = s;
+	bind_req.Function = p_dev->func;
+	bind_req.dev_info = (dev_info_t *) p_drv->drv.name;
+	ret = pcmcia_bind_device(&bind_req);
+	if (ret) {
+		cs_error(NULL, BindDevice, ret);
+		printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
+		       (char *)dev_info, s->sock);
+		ret = -ENODEV;
+		goto e_out;
+	}
+
+	/* Add binding to list for this socket */
+	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 *)p_drv->drv.name);
+			ret = -ENODEV;
+			goto e_dec_out;
+		}
+	}
+	return 0;
+    
+ e_dec_out:
+	p_drv->use_count--;
+ e_out:
+	module_put(p_drv->owner);
+	return (ret);
+}
+
+
+static int pcmcia_device_remove(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver *p_drv = to_pcmcia_drv(dev->driver);
+
+	DEBUG(0, "ds: pcmcia_device_remove()");
+
+	if (p_drv->detach)
+		p_drv->detach(p_dev->instance);
+
+	p_drv->use_count--;
+	module_put(p_drv->owner);
+
+	return 0;
+}
+
+
 /*********************** device adding / removing ***************************/
 
 
@@ -455,78 +519,46 @@
 
 static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
-    struct pcmcia_driver *driver;
-    socket_bind_t *b;
-    bind_req_t bind_req;
-    int ret;
-
-    if (!s)
-	    return -EINVAL;
+	struct pcmcia_driver *driver;
+	struct pcmcia_device *dev;
+	int ret = -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;
-    }
+	driver = get_pcmcia_driver(&bind_info->dev_info);
+	if (!driver)
+		return -EINVAL;
 
-    if (!try_module_get(driver->owner))
-	    return -EINVAL;
+	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;
-    }
+	if (!get_bus(&pcmcia_bus_type))
+		return -EINVAL;
 
-    /* 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;
-    
-    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;
+	down(&s->devices_list_sem);
+	list_for_each_entry(dev, &s->devices_list, socket_device_list) {
+		if (dev->func == bind_info->function) {
+			if (dev->dev.driver == &driver->drv) {
+				ret = 0; /* in-kernel matching got here first */
+				break;
+			}
+			dev->dev.driver = &driver->drv;
+			ret = pcmcia_device_probe(&dev->dev);
+			if (!ret)
+				device_bind_driver(&dev->dev);
+		}
 	}
-    }
-    
-    return 0;
+	up(&s->devices_list_sem);
+
+	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_driver *driver;
+    struct pcmcia_device *dev;
+    int ret = -ENODEV;
 
 #ifdef CONFIG_CARDBUS
     /*
@@ -564,27 +596,40 @@
     }
 #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;
+    driver = get_pcmcia_driver(&bind_info->dev_info);
+    if (!driver)
+	    return -ENODEV;
+
+    down(&s->devices_list_sem);
+    list_for_each_entry(dev, &s->devices_list, socket_device_list) {
+	    if ((dev->func == bind_info->function) &&
+		(dev->dev.driver == &driver->drv)) {
+		    ret = 0;
+		    break;
+	    }
+    }
+    up(&s->devices_list_sem);
+
+    if (ret)
+	    return (ret);
+
+    if ((!dev->instance) || 
+	(dev->instance->state & DEV_CONFIG_PENDING))
+	    return -EAGAIN;
     if (first)
-	node = b->instance->dev;
+	    node = dev->instance->dev;
     else
-	for (node = b->instance->dev; node; node = node->next)
-	    if (node == bind_info->next) break;
-    if (node == NULL) return -ENODEV;
+	    for (node = dev->instance->dev; node; node = node->next)
+		    if (node == bind_info->next) 
+			    break;
+    if (!node) 
+	    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;
 } /* get_device_info */
 
@@ -592,28 +637,18 @@
 
 static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
-    socket_bind_t **b, *c;
+	struct pcmcia_device *dev;
 
-    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)
-	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);
-    return 0;
+	down(&s->devices_list_sem);
+	list_for_each_entry(dev, &s->devices_list, socket_device_list) {
+		if ((dev->func == bind_info->function) && dev->dev.driver) {
+			device_release_driver(&dev->dev);
+			put_bus(&pcmcia_bus_type);
+		}
+	}
+	up(&s->devices_list_sem);
+
+	return 0;
 } /* unbind_request */
 
 /*======================================================================
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h	2003-06-22 08:28:19.000000000 +0200
+++ linux/include/pcmcia/ds.h	2003-06-21 07:52:02.000000000 +0200
@@ -179,6 +179,9 @@
 
 	unsigned int			has_funcid;
 	cistpl_funcid_t			funcid;
+
+	/* deprecated */
+	dev_link_t			*instance;
 };
 
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
-------------- next part --------------
This patch adds seven files (manf_id, card_id, func_id, vers1 to
vers4) to any pcmcia device registered with the driver model core.

 ds.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 55 insertions(+)

diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-06-22 08:54:50.000000000 +0200
+++ linux/drivers/pcmcia/ds.c	2003-06-22 08:58:32.000000000 +0200
@@ -254,6 +254,43 @@
 }
 
 
+/************************ per-device sysfs output ***************************/
+
+#define show_one(file_name, object, test)	 			\
+static ssize_t show_##file_name 					\
+(struct device *dev, char *buf)						\
+{									\
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\
+	return p_dev->test ? sprintf (buf, "%x\n", p_dev->object) : 	\
+			sprintf(buf, "unknown\n");			\
+}	 								\
+DEVICE_ATTR(file_name, 0444, show_##file_name, NULL);
+
+show_one(func_id, funcid.func, has_funcid);
+show_one(manf_id, manfid.manf, has_manfid);
+show_one(card_id, manfid.card, has_manfid);
+
+#define show_one_s(file_name, object, test)	 			\
+static ssize_t show_##file_name 					\
+(struct device *dev, char *buf)						\
+{									\
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\
+	return test ? sprintf (buf, "%s\n", object) : 			\
+			sprintf(buf, "\n");				\
+}	 								\
+DEVICE_ATTR(file_name, 0444, show_##file_name, NULL);
+
+show_one_s(vers1, (p_dev->vers1.str + p_dev->vers1.ofs[0]), 
+	   (p_dev->vers1.ns >= 1));
+show_one_s(vers2, (p_dev->vers1.str + p_dev->vers1.ofs[1]), 
+	   (p_dev->vers1.ns >= 2));
+show_one_s(vers3, (p_dev->vers1.str + p_dev->vers1.ofs[2]), 
+	   (p_dev->vers1.ns >= 3));
+show_one_s(vers4, (p_dev->vers1.str + p_dev->vers1.ofs[3]), 
+	   (p_dev->vers1.ns >= 4));
+
+
+
 /*********************** device adding / removing ***************************/
 
 
@@ -360,6 +397,15 @@
 	}
 	list_add(&p_dev->socket_device_list, &s->pcmcia->devices_list);
 
+	/* add sysfs files */
+	device_create_file(&p_dev->dev, &dev_attr_func_id);
+	device_create_file(&p_dev->dev, &dev_attr_manf_id);
+	device_create_file(&p_dev->dev, &dev_attr_card_id);
+	device_create_file(&p_dev->dev, &dev_attr_vers1);
+	device_create_file(&p_dev->dev, &dev_attr_vers2);
+	device_create_file(&p_dev->dev, &dev_attr_vers3);
+	device_create_file(&p_dev->dev, &dev_attr_vers4);
+
 	/* if we got a multifunction device, we need to register more devices,
 	 * so go back up */
 	func++;
@@ -381,6 +427,15 @@
 	down(&s->pcmcia->devices_list_sem);
 	list_for_each_safe(p1, p2, &s->pcmcia->devices_list) {
 		struct pcmcia_device *p_dev = container_of(p1, struct pcmcia_device, socket_device_list);
+
+		device_remove_file(&p_dev->dev, &dev_attr_func_id);
+		device_remove_file(&p_dev->dev, &dev_attr_manf_id);
+		device_remove_file(&p_dev->dev, &dev_attr_card_id);
+		device_remove_file(&p_dev->dev, &dev_attr_vers1);
+		device_remove_file(&p_dev->dev, &dev_attr_vers2);
+		device_remove_file(&p_dev->dev, &dev_attr_vers3);
+		device_remove_file(&p_dev->dev, &dev_attr_vers4);
+
 		device_unregister(&p_dev->dev);
 		list_del(&p_dev->socket_device_list);
 		kfree(p_dev);


More information about the linux-pcmcia mailing list