updated patches to handle multifunctional single-function devices

Dominik Brodowski linux at dominikbrodowski.de
Mon Dec 13 11:05:03 EST 2004


I've uploaded new versions of some patches of the pcmcia-17, -18, -19, -20
and -21 patchsets to 

http://kernel.org/pub/linux/kernel/people/brodo/patches/2.6.10-rc3/
http://kernel.org/pub/linux/kernel/people/brodo/patchsets/

and pushed the ones of -17, -18 and -19 to akpm. 

The only functional change is in pcmcia-17-06-pcmcia-device, which I append 
to this message: multiple drivers may be needed for one physical PCMCIA device
and for one physical PCMCIA "function". All other changes are just
"follow-ups" and/or rediffs to this functional change.

I'll update the additional patches already to be found at the places above
[2[2-4]-*] in the following days.

	Dominik


Add pcmcia_device(s). They're named pcmciaX.Y with X being the socket number
and Y being the "device" number -- one PCMCIA card may have several 
hardware-implemented functions (so-called multifunction devices) or may be
able to be driver by two drivers at the same time (e.g. pcnet_cs and 
serial_cs).

Signed-off-by: Dominik Brodowski <linux at brodo.de>
Index: 2.6.10-rc3/drivers/pcmcia/ds.c
===================================================================
--- 2.6.10-rc3.orig/drivers/pcmcia/ds.c	2004-12-13 15:21:02.000000000 +0100
+++ 2.6.10-rc3/drivers/pcmcia/ds.c	2004-12-13 15:55:04.614965062 +0100
@@ -101,7 +101,15 @@
 	wait_queue_head_t	queue, request;
 	socket_bind_t		*bind;
 	struct pcmcia_socket	*parent;
+
+	/* the PCMCIA devices connected to this socket (normally one, more
+	 * for multifunction devices: */
+	struct list_head	devices_list;
+	u8			device_count; /* the number of devices, used
+					       * only internally and subject
+					       * to incorrectness and change */
 };
+static spinlock_t pcmcia_dev_list_lock;
 
 #define DS_SOCKET_PRESENT		0x01
 #define DS_SOCKET_BUSY			0x02
@@ -328,6 +336,16 @@
 }
 #endif
 
+/* pcmcia_device handling */
+
+static void pcmcia_release_dev(struct device *dev)
+{
+	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	p_dev->socket->pcmcia->device_count = 0;
+	kfree(p_dev);
+}
+
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -491,8 +509,10 @@
 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;
 	client_t *client;
+	unsigned long flags;
 
 	if (!s)
 		return -EINVAL;
@@ -543,6 +563,38 @@
 	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) {
+		/* FIXME: client isn't freed here */
+		goto no_p_dev;
+	}
+	memset(p_dev, 0, sizeof(struct pcmcia_device));
+
+	p_dev->socket = s->parent;
+	p_dev->device_no = (s->device_count++);
+	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->device_no);
+	p_dev->dev.driver = &driver->drv;
+	if (device_register(&p_dev->dev)) {
+		/* FIXME: client isn't freed here */
+		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:
+
 	driver->use_count++;
 	if (driver->attach) {
 		b->instance = driver->attach();
@@ -632,6 +684,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;
 
     ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock,
 	  (char *)bind_info->dev_info);
@@ -652,6 +706,22 @@
     module_put(c->driver->owner);
     *b = c->next;
     kfree(c);
+
+ restart:
+    /* 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) {
+		    list_del(&p_dev->socket_device_list);
+		    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+		    device_unregister(&p_dev->dev);
+
+		    /* multiple devices may be registered to this "function" */
+		    goto restart;
+	    }
+    }
+    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
     return 0;
 } /* unbind_request */
 
@@ -1034,6 +1104,7 @@
 
 	init_waitqueue_head(&s->queue);
 	init_waitqueue_head(&s->request);
+	INIT_LIST_HEAD(&s->devices_list);
 
 	/* initialize data */
 	s->parent = socket;
@@ -1090,6 +1161,8 @@
 {
 	int i;
 
+	spin_lock_init(&pcmcia_dev_list_lock);
+
 	bus_register(&pcmcia_bus_type);
 	class_interface_register(&pcmcia_bus_interface);
 
Index: 2.6.10-rc3/include/pcmcia/ds.h
===================================================================
--- 2.6.10-rc3.orig/include/pcmcia/ds.h	2004-12-13 15:21:02.000000000 +0100
+++ 2.6.10-rc3/include/pcmcia/ds.h	2004-12-13 15:55:04.614965062 +0100
@@ -127,6 +127,8 @@
     ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
 
 
+struct pcmcia_socket;
+
 extern struct bus_type pcmcia_bus_type;
 
 struct pcmcia_driver {
@@ -141,6 +143,26 @@
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
+struct pcmcia_device {
+	/* the socket and the device_no [for multifunction devices]
+	   uniquely define a pcmcia_device */
+	struct pcmcia_socket	*socket;
+
+	u8			device_no;
+
+	/* the hardware "function" device; certain subdevices can
+	 * share one hardware "function" device. */
+	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)
+
+
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);
 




More information about the linux-pcmcia mailing list