[PATCH] pcmcia: new socket initialization interface

Dominik Brodowski linux at brodo.de
Sat May 17 23:14:04 BST 2003


Add a more sane socket registration interface.

Previously, it was messed up because Greg's struct class hadn't been
invented when I wrote the code: there may be multiple sockets per
"struct device", and there is the need for one "struct class_device"
for each socket.

 drivers/pcmcia/cs.c         |  243 ++++++++++++++++++++------------------------
 drivers/pcmcia/ds.c         |   58 +++-------
 drivers/pcmcia/i82092.c     |   50 ++++-----
 drivers/pcmcia/i82365.c     |   43 ++++---
 drivers/pcmcia/pci_socket.c |   24 +---
 drivers/pcmcia/pci_socket.h |    2
 drivers/pcmcia/tcic.c       |   40 +++----
 include/pcmcia/ss.h         |   20 +--
 8 files changed, 217 insertions(+), 263 deletions(-)

diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-original/drivers/pcmcia/cs.c	2003-05-17 21:19:17.000000000 +0200
+++ linux/drivers/pcmcia/cs.c	2003-05-17 21:22:45.000000000 +0200
@@ -303,7 +303,6 @@
 ======================================================================*/
 
 static int pccardd(void *__skt);
-void pcmcia_unregister_socket(struct class_device *dev);
 
 #define to_class_data(dev) dev->class_data
 
@@ -321,12 +320,69 @@
 	return NULL;
 }
 
+/**
+ * socket drivers are expected to use the following callbacks in their 
+ * .drv struct:
+ *  - pcmcia_socket_dev_suspend
+ *  - pcmcia_socket_dev_resume
+ * These functions check for the appropriate struct pcmcia_soket arrays,
+ * and pass them to the low-level functions pcmcia_{suspend,resume}_socket
+ */
+static int socket_resume(socket_info_t *skt);
+static int socket_suspend(socket_info_t *skt);
 
-static int pcmcia_add_socket(struct pcmcia_socket *socket)
+int pcmcia_socket_dev_suspend(struct device *dev, u32 state, u32 level)
 {
+	struct pcmcia_socket *socket;
 	socket_info_t *s;
-	int ret;
 
+	if (level != SUSPEND_SAVE_STATE)
+		return 0;
+
+	down(&pcmcia_socket_list_lock);
+	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
+		if (socket->dev.dev != dev)
+			continue;
+		s = (socket_info_t *) socket->s_info;
+		down(&s->skt_sem);
+		socket_suspend(s);
+		up(&s->skt_sem);
+	}
+	up(&pcmcia_socket_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pcmcia_socket_dev_suspend);
+
+int pcmcia_socket_dev_resume(struct device *dev, u32 level)
+{
+	struct pcmcia_socket *socket;
+	socket_info_t *s;
+
+	if (level != RESUME_RESTORE_STATE)
+		return 0;
+
+	down(&pcmcia_socket_list_lock);
+	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
+		if (socket->dev.dev != dev)
+			continue;
+		s = (socket_info_t *) socket->s_info;
+		down(&s->skt_sem);
+		socket_resume(s);
+		up(&s->skt_sem);
+	}
+	up(&pcmcia_socket_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pcmcia_socket_dev_resume);
+
+
+static int pcmcia_add_socket(struct class_device *class_dev)
+{
+	struct pcmcia_socket *socket = class_get_devdata(class_dev);
+	socket_info_t *s;
+	int ret;
 	s = (socket_info_t *) socket->s_info;
 	/* socket initialization */
 	s->ss_entry = socket->ops;
@@ -373,8 +429,9 @@
 }
 
 
