Subject: [PCMCIA] pcmcia-18b: error on leftover devices
From: Dominik Brodowski <[email-masked]>
To: [email-masked]
Date: Fri, 29 Oct 2004 00:44:07 +0200

13-bug_on_dev_list_not_null

All in-kernel PCMCIA devices do unregister their client in their respective
->detach() function after a REMOVAL event. So, AFAICS, the dev_list iteration
should always be false.

14-bug_on_list

BUG if the socket's list of clients is not empty on shutdown and/or
removal

15-move_client

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 <[email-masked]>

diff -ruN linux-original/drivers/bluetooth/bluecard_cs.c linux/drivers/bluetooth/bluecard_cs.c
--- linux-original/drivers/bluetooth/bluecard_cs.c	2004-10-28 21:12:51.000000000 +0200
+++ linux/drivers/bluetooth/bluecard_cs.c	2004-10-28 21:53:37.283126848 +0200
@@ -1115,10 +1115,7 @@
 static void __exit exit_bluecard_cs(void)
 {
 	pcmcia_unregister_driver(&bluecard_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		bluecard_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_bluecard_cs);
diff -ruN linux-original/drivers/bluetooth/bt3c_cs.c linux/drivers/bluetooth/bt3c_cs.c
--- linux-original/drivers/bluetooth/bt3c_cs.c	2004-10-28 21:12:51.000000000 +0200
+++ linux/drivers/bluetooth/bt3c_cs.c	2004-10-28 21:53:37.284126696 +0200
@@ -969,10 +969,7 @@
 static void __exit exit_bt3c_cs(void)
 {
 	pcmcia_unregister_driver(&bt3c_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		bt3c_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_bt3c_cs);
diff -ruN linux-original/drivers/bluetooth/btuart_cs.c linux/drivers/bluetooth/btuart_cs.c
--- linux-original/drivers/bluetooth/btuart_cs.c	2004-10-28 21:12:51.000000000 +0200
+++ linux/drivers/bluetooth/btuart_cs.c	2004-10-28 21:53:37.285126544 +0200
@@ -886,10 +886,7 @@
 static void __exit exit_btuart_cs(void)
 {
 	pcmcia_unregister_driver(&btuart_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		btuart_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_btuart_cs);
diff -ruN linux-original/drivers/bluetooth/dtl1_cs.c linux/drivers/bluetooth/dtl1_cs.c
--- linux-original/drivers/bluetooth/dtl1_cs.c	2004-10-28 21:12:51.000000000 +0200
+++ linux/drivers/bluetooth/dtl1_cs.c	2004-10-28 21:53:37.286126392 +0200
@@ -838,10 +838,7 @@
 static void __exit exit_dtl1_cs(void)
 {
 	pcmcia_unregister_driver(&dtl1_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		dtl1_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_dtl1_cs);
diff -ruN linux-original/drivers/char/pcmcia/synclink_cs.c linux/drivers/char/pcmcia/synclink_cs.c
--- linux-original/drivers/char/pcmcia/synclink_cs.c	2004-10-28 21:12:45.000000000 +0200
+++ linux/drivers/char/pcmcia/synclink_cs.c	2004-10-28 21:53:37.289125936 +0200
@@ -3147,13 +3147,7 @@
 	}
 
 	pcmcia_unregister_driver(&mgslpc_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG)
-			mgslpc_release((u_long)dev_list);
-		mgslpc_detach(dev_list);
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 static int __init synclink_cs_init(void)
diff -ruN linux-original/drivers/ide/legacy/ide-cs.c linux/drivers/ide/legacy/ide-cs.c
--- linux-original/drivers/ide/legacy/ide-cs.c	2004-10-28 21:12:47.000000000 +0200
+++ linux/drivers/ide/legacy/ide-cs.c	2004-10-28 21:53:37.290125784 +0200
@@ -485,8 +485,7 @@
 static void __exit exit_ide_cs(void)
 {
 	pcmcia_unregister_driver(&ide_cs_driver);
-	while (dev_list != NULL)
-		ide_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_ide_cs);
diff -ruN linux-original/drivers/isdn/hardware/avm/avm_cs.c linux/drivers/isdn/hardware/avm/avm_cs.c
--- linux-original/drivers/isdn/hardware/avm/avm_cs.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/isdn/hardware/avm/avm_cs.c	2004-10-28 21:53:37.291125632 +0200
@@ -521,13 +521,7 @@
 static void __exit avmcs_exit(void)
 {
 	pcmcia_unregister_driver(&avmcs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG)
-			avmcs_release(dev_list);
-		avmcs_detach(dev_list);
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(avmcs_init);
diff -ruN linux-original/drivers/isdn/hisax/avma1_cs.c linux/drivers/isdn/hisax/avma1_cs.c
--- linux-original/drivers/isdn/hisax/avma1_cs.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/isdn/hisax/avma1_cs.c	2004-10-28 21:53:37.292125480 +0200
@@ -531,13 +531,7 @@
 static void __exit exit_avma1_cs(void)
 {
 	pcmcia_unregister_driver(&avma1cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG)
-			avma1cs_release(dev_list);
-		avma1cs_detach(dev_list);
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_avma1_cs);
diff -ruN linux-original/drivers/isdn/hisax/elsa_cs.c linux/drivers/isdn/hisax/elsa_cs.c
--- linux-original/drivers/isdn/hisax/elsa_cs.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/isdn/hisax/elsa_cs.c	2004-10-28 21:53:37.292125480 +0200
@@ -541,10 +541,7 @@
 static void __exit exit_elsa_cs(void)
 {
 	pcmcia_unregister_driver(&elsa_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		elsa_cs_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_elsa_cs);
diff -ruN linux-original/drivers/isdn/hisax/sedlbauer_cs.c linux/drivers/isdn/hisax/sedlbauer_cs.c
--- linux-original/drivers/isdn/hisax/sedlbauer_cs.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/isdn/hisax/sedlbauer_cs.c	2004-10-28 21:53:37.293125328 +0200
@@ -648,13 +648,7 @@
 static void __exit exit_sedlbauer_cs(void)
 {
 	pcmcia_unregister_driver(&sedlbauer_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG)
-			sedlbauer_release(dev_list);
-		sedlbauer_detach(dev_list);
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_sedlbauer_cs);
diff -ruN linux-original/drivers/isdn/hisax/teles_cs.c linux/drivers/isdn/hisax/teles_cs.c
--- linux-original/drivers/isdn/hisax/teles_cs.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/isdn/hisax/teles_cs.c	2004-10-28 21:53:37.294125176 +0200
@@ -522,10 +522,7 @@
 static void __exit exit_teles_cs(void)
 {
 	pcmcia_unregister_driver(&teles_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		teles_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_teles_cs);
diff -ruN linux-original/drivers/mtd/maps/pcmciamtd.c linux/drivers/mtd/maps/pcmciamtd.c
--- linux-original/drivers/mtd/maps/pcmciamtd.c	2004-10-28 21:12:51.000000000 +0200
+++ linux/drivers/mtd/maps/pcmciamtd.c	2004-10-28 21:53:37.295125024 +0200
@@ -854,35 +854,7 @@
 {
 	DEBUG(1, DRIVER_DESC " unloading");
 	pcmcia_unregister_driver(&pcmciamtd_driver);
-
-	while(dev_list) {
-		dev_link_t *link = dev_list;
-
-		dev_list = link->next;
-		if (link) {
-			struct pcmciamtd_dev *dev = link->priv;
-			
- 			if(dev) {
-				if(link->state & DEV_PRESENT) {
-					if (!(link->state & DEV_STALE_LINK)) {
-						pcmciamtd_detach(link);
-					}
-					link->state &= ~DEV_PRESENT;
-					if(dev->mtd_info) {
-						del_mtd_device(dev->mtd_info);
-						info("mtd%d: Removed",
-						     dev->mtd_info->index);
-					}
-				}
-				if(dev->mtd_info) {
-					DEBUG(2, "Destroying map for mtd%d",
-					      dev->mtd_info->index);
-					map_destroy(dev->mtd_info);
-				}
-				kfree(dev);
-			}
-		}
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_pcmciamtd);
diff -ruN linux-original/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- linux-original/drivers/net/pcmcia/3c574_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/3c574_cs.c	2004-10-28 21:53:37.296124872 +0200
@@ -1308,8 +1308,7 @@
 static void __exit exit_tc574(void)
 {
 	pcmcia_unregister_driver(&tc574_driver);
-	while (dev_list != NULL)
-		tc574_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_tc574);
diff -ruN linux-original/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- linux-original/drivers/net/pcmcia/3c589_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/3c589_cs.c	2004-10-28 21:53:37.297124720 +0200
@@ -1083,8 +1083,7 @@
 static void __exit exit_tc589(void)
 {
 	pcmcia_unregister_driver(&tc589_driver);
-	while (dev_list != NULL)
-		tc589_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_tc589);
diff -ruN linux-original/drivers/net/pcmcia/axnet_cs.c linux/drivers/net/pcmcia/axnet_cs.c
--- linux-original/drivers/net/pcmcia/axnet_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/axnet_cs.c	2004-10-28 21:53:37.298124568 +0200
@@ -877,8 +877,7 @@
 static void __exit exit_axnet_cs(void)
 {
 	pcmcia_unregister_driver(&axnet_cs_driver);
-	while (dev_list != NULL)
-		axnet_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_axnet_cs);
diff -ruN linux-original/drivers/net/pcmcia/com20020_cs.c linux/drivers/net/pcmcia/com20020_cs.c
--- linux-original/drivers/net/pcmcia/com20020_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/com20020_cs.c	2004-10-28 21:53:37.308123048 +0200
@@ -513,8 +513,7 @@
 static void __exit exit_com20020_cs(void)
 {
 	pcmcia_unregister_driver(&com20020_cs_driver);
-	while (dev_list != NULL)
-		com20020_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_com20020_cs);
diff -ruN linux-original/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-original/drivers/net/pcmcia/fmvj18x_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	2004-10-28 21:53:37.310122744 +0200
@@ -792,8 +792,7 @@
 static void __exit exit_fmvj18x_cs(void)
 {
 	pcmcia_unregister_driver(&fmvj18x_cs_driver);
-	while (dev_list != NULL)
-		fmvj18x_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_fmvj18x_cs);
diff -ruN linux-original/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- linux-original/drivers/net/pcmcia/ibmtr_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	2004-10-28 21:53:37.310122744 +0200
@@ -538,8 +538,7 @@
 static void __exit exit_ibmtr_cs(void)
 {
 	pcmcia_unregister_driver(&ibmtr_cs_driver);
-	while (dev_list != NULL)
-		ibmtr_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_ibmtr_cs);
diff -ruN linux-original/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- linux-original/drivers/net/pcmcia/nmclan_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/nmclan_cs.c	2004-10-28 21:53:37.312122440 +0200
@@ -1702,8 +1702,7 @@
 static void __exit exit_nmclan_cs(void)
 {
 	pcmcia_unregister_driver(&nmclan_cs_driver);
-	while (dev_list != NULL)
-		nmclan_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_nmclan_cs);
diff -ruN linux-original/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- linux-original/drivers/net/pcmcia/pcnet_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/pcnet_cs.c	2004-10-28 21:53:37.320121224 +0200
@@ -1659,8 +1659,7 @@
 {
     DEBUG(0, "pcnet_cs: unloading\n");
     pcmcia_unregister_driver(&pcnet_driver);
-    while (dev_list != NULL)
-	pcnet_detach(dev_list);
+    BUG_ON(dev_list != NULL);
 }
 
 module_init(init_pcnet_cs);
diff -ruN linux-original/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- linux-original/drivers/net/pcmcia/smc91c92_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	2004-10-28 21:53:37.322120920 +0200
@@ -2263,8 +2263,7 @@
 static void __exit exit_smc91c92_cs(void)
 {
 	pcmcia_unregister_driver(&smc91c92_cs_driver);
-	while (dev_list != NULL)
-		smc91c92_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_smc91c92_cs);
diff -ruN linux-original/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- linux-original/drivers/net/pcmcia/xirc2ps_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	2004-10-28 21:53:37.332119400 +0200
@@ -2016,9 +2016,7 @@
 exit_xirc2ps_cs(void)
 {
 	pcmcia_unregister_driver(&xirc2ps_cs_driver);
-
-	while (dev_list)
-		xirc2ps_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_xirc2ps_cs);
diff -ruN linux-original/drivers/net/wireless/airo_cs.c linux/drivers/net/wireless/airo_cs.c
--- linux-original/drivers/net/wireless/airo_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/wireless/airo_cs.c	2004-10-28 21:53:37.333119248 +0200
@@ -592,13 +592,7 @@
 static void airo_cs_cleanup(void)
 {
 	pcmcia_unregister_driver(&airo_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG)
-			airo_release(dev_list);
-		airo_detach(dev_list);
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 /*
diff -ruN linux-original/drivers/net/wireless/atmel_cs.c linux/drivers/net/wireless/atmel_cs.c
--- linux-original/drivers/net/wireless/atmel_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/wireless/atmel_cs.c	2004-10-28 21:53:37.334119096 +0200
@@ -696,13 +696,7 @@
 static void atmel_cs_cleanup(void)
 {
         pcmcia_unregister_driver(&atmel_driver);
-
-        /* XXX: this really needs to move into generic code.. */
-        while (dev_list != NULL) {
-                if (dev_list->state & DEV_CONFIG)
-                        atmel_release(dev_list);
-                atmel_detach(dev_list);
-        }
+	BUG_ON(dev_list != NULL);
 }
 
 /*
diff -ruN linux-original/drivers/net/wireless/netwave_cs.c linux/drivers/net/wireless/netwave_cs.c
--- linux-original/drivers/net/wireless/netwave_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/wireless/netwave_cs.c	2004-10-28 21:53:37.335118944 +0200
@@ -1692,9 +1692,7 @@
 static void __exit exit_netwave_cs(void)
 {
 	pcmcia_unregister_driver(&netwave_driver);
-
-	if (dev_list != NULL)	/* Critical situation */
-		printk("netwave_cs: devices remaining when removing module\n");
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_netwave_cs);
diff -ruN linux-original/drivers/net/wireless/orinoco_cs.c linux/drivers/net/wireless/orinoco_cs.c
--- linux-original/drivers/net/wireless/orinoco_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/wireless/orinoco_cs.c	2004-10-28 21:53:37.336118792 +0200
@@ -653,14 +653,7 @@
 exit_orinoco_cs(void)
 {
 	pcmcia_unregister_driver(&orinoco_driver);
-
-	if (dev_list)
-		DEBUG(0, PFX "Removing leftover devices.\n");
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG)
-			orinoco_cs_release(dev_list);
-		orinoco_cs_detach(dev_list);
-	}
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_orinoco_cs);
diff -ruN linux-original/drivers/net/wireless/ray_cs.c linux/drivers/net/wireless/ray_cs.c
--- linux-original/drivers/net/wireless/ray_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/wireless/ray_cs.c	2004-10-28 21:53:37.338118488 +0200
@@ -2956,8 +2956,7 @@
 #endif
 
     pcmcia_unregister_driver(&ray_driver);
-    while (dev_list != NULL)
-        ray_detach(dev_list);
+    BUG_ON(dev_list != NULL);
 } /* exit_ray_cs */
 
 module_init(init_ray_cs);
diff -ruN linux-original/drivers/net/wireless/wl3501_cs.c linux/drivers/net/wireless/wl3501_cs.c
--- linux-original/drivers/net/wireless/wl3501_cs.c	2004-10-28 21:12:44.000000000 +0200
+++ linux/drivers/net/wireless/wl3501_cs.c	2004-10-28 21:53:37.340118184 +0200
@@ -2267,13 +2267,7 @@
 {
 	dprintk(0, ": unloading");
 	pcmcia_unregister_driver(&wl3501_driver);
-	while (wl3501_dev_list) {
-		/* Mark the device as non-existing to minimize calls to card */
-		wl3501_dev_list->state &= ~DEV_PRESENT;
-		if (wl3501_dev_list->state & DEV_CONFIG)
-			wl3501_release(wl3501_dev_list);
-		wl3501_detach(wl3501_dev_list);
-	}
+	BUG_ON(wl3501_dev_list != NULL);
 }
 
 module_init(wl3501_init_module);
diff -ruN linux-original/drivers/parport/parport_cs.c linux/drivers/parport/parport_cs.c
--- linux-original/drivers/parport/parport_cs.c	2004-10-28 21:12:48.000000000 +0200
+++ linux/drivers/parport/parport_cs.c	2004-10-28 21:53:37.341118032 +0200
@@ -401,10 +401,7 @@
 static void __exit exit_parport_cs(void)
 {
 	pcmcia_unregister_driver(&parport_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		parport_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_parport_cs);
diff -ruN linux-original/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c
--- linux-original/drivers/pcmcia/bulkmem.c	2004-10-28 21:53:20.546671176 +0200
+++ linux/drivers/pcmcia/bulkmem.c	2004-10-28 21:53:54.413522632 +0200
@@ -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 -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-original/drivers/pcmcia/cs.c	2004-10-28 21:53:20.550670568 +0200
+++ linux/drivers/pcmcia/cs.c	2004-10-28 21:53:54.415522328 +0200
@@ -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
@@ -198,13 +199,6 @@
 static void pcmcia_release_socket(struct class_device *class_dev)
 {
 	struct pcmcia_socket *socket = class_get_devdata(class_dev);
-	client_t *client;
-
-	while (socket->clients) {
-		client = socket->clients;
-		socket->clients = socket->clients->next;
-		kfree(client);
-	}
 
 	complete(&socket->socket_released);
 }
@@ -357,8 +351,6 @@
 
 static void shutdown_socket(struct pcmcia_socket *s)
 {
-    client_t **c;
-    
     cs_dbg(s, 1, "shutdown_socket\n");
 
     /* Blank out the socket state */
@@ -376,15 +368,6 @@
 	kfree(s->config);
 	s->config = NULL;
     }
-    for (c = &s->clients; *c; ) {
-	if ((*c)->state & CLIENT_UNBOUND) {
-	    client_t *d = *c;
-	    *c = (*c)->next;
-	    kfree(d);
-	} else {
-	    c = &((*c)->next);
-	}
-    }
     free_regions(&s->a_region);
     free_regions(&s->c_region);
 
diff -ruN linux-original/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- linux-original/drivers/pcmcia/cs_internal.h	2004-10-28 21:53:20.551670416 +0200
+++ linux/drivers/pcmcia/cs_internal.h	2004-10-28 21:53:54.415522328 +0200
@@ -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 -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c	2004-10-28 21:53:20.553670112 +0200
+++ linux/drivers/pcmcia/ds.c	2004-10-28 21:53:54.417522024 +0200
@@ -350,6 +350,7 @@
 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);
 }
@@ -423,11 +424,11 @@
 	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;
 }
@@ -553,10 +554,10 @@
 {
 	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;
 
@@ -564,26 +565,9 @@
 	       (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))
+	if ((!p_drv) || (!try_module_get(p_drv->owner)))
 		return -EINVAL;
 
-	client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL);
-	if (!client) {
-		ret = -ENOMEM;
-		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
 	 * struct pcmcia_device.
@@ -593,20 +577,12 @@
 	if (!p_dev) {
 		ret = -ENOMEM;
 		pcmcia_put_bus_socket(s);
-		goto err_free_client;
+		goto err_put;
 	}
 	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;
@@ -614,11 +590,18 @@
 	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;
 	}
 
 	/*
@@ -638,15 +621,11 @@
 	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;
 		}
@@ -656,8 +635,6 @@
 
  err_unregister:
 	device_unregister(&p_dev->dev);
- err_free_client:
-	kfree(client);
  err_put:
 	module_put(p_drv->owner);
 	return (ret);
@@ -686,11 +663,11 @@
 			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 = get_p_dev(p_dev);
 				if (p_dev)
-					client = p_dev->client;
+					client = &p_dev->client;
 				spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 				goto found;
 			}
@@ -749,7 +726,6 @@
 	}
 
 	up(&s->skt_sem);
-	put_p_dev(p_dev); /* FIXME: put in deregister_client. */
 	return CS_SUCCESS;
 
  out_no_resource:
