From: <viro@www.linux.org.uk>

parport_pc switched to keeping track of the ports it had created; in
module_exit it uses the private list instead of messing with
parport_enumerate().


---

 drivers/parport/parport_pc.c |   31 ++++++++++++++++++++++---------
 include/linux/parport_pc.h   |    2 ++
 2 files changed, 24 insertions(+), 9 deletions(-)

diff -puN drivers/parport/parport_pc.c~parport-09-track-used-ports drivers/parport/parport_pc.c
--- 25/drivers/parport/parport_pc.c~parport-09-track-used-ports	2004-02-18 23:44:02.000000000 -0800
+++ 25-akpm/drivers/parport/parport_pc.c	2004-02-18 23:44:02.000000000 -0800
@@ -2107,6 +2107,9 @@ static int __devinit parport_dma_probe (
 
 /* --- Initialisation code -------------------------------- */
 
+static LIST_HEAD(ports_list);
+static spinlock_t ports_lock = SPIN_LOCK_UNLOCKED;
+
 struct parport *parport_pc_probe_port (unsigned long int base,
 				       unsigned long int base_hi,
 				       int irq, int dma,
@@ -2145,6 +2148,8 @@ struct parport *parport_pc_probe_port (u
 	priv->dma_buf = 0;
 	priv->dma_handle = 0;
 	priv->dev = dev;
+	INIT_LIST_HEAD(&priv->list);
+	priv->port = p;
 	p->base_hi = base_hi;
 	p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
 	p->private_data = priv;
@@ -2296,6 +2301,9 @@ struct parport *parport_pc_probe_port (u
 	/* Now that we've told the sharing engine about the port, and
 	   found out its characteristics, let the high-level drivers
 	   know about it. */
+	spin_lock(&ports_lock);
+	list_add(&priv->list, &ports_list);
+	spin_unlock(&ports_lock);
 	parport_announce_port (p);
 
 	return p;
@@ -2325,6 +2333,9 @@ void parport_pc_unregister_port (struct 
 #endif /* CONFIG_PARPORT_PC_FIFO */
 	struct parport_operations *ops = p->ops;
 	parport_remove_port(p);
+	spin_lock(&ports_lock);
+	list_del_init(&priv->list);
+	spin_unlock(&ports_lock);
 	if (p->dma != PARPORT_DMA_NONE)
 		free_dma(p->dma);
 	if (p->irq != PARPORT_IRQ_NONE)
@@ -3126,19 +3137,21 @@ static int __init parport_pc_init(void)
 
 static void __exit parport_pc_exit(void)
 {
-	/* We ought to keep track of which ports are actually ours. */
-	struct parport *p = parport_enumerate(), *tmp;
-
 	if (registered_parport)
 		pci_unregister_driver (&parport_pc_pci_driver);
 
-	while (p) {
-		tmp = p->next;
-		if (p->modes & PARPORT_MODE_PCSPP)
-			parport_pc_unregister_port (p);
-
-		p = tmp;
+	spin_lock(&ports_lock);
+	while (!list_empty(&ports_list)) {
+		struct parport_pc_private *priv;
+		struct parport *port;
+		priv = list_entry(ports_list.next,
+				  struct parport_pc_private, list);
+		port = priv->port;
+		spin_unlock(&ports_lock);
+		parport_pc_unregister_port(port);
+		spin_lock(&ports_lock);
 	}
+	spin_unlock(&ports_lock);
 	pnp_unregister_driver (&parport_pc_pnp_driver);
 }
 
diff -puN include/linux/parport_pc.h~parport-09-track-used-ports include/linux/parport_pc.h
--- 25/include/linux/parport_pc.h~parport-09-track-used-ports	2004-02-18 23:44:02.000000000 -0800
+++ 25-akpm/include/linux/parport_pc.h	2004-02-18 23:44:02.000000000 -0800
@@ -39,6 +39,8 @@ struct parport_pc_private {
 	char *dma_buf;
 	dma_addr_t dma_handle;
 	struct pci_dev *dev;
+	struct list_head list;
+	struct parport *port;
 };
 
 static __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)

_