-static void pcmcia_remove_socket(struct pcmcia_socket *socket)
+static void pcmcia_remove_socket(struct class_device *class_dev)
 {
+	struct pcmcia_socket *socket = class_get_devdata(class_dev);
 	client_t *client;
 	socket_info_t *s;
 
@@ -409,85 +466,78 @@
 /**
  * pcmcia_register_socket - add a new pcmcia socket device
  */
-int pcmcia_register_socket(struct class_device *class_dev)
+unsigned int pcmcia_register_socket(struct pcmcia_socket *socket)
 {
-	struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
-	socket_info_t *s_info;
-	unsigned int i, ret;
-	struct pcmcia_socket *socket;
-
-	if (!cls_d)
+	if (!socket || !socket->ops || !socket->dev.dev)
 		return -EINVAL;
 
-	DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", cls_d->ops);
+	DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ops);
 
-	s_info = kmalloc(cls_d->nsock * sizeof(struct socket_info_t), GFP_KERNEL);
-	if (!s_info)
+	socket->s_info = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+	if (!socket->s_info)
 		return -ENOMEM;
-	memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
+	memset(socket->s_info, 0, sizeof(socket_info_t));
 
-	cls_d->s_info = s_info;
-	ret = 0;
+	/* try to obtain a socket number [yes, it gets ugly if we
+	 * register more than 2^sizeof(unsigned int) pcmcia 
+	 * sockets... but the socket number is deprecated 
+	 * anyways, so I don't care] */
+	down(&pcmcia_socket_list_lock);
+	if (list_empty(&pcmcia_socket_list))
+		socket->socket_no = 0;
+	else {
+		unsigned int found, i = 1;
+		struct pcmcia_socket *tmp;
+		do {
+			found = 1;
+			list_for_each_entry(tmp, &pcmcia_socket_list, socket_list) {
+				if (tmp->socket_no == i)
+					found = 0;
+			}
+			i++;
+		} while (!found);
+		socket->socket_no = i - 1;
+	}
+	list_add_tail(&socket->socket_list, &pcmcia_socket_list);
+	up(&pcmcia_socket_list_lock);
 
-	/* socket initialization */
-	for (i = 0; i < cls_d->nsock; i++) {
-		socket = kmalloc(sizeof(struct pcmcia_socket), GFP_KERNEL);
-		if (!socket)
-			return -ENOMEM;
-		memset(socket, 0, sizeof(struct pcmcia_socket));
-
-		socket->s_info = (void *) &s_info[i];
-		socket->socket_no = i + cls_d->sock_offset;
-		socket->ops = cls_d->ops;
+	/* set proper values in socket->dev */
+	socket->dev.class_data = socket;
+	socket->dev.class = &pcmcia_socket_class;
+	snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u\n", socket->socket_no);
 
+	if (class_device_register(&socket->dev)) {
+		kfree(socket->s_info);
 		down(&pcmcia_socket_list_lock);
-		list_add_tail(&socket->socket_list, &pcmcia_socket_list);
-		up(&pcmcia_socket_list_lock);
-
-		pcmcia_add_socket(socket);
+		list_del(&socket->socket_list);
+ 		up(&pcmcia_socket_list_lock);
+		return -EINVAL;
 	}
-	return ret;
+
+	return 0;
 } /* pcmcia_register_socket */
+EXPORT_SYMBOL(pcmcia_register_socket);
 
 
 /**
- * pcmcia_unregister_socket - remove a pcmcia socket device
+ * pcmcia_unregister_socket - unregister a socket from the core
  */
-void pcmcia_unregister_socket(struct class_device *class_dev)
+void pcmcia_unregister_socket(struct pcmcia_socket *socket)
 {
- 	struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
-	struct pcmcia_socket *socket;
-	unsigned int i;
-	socket_info_t *s;
-
-	if (!cls_d)
+	if (!socket)
 		return;
 
-	s = (socket_info_t *) cls_d->s_info;
-
-	for (i = 0; i < cls_d->nsock; i++) {
-		down(&pcmcia_socket_list_lock);
-		list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-			if (socket->s_info == s)
-				goto found;
-		}
-		up(&pcmcia_socket_list_lock);
-		continue;
-
-	found:
-		up(&pcmcia_socket_list_lock);
+	DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ops);
 
+	class_device_unregister(&socket->dev);
 
-		pcmcia_remove_socket(socket);
-
-		down(&pcmcia_socket_list_lock);
-		list_del(&socket->socket_list);
-		up(&pcmcia_socket_list_lock);
+	down(&pcmcia_socket_list_lock);
+	list_del(&socket->socket_list);
+	up(&pcmcia_socket_list_lock);
 
-		s++;
-	}
-	kfree(cls_d->s_info);
-} /* pcmcia_unregister_socket */
+	kfree(socket->s_info);
+}
+EXPORT_SYMBOL(pcmcia_unregister_socket);
 
 
 /*======================================================================
@@ -851,67 +901,7 @@
 	wake_up(&s->thread_wait);
 } /* parse_events */
 