@@ -871,7 +847,7 @@
 		}
 		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" */
@@ -890,44 +866,35 @@
 
 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;
 
 	s = SOCKET(handle);
 	ds_dbg(1, "deregister_client(%p)\n", handle);
 
-	if (handle->state &
-	    (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
-		return CS_IN_USE;
+	if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+		goto warn_out;
 	for (i = 0; i < MAX_WIN; i++)
 		if (handle->state & CLIENT_WIN_REQ(i))
-			return CS_IN_USE;
+			goto warn_out;
 
-	if ((handle->state & CLIENT_STALE) ||
-	    (handle->Attributes & INFO_MASTER_CLIENT)) {
-		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;
+	if (handle->state & CLIENT_STALE) {
 		handle->client_magic = 0;
-		kfree(handle);
-		spin_unlock_irqrestore(&s->lock, flags);
+		handle->state &= ~CLIENT_STALE;
+		put_p_dev(p_dev);
 	} else {
 		handle->state = CLIENT_UNBOUND;
 		handle->event_handler = NULL;
 	}
 
 	return CS_SUCCESS;
+ warn_out:
+	printk(KERN_WARNING "ds: deregister_client was called too early.\n");
+	return CS_IN_USE;
 } /* deregister_client */
 EXPORT_SYMBOL(pcmcia_deregister_client);
 
diff -ruN linux-original/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c
--- linux-original/drivers/scsi/pcmcia/aha152x_stub.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/scsi/pcmcia/aha152x_stub.c	2004-10-28 21:53:37.342117880 +0200
@@ -347,10 +347,7 @@
 static void __exit exit_aha152x_cs(void)
 {
 	pcmcia_unregister_driver(&aha152x_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		aha152x_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_aha152x_cs);
diff -ruN linux-original/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c
--- linux-original/drivers/scsi/pcmcia/fdomain_stub.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/scsi/pcmcia/fdomain_stub.c	2004-10-28 21:53:37.342117880 +0200
@@ -328,10 +328,7 @@
 static void __exit exit_fdomain_cs(void)
 {
 	pcmcia_unregister_driver(&fdomain_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		fdomain_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_fdomain_cs);
diff -ruN linux-original/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c
--- linux-original/drivers/scsi/pcmcia/nsp_cs.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/scsi/pcmcia/nsp_cs.c	2004-10-28 21:53:37.357115600 +0200
@@ -2194,10 +2194,9 @@
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
 	pcmcia_unregister_driver(&nsp_driver);
+	BUG_ON(dev_list != NULL);
 #else
 	unregister_pcmcia_driver(&dev_info);
-#endif
-
 	/* XXX: this really needs to move into generic code.. */
 	while (dev_list != NULL) {
 		if (dev_list->state & DEV_CONFIG) {
@@ -2205,6 +2204,7 @@
 		}
 		nsp_cs_detach(dev_list);
 	}
+#endif
 }

diff -ruN linux-original/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c
--- linux-original/drivers/scsi/pcmcia/qlogic_stub.c	2004-10-28 21:12:46.000000000 +0200
+++ linux/drivers/scsi/pcmcia/qlogic_stub.c	2004-10-28 21:53:37.358115448 +0200
@@ -432,10 +432,7 @@
 static void __exit exit_qlogic_cs(void)
 {
 	pcmcia_unregister_driver(&qlogic_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		qlogic_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
diff -ruN linux-original/drivers/serial/serial_cs.c linux/drivers/serial/serial_cs.c
--- linux-original/drivers/serial/serial_cs.c	2004-10-28 21:12:51.000000000 +0200
+++ linux/drivers/serial/serial_cs.c	2004-10-28 21:53:37.359115296 +0200
@@ -749,10 +749,7 @@
 static void __exit exit_serial_cs(void)
 {
 	pcmcia_unregister_driver(&serial_cs_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		serial_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_serial_cs);
diff -ruN linux-original/drivers/telephony/ixj_pcmcia.c linux/drivers/telephony/ixj_pcmcia.c
--- linux-original/drivers/telephony/ixj_pcmcia.c	2004-10-28 21:12:48.000000000 +0200
+++ linux/drivers/telephony/ixj_pcmcia.c	2004-10-28 21:53:37.359115296 +0200
@@ -313,10 +313,7 @@
 static void ixj_pcmcia_exit(void)
 {
 	pcmcia_unregister_driver(&ixj_driver);
-
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL)
-		ixj_detach(dev_list);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(ixj_pcmcia_init);
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h	2004-10-28 21:53:20.567667984 +0200
+++ linux/include/pcmcia/ds.h	2004-10-28 21:53:54.418521872 +0200
@@ -128,7 +128,6 @@

 struct pcmcia_socket;
-struct client_t;
 
 extern struct bus_type pcmcia_bus_type;
 
@@ -154,14 +153,26 @@
 	/* 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;
 };
 
 #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 -ruN linux-original/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- linux-original/include/pcmcia/ss.h	2004-10-28 21:53:20.569667680 +0200
+++ linux/include/pcmcia/ss.h	2004-10-28 21:53:54.418521872 +0200
@@ -153,7 +153,6 @@
 	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;
diff -ruN linux-original/sound/pcmcia/pdaudiocf/pdaudiocf.c linux/sound/pcmcia/pdaudiocf/pdaudiocf.c
--- linux-original/sound/pcmcia/pdaudiocf/pdaudiocf.c	2004-10-28 21:12:54.000000000 +0200
+++ linux/sound/pcmcia/pdaudiocf/pdaudiocf.c	2004-10-28 21:53:37.360115144 +0200
@@ -274,15 +274,6 @@
 }
 
 /*
- * snd_pdacf_detach_all - detach all instances linked to the hw
- */
-static void snd_pdacf_detach_all(void)
-{
-	while (dev_list != NULL)
-		snd_pdacf_detach(dev_list);
-}
-
-/*
  * configuration callback
  */
 
@@ -413,7 +404,7 @@
 static void __exit exit_pdacf(void)
 {
 	pcmcia_unregister_driver(&pdacf_cs_driver);
-	snd_pdacf_detach_all();
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_pdacf);
diff -ruN linux-original/sound/pcmcia/vx/vx_entry.c linux/sound/pcmcia/vx/vx_entry.c
--- linux-original/sound/pcmcia/vx/vx_entry.c	2004-10-28 21:12:54.000000000 +0200
+++ linux/sound/pcmcia/vx/vx_entry.c	2004-10-28 21:53:37.361114992 +0200
@@ -245,15 +245,6 @@
 }
 
 /*
- * snd_vxpocket_detach_all - detach all instances linked to the hw
- */
-void snd_vxpocket_detach_all(struct snd_vxp_entry *hw)
-{
-	while (hw->dev_list != NULL)
-		snd_vxpocket_detach(hw, hw->dev_list);
-}
-
-/*
  * configuration callback
  */
 
@@ -373,4 +364,3 @@
 EXPORT_SYMBOL(snd_vxpocket_ops);
 EXPORT_SYMBOL(snd_vxpocket_attach);
 EXPORT_SYMBOL(snd_vxpocket_detach);
-EXPORT_SYMBOL(snd_vxpocket_detach_all);
diff -ruN linux-original/sound/pcmcia/vx/vxpocket.c linux/sound/pcmcia/vx/vxpocket.c
--- linux-original/sound/pcmcia/vx/vxpocket.c	2004-10-28 21:12:54.000000000 +0200
+++ linux/sound/pcmcia/vx/vxpocket.c	2004-10-28 21:53:37.361114992 +0200
@@ -165,7 +165,7 @@
 static void __exit exit_vxpocket(void)
 {
 	pcmcia_unregister_driver(&vxp_cs_driver);
-	snd_vxpocket_detach_all(&hw_entry);
+	BUG_ON(hw_entry.dev_list != NULL);
 }
 
 module_init(init_vxpocket);
diff -ruN linux-original/sound/pcmcia/vx/vxpocket.h linux/sound/pcmcia/vx/vxpocket.h
--- linux-original/sound/pcmcia/vx/vxpocket.h	2004-10-28 21:12:54.000000000 +0200
+++ linux/sound/pcmcia/vx/vxpocket.h	2004-10-28 21:53:37.362114840 +0200
@@ -77,7 +77,6 @@
  */
 dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw);
 void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link);
-void snd_vxpocket_detach_all(struct snd_vxp_entry *hw);
 
 int vxp_add_mic_controls(vx_core_t *chip);