-/*======================================================================
-
-    Another event handler, for power management events.
-
-    This does not comply with the latest PC Card spec for handling
-    power management events.
-    
-======================================================================*/
-
-void pcmcia_suspend_socket (socket_info_t *skt)
-{
-	down(&skt->skt_sem);
-	socket_suspend(skt);
-	up(&skt->skt_sem);
-}
-
-void pcmcia_resume_socket (socket_info_t *skt)
-{
-	down(&skt->skt_sem);
-	socket_resume(skt);
-	up(&skt->skt_sem);
-}
-
-
-int pcmcia_socket_dev_suspend(struct pcmcia_socket_class_data *cls_d, u32 state, u32 level)
-{
-	socket_info_t *s;
-	int i;
-
-	if ((!cls_d) || (level != SUSPEND_SAVE_STATE))
-		return 0;
-
-	s = (socket_info_t *) cls_d->s_info;
-
-	for (i = 0; i < cls_d->nsock; i++) {
-		pcmcia_suspend_socket(s);
-		s++;
-	}
 
-	return 0;
-}
-EXPORT_SYMBOL(pcmcia_socket_dev_suspend);
-
-int pcmcia_socket_dev_resume(struct pcmcia_socket_class_data *cls_d, u32 level)
-{
-	socket_info_t *s;
-	int i;
-
-	if ((!cls_d) || (level != RESUME_RESTORE_STATE))
-		return 0;
-
-	s = (socket_info_t *) cls_d->s_info;
-
-	for (i = 0; i < cls_d->nsock; i++) {
-		pcmcia_resume_socket(s);
-		s++;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(pcmcia_socket_dev_resume);
 
 
 /*======================================================================
@@ -2571,11 +2561,6 @@
 EXPORT_SYMBOL(proc_pccard);
 #endif
 
-EXPORT_SYMBOL(pcmcia_register_socket);
-EXPORT_SYMBOL(pcmcia_unregister_socket);
-EXPORT_SYMBOL(pcmcia_suspend_socket);
-EXPORT_SYMBOL(pcmcia_resume_socket);
-
 struct class pcmcia_socket_class = {
 	.name = "pcmcia_socket",
 };
@@ -2583,8 +2568,8 @@
 
 static struct class_interface pcmcia_socket = {
 	.class = &pcmcia_socket_class,
-	.add = &pcmcia_register_socket,
-	.remove = &pcmcia_unregister_socket,
+	.add = &pcmcia_add_socket,
+	.remove = &pcmcia_remove_socket,
 };
 
 
diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2003-05-17 18:27:21.000000000 +0200
+++ linux/drivers/pcmcia/ds.c	2003-05-17 21:05:08.000000000 +0200
@@ -883,13 +883,19 @@
 
 /*====================================================================*/
 
-static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr)
+static int pcmcia_bus_add_socket(struct class_device *class_dev)
 {
+	struct pcmcia_socket *socket = class_dev->class_data;
+	struct device *dev;
 	client_reg_t client_reg;
 	bind_req_t bind;
-	struct pcmcia_bus_socket *s, *tmp_s;
+	struct pcmcia_bus_socket *s;
 	int ret;
-	int i;
+
+	if (!socket)
+		return -EINVAL;
+
+	dev = socket->dev.dev;
 
 	s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL);
 	if(!s)
@@ -906,19 +912,7 @@
 	init_waitqueue_head(&s->queue);
 	init_waitqueue_head(&s->request);
 
-	/* find the lowest, unused socket no. Please note that this is a
-	 * temporary workaround until "struct pcmcia_socket" is introduced
-	 * into cs.c which will include this number, and which will be
-	 * accessible to ds.c directly */
-	i = 0;
- next_try:
-	list_for_each_entry(tmp_s, &bus_socket_list, socket_list) {
-		if (tmp_s->socket_no == i) {
-			i++;
-			goto next_try;
-		}
-	}
-	s->socket_no = i;
+	s->socket_no = socket->socket_no;
 
 	/* initialize data */
 	s->socket_dev = dev;
@@ -952,44 +946,26 @@
 		return -EINVAL;
 	}
 
+	down_write(&bus_socket_list_rwsem);
 	list_add(&s->socket_list, &bus_socket_list);
+	up_write(&bus_socket_list_rwsem);
 
 	return 0;
 }
 
 
-static int pcmcia_bus_add_socket_dev(struct class_device *class_dev)
+static void pcmcia_bus_remove_socket(struct class_device *class_dev)
 {
-	struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
-	unsigned int i;
-	unsigned int ret = 0;
-
-	if (!cls_d)
-		return -ENODEV;
-
-	down_write(&bus_socket_list_rwsem);
-        for (i = 0; i < cls_d->nsock; i++)
-		ret += pcmcia_bus_add_socket(class_dev->dev, i);
-	up_write(&bus_socket_list_rwsem);
-
-	return ret;
-}
-
-static void pcmcia_bus_remove_socket_dev(struct class_device *class_dev)
-{
-	struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
+	struct pcmcia_socket *socket = class_dev->class_data;
 	struct list_head *list_loop;
 	struct list_head *tmp_storage;
 
-	if (!cls_d)
-		return;
-
 	flush_scheduled_work();
 
 	down_write(&bus_socket_list_rwsem);
 	list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) {
 		struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list);
-		if (bus_sock->socket_dev == class_dev->dev) {
+		if (bus_sock->socket_no == socket->socket_no) {
 			pcmcia_deregister_client(bus_sock->handle);
 			list_del(&bus_sock->socket_list);
 			kfree(bus_sock);
@@ -1003,8 +979,8 @@
 /* the pcmcia_bus_interface is used to handle pcmcia socket devices */
 static struct class_interface pcmcia_bus_interface = {
 	.class = &pcmcia_socket_class,
-	.add = &pcmcia_bus_add_socket_dev,
-	.remove = &pcmcia_bus_remove_socket_dev,
+	.add = &pcmcia_bus_add_socket,
+	.remove = &pcmcia_bus_remove_socket,
 };
 
 
diff -ruN linux-original/drivers/pcmcia/i82092.c linux/drivers/pcmcia/i82092.c
--- linux-original/drivers/pcmcia/i82092.c	2003-05-17 18:27:21.000000000 +0200
+++ linux/drivers/pcmcia/i82092.c	2003-05-17 21:05:08.000000000 +0200
@@ -44,14 +44,12 @@
 
 static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state)
 {
-	struct pcmcia_socket_class_data *cls_d = pci_get_drvdata(dev);
-	return pcmcia_socket_dev_suspend(cls_d, state, 0);
+	return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
 }
 
 static int i82092aa_socket_resume (struct pci_dev *dev)
 {
-	struct pcmcia_socket_class_data *cls_d = pci_get_drvdata(dev);
-	return pcmcia_socket_dev_resume(cls_d, RESUME_RESTORE_STATE);
+	return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
 }
 
 static struct pci_driver i82092aa_pci_drv = {
@@ -94,7 +92,8 @@
 	void	(*handler)(void *info, u_int events); 
 				/* callback to the driver of the card */
 	void	*info;		/* to be passed to the handler */
-	
+
+	struct pcmcia_socket socket;	
 	struct pci_dev *dev;	/* The PCI device for the socket */
 };
 
@@ -107,7 +106,6 @@
 {
 	unsigned char configbyte;
 	int i, ret;
-	struct pcmcia_socket_class_data *cls_d;
 	
 	enter("i82092aa_pci_probe");
 	
@@ -166,26 +164,26 @@
 		goto err_out_free_res;
 	}
 
-	
-	cls_d = kmalloc(sizeof(*cls_d), GFP_KERNEL);
-	if (!cls_d) {
-		printk(KERN_ERR "i82092aa: kmalloc failed\n");
-		goto err_out_free_irq;
-	}
-	memset(cls_d, 0, sizeof(*cls_d));
-	cls_d->nsock = socket_count;
-	cls_d->ops = &i82092aa_operations;
-	pci_set_drvdata(dev, &cls_d);
-	cls_d->class_dev.class = &pcmcia_socket_class;
-	cls_d->class_dev.dev = &dev->dev;
-	strncpy(cls_d->class_dev.class_id, dev->dev.name, BUS_ID_SIZE);
-	class_set_devdata(&cls_d->class_dev, cls_d);
-	class_device_register(&cls_d->class_dev);
+	pci_set_drvdata(dev, &sockets[i].socket);
+
+	for (i = 0; i<socket_count; i++) {
+		sockets[i].socket.dev.dev = &dev->dev;
+		sockets[i].socket.ops = &i82092aa_operations;
+		ret = pcmcia_register_socket(&sockets[i].socket);
+		if (ret) {
+			goto err_out_free_sockets;
+		}
+	}
 
 	leave("i82092aa_pci_probe");
 	return 0;
 
-err_out_free_irq:
+err_out_free_sockets:
+	if (i) {
+		for (i--;i>=0;i--) {
+			pcmcia_unregister_socket(&sockets[i].socket);
+		}
+	}
 	free_irq(dev->irq, i82092aa_interrupt);
 err_out_free_res:
 	release_region(pci_resource_start(dev, 0), 2);
@@ -196,16 +194,14 @@
 
 static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
 {
-	struct pcmcia_socket_class_data *cls_d = pci_get_drvdata(dev);
+	struct pcmcia_socket *socket = pci_get_drvdata(dev);
 
 	enter("i82092aa_pci_remove");
 	
 	free_irq(dev->irq, i82092aa_interrupt);
 
-	if (cls_d) {
-		class_device_unregister(&cls_d->class_dev);
-		kfree(cls_d);
-	}
+	if (socket)
+		pcmcia_unregister_socket(socket);
 
 	leave("i82092aa_pci_remove");
 }
diff -ruN linux-original/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- linux-original/drivers/pcmcia/i82365.c	2003-05-17 18:27:21.000000000 +0200
+++ linux/drivers/pcmcia/i82365.c	2003-05-17 21:05:08.000000000 +0200
@@ -166,6 +166,7 @@
 
 typedef struct socket_info_t {
     u_short		type, flags;
+    struct pcmcia_socket	socket;
     socket_cap_t	cap;
     ioaddr_t		ioaddr;
     u_short		psock;
@@ -1502,15 +1503,11 @@
 
 /*====================================================================*/
 
-static struct pcmcia_socket_class_data i82365_data = {
-	.ops = &pcic_operations,
-};
-
 static struct device_driver i82365_driver = {
 	.name = "i82365",
 	.bus = &platform_bus_type,
-/*	.suspend = pcmcia_socket_dev_suspend,	FIXME?	*/
-/*	.resume = pcmcia_socket_dev_resume,	FIXME?	*/
+	.suspend = pcmcia_socket_dev_suspend,
+	.resume = pcmcia_socket_dev_resume,
 };
 
 static struct platform_device i82365_device = {
@@ -1521,13 +1518,11 @@
 	},
 };
 
-static struct class_device i82365_class_data = {
-	.class = &pcmcia_socket_class,
-};
-
 static int __init init_i82365(void)
 {
     servinfo_t serv;
+    int i, ret;
+
     pcmcia_get_card_services_info(&serv);
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "i82365: Card Services release "
@@ -1551,19 +1546,25 @@
 	return -ENODEV;
     }
 
+    platform_device_register(&i82365_device);
+
     /* Set up interrupt handler(s) */
 #ifdef CONFIG_ISA
     if (grab_irq != 0)
 	request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
 #endif
-    
-    i82365_data.nsock = sockets;
-    i82365_class_data.dev = &i82365_device.dev;
-    i82365_class_data.class_data = &i82365_data;
-    strncpy(i82365_class_data.class_id, "i82365", BUS_ID_SIZE);
-    
-    platform_device_register(&i82365_device);
-    class_device_register(&i82365_class_data);
+
+    /* register sockets with the pcmcia core */
+    for (i = 0; i < sockets; i++) {
+	    socket[i].socket.dev.dev = &i82365_device.dev;
+	    socket[i].socket.ops = &pcic_operations;
+	    ret = pcmcia_register_socket(&socket[i].socket);	    
+	    if (ret && i--) {
+		    for (; i>= 0; i--)
+			    pcmcia_unregister_socket(&socket[i].socket);
+		    break;
+	    }
+    }
 
     /* Finally, schedule a polling interrupt */
     if (poll_interval != 0) {
@@ -1581,10 +1582,12 @@
 static void __exit exit_i82365(void)
 {
     int i;
+    for (i = 0; i < sockets; i++) {
+	    pcmcia_unregister_socket(&socket[i].socket);
 #ifdef CONFIG_PROC_FS
-    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
+	    pcic_proc_remove(i);
 #endif
-    class_device_unregister(&i82365_class_data);
+    }
     platform_device_unregister(&i82365_device);
     if (poll_interval != 0)
 	del_timer_sync(&poll_timer);
diff -ruN linux-original/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- linux-original/drivers/pcmcia/pci_socket.c	2003-05-17 18:27:21.000000000 +0200
+++ linux/drivers/pcmcia/pci_socket.c	2003-05-17 21:05:08.000000000 +0200
@@ -148,15 +148,10 @@
 	
 	memset(socket, 0, sizeof(*socket));
 
-	/* prepare class_data */
-	socket->cls_d.sock_offset = nr;
-	socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses
-			     this yet */
-	socket->cls_d.ops = &pci_socket_operations;
-	socket->cls_d.class_dev.class = &pcmcia_socket_class;
-	socket->cls_d.class_dev.dev = &dev->dev;
-	strncpy(socket->cls_d.class_dev.class_id, dev->dev.bus_id, BUS_ID_SIZE);
-	class_set_devdata(&socket->cls_d.class_dev, &socket->cls_d);
+	/* prepare pcmcia_socket */
+	socket->socket.ops = &pci_socket_operations;
+	socket->socket.dev.dev = &dev->dev;
+	socket->socket.driver_data = socket;
 
 	/* prepare pci_socket_t */
 	socket->dev = dev;
@@ -168,7 +163,7 @@
 		socket->dev = NULL;
 		pci_set_drvdata(dev, NULL);
 	} else {
-		class_device_register(&socket->cls_d.class_dev);
+		pcmcia_register_socket(&socket->socket);
 	}
 	return err;
 }
@@ -198,23 +193,20 @@
 	/* note: we are already unregistered from the cs core */
 	if (socket->op && socket->op->close)
 		socket->op->close(socket);
-	class_device_unregister(&socket->cls_d.class_dev);
+	pcmcia_unregister_socket(&socket->socket);
 	pci_set_drvdata(dev, NULL);
 }
 
 static int cardbus_suspend (struct pci_dev *dev, u32 state)
 {
-	pci_socket_t *socket = pci_get_drvdata(dev);
-	return pcmcia_socket_dev_suspend(&socket->cls_d, state, 0);
+	return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
 }
 
 static int cardbus_resume (struct pci_dev *dev)
 {
-	pci_socket_t *socket = pci_get_drvdata(dev);
-	return pcmcia_socket_dev_resume(&socket->cls_d, RESUME_RESTORE_STATE);
+	return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
 }
 
-
 static struct pci_device_id cardbus_table [] __devinitdata = { {
 	.class		= PCI_CLASS_BRIDGE_CARDBUS << 8,
 	.class_mask	= ~0,
diff -ruN linux-original/drivers/pcmcia/pci_socket.h linux/drivers/pcmcia/pci_socket.h
--- linux-original/drivers/pcmcia/pci_socket.h	2003-05-17 18:27:21.000000000 +0200
+++ linux/drivers/pcmcia/pci_socket.h	2003-05-17 21:05:08.000000000 +0200
@@ -23,7 +23,7 @@
 	struct work_struct tq_task;
 	struct timer_list poll_timer;
 
-	struct pcmcia_socket_class_data cls_d;
+	struct pcmcia_socket socket;
 	/* A few words of private data for the low-level driver.. */
 	unsigned int private[8];
 } pci_socket_t;
diff -ruN linux-original/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c
--- linux-original/drivers/pcmcia/tcic.c	2003-05-17 18:27:21.000000000 +0200
+++ linux/drivers/pcmcia/tcic.c	2003-05-17 21:05:08.000000000 +0200
@@ -121,6 +121,7 @@
     void	*info;
     u_char	last_sstat;
     u_char	id;
+    struct pcmcia_socket socket;
 } socket_info_t;
 
 static struct timer_list poll_timer;
@@ -372,15 +373,11 @@
 
 /*====================================================================*/
 
-static struct pcmcia_socket_class_data tcic_data = {
-	.ops = &tcic_operations,
-};
-
 static struct device_driver tcic_driver = {
 	.name = "tcic-pcmcia",
 	.bus = &platform_bus_type,
-/*	.suspend = pcmcia_socket_dev_suspend,	FIXME?	*/
-/*	.resume = pcmcia_socket_dev_resume,	FIXME?	*/
+	.suspend = pcmcia_socket_dev_suspend,
+	.resume = pcmcia_socket_dev_resume,
 };
 
 static struct platform_device tcic_device = {
@@ -391,13 +388,9 @@
 	},
 };
 
-static struct class_device tcic_class_data = {
-	.class = &pcmcia_socket_class,
-};
-
 static int __init init_tcic(void)
 {
-    int i, sock;
+    int i, sock, ret = 0;
     u_int mask, scan;
     servinfo_t serv;
 
@@ -524,15 +517,18 @@
     /* jump start interrupt handler, if needed */
     tcic_interrupt(0, NULL, NULL);
 
-    tcic_data.nsock = sockets;
-    tcic_class_data.dev = &tcic_device.dev;
-    tcic_class_data.class_data = &tcic_data;
-    strncpy(tcic_class_data.class_id, "tcic-pcmcia", BUS_ID_SIZE);
-    
     platform_device_register(&tcic_device);
-    class_device_register(&tcic_class_data);
 
-    return 0;
+
+    for (i = 0; i < sockets; i++) {
+	    socket_table[i].socket.ops = &tcic_operations;
+	    socket_table[i].socket.dev.dev = &tcic_device.dev;
+	    ret = pcmcia_register_socket(&socket_table[i].socket);	    
+	    if (ret && i)
+		    pcmcia_unregister_socket(&socket_table[0].socket);
+    }
+    
+    return ret;
     
 } /* init_tcic */
 
@@ -540,13 +536,19 @@
 
 static void __exit exit_tcic(void)
 {
+    int i;
+
     del_timer_sync(&poll_timer);
     if (cs_irq != 0) {
 	tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
 	free_irq(cs_irq, tcic_interrupt);
     }
     release_region(tcic_base, 16);
-    class_device_unregister(&tcic_class_data);
+
+    for (i = 0; i < sockets; i++) {
+	    pcmcia_unregister_socket(&socket_table[i].socket);	    
+    }
+
     platform_device_unregister(&tcic_device);
     driver_unregister(&tcic_driver);
 } /* exit_tcic */
diff -ruN linux-original/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- linux-original/include/pcmcia/ss.h	2003-05-17 21:19:17.000000000 +0200
+++ linux/include/pcmcia/ss.h	2003-05-17 21:05:08.000000000 +0200
@@ -144,26 +144,26 @@
 
 struct pcmcia_socket {
 	struct list_head		socket_list;
+	struct class_device		dev;
 	struct pccard_operations	*ops;
 
+	/* data internal to the socket driver */
+	void				*driver_data;
+
 	/* deprecated */
 	unsigned int			socket_no;
 	void				*s_info; /* socket_info_t */
 };
 
-struct pcmcia_socket_class_data {
-	unsigned int nsock;			/* number of sockets */
-	unsigned int sock_offset;		/* socket # (which is
-	 * returned to driver) = sock_offset + (0, 1, .. , (nsock-1) */
-	struct pccard_operations *ops;		/* see above */
-	void *s_info;				/* socket_info_t */
-	struct class_device class_dev;		/* generic class structure */
-};
+
+extern unsigned int pcmcia_register_socket(struct pcmcia_socket *socket);
+extern void pcmcia_unregister_socket(struct pcmcia_socket *socket);
 
 extern struct class pcmcia_socket_class;
 
+
 /* socket drivers are expected to use these callbacks in their .drv struct */
-extern int pcmcia_socket_dev_suspend(struct pcmcia_socket_class_data *cls_d, u32 state, u32 level);
-extern int pcmcia_socket_dev_resume(struct pcmcia_socket_class_data *cls_d, u32 level);
+extern int pcmcia_socket_dev_suspend(struct device *dev, u32 state, u32 level);
+extern int pcmcia_socket_dev_resume(struct device *dev, u32 level);
 
 #endif /* _LINUX_SS_H */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-pcmcia/attachments/20030517/b5a47052/attachment.bin


More information about the linux-pcmcia mailing list