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

References to slave ports of mux added to struct parport. 
parport_daisy_init() doesn't go through parport_announce_port() for mux
slaves anymore; parport_annouce_port() deals with found ones itself.  Error
handling sanitized, races on unregistration fixed.


---

 drivers/parport/daisy.c |   20 +++++++++-
 drivers/parport/share.c |   94 ++++++++++++++++++++++++++++++------------------
 include/linux/parport.h |    1 
 3 files changed, 79 insertions(+), 36 deletions(-)

diff -puN drivers/parport/daisy.c~parport-06-refcounting-fixes drivers/parport/daisy.c
--- 25/drivers/parport/daisy.c~parport-06-refcounting-fixes	2004-02-18 23:43:57.000000000 -0800
+++ 25-akpm/drivers/parport/daisy.c	2004-02-18 23:43:57.000000000 -0800
@@ -80,6 +80,7 @@ static struct parport *clone_parport (st
 		extra->portnum = real->portnum;
 		extra->physport = real;
 		extra->muxport = muxport;
+		real->slaves[muxport-1] = extra;
 	}
 
 	return extra;
@@ -94,7 +95,9 @@ int parport_daisy_init (struct parport *
 	static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
 	int num_ports;
 	int i;
+	int last_try = 0;
 
+again:
 	/* Because this is called before any other devices exist,
 	 * we don't have to claim exclusive access.  */
 
@@ -127,7 +130,7 @@ int parport_daisy_init (struct parport *
 			/* Analyse that port too.  We won't recurse
 			   forever because of the 'port->muxport < 0'
 			   test above. */
-			parport_announce_port (extra);
+			parport_daisy_init(extra);
 		}
 	}
 
@@ -149,6 +152,21 @@ int parport_daisy_init (struct parport *
 		kfree (deviceid);
 	}
 
+	if (!detected && !last_try) {
+		/* No devices were detected.  Perhaps they are in some
+                   funny state; let's try to reset them and see if
+                   they wake up. */
+		parport_daisy_fini (port);
+		parport_write_control (port, PARPORT_CONTROL_SELECT);
+		udelay (50);
+		parport_write_control (port,
+				       PARPORT_CONTROL_SELECT |
+				       PARPORT_CONTROL_INIT);
+		udelay (50);
+		last_try = 1;
+		goto again;
+	}
+
 	return detected;
 }
 
diff -puN drivers/parport/share.c~parport-06-refcounting-fixes drivers/parport/share.c
--- 25/drivers/parport/share.c~parport-06-refcounting-fixes	2004-02-18 23:43:57.000000000 -0800
+++ 25-akpm/drivers/parport/share.c	2004-02-18 23:43:57.000000000 -0800
@@ -413,22 +413,11 @@ struct parport *parport_register_port(un
 
 void parport_announce_port (struct parport *port)
 {
+	int i;
 
 #ifdef CONFIG_PARPORT_1284
 	/* Analyse the IEEE1284.3 topology of the port. */
-	if (parport_daisy_init (port) == 0) {
-		/* No devices were detected.  Perhaps they are in some
-                   funny state; let's try to reset them and see if
-                   they wake up. */
-		parport_daisy_fini (port);
-		parport_write_control (port, PARPORT_CONTROL_SELECT);
-		udelay (50);
-		parport_write_control (port,
-				       PARPORT_CONTROL_SELECT |
-				       PARPORT_CONTROL_INIT);
-		udelay (50);
-		parport_daisy_init (port);
-	}
+	parport_daisy_init(port);
 #endif
 
 	down(&registration_lock);
@@ -447,13 +436,48 @@ void parport_announce_port (struct parpo
 	portlist_tail = port;
 	if (!portlist)
 		portlist = port;
+	for (i = 1; i < 3; i++) {
+		struct parport *slave = port->slaves[i-1];
+		if (slave) {
+			portlist_tail->next = slave;
+			portlist_tail = slave;
+		}
+	}
 	spin_unlock_irq(&parportlist_lock);
 
-	/* Let drivers know that a new port has arrived. */
+	/* Let drivers know that new port(s) has arrived. */
 	attach_driver_chain (port);
+	for (i = 1; i < 3; i++) {
+		struct parport *slave = port->slaves[i-1];
+		if (slave)
+			attach_driver_chain(slave);
+	}
 	up(&registration_lock);
 }
 
+static void unlink_from_list(struct parport *port)
+{
+	struct parport *p;
+	spin_lock(&parportlist_lock);
+	/* We are protected from other people changing the list, but
+	 * they can still see it (using parport_enumerate).  So be
+	 * careful about the order of writes.. */
+	if (portlist == port) {
+		if ((portlist = port->next) == NULL)
+			portlist_tail = NULL;
+	} else {
+		for (p = portlist; (p != NULL) && (p->next != port);
+		     p=p->next);
+		if (p) {
+			if ((p->next = port->next) == NULL)
+				portlist_tail = p;
+		}
+		else printk (KERN_WARNING
+			     "%s not found in port list!\n", port->name);
+	}
+	spin_unlock(&parportlist_lock);
+}
+
 /**
  *	parport_unregister_port - deregister a parallel port
  *	@port: parallel port to deregister
@@ -475,41 +499,41 @@ void parport_announce_port (struct parpo
 
 void parport_unregister_port(struct parport *port)
 {
-	struct parport *p;
+	int i;
 
 	down(&registration_lock);
-	port->ops = &dead_ops;
 
 	/* Spread the word. */
 	detach_driver_chain (port);
 
 #ifdef CONFIG_PARPORT_1284
 	/* Forget the IEEE1284.3 topology of the port. */
-	parport_daisy_fini (port);
+	parport_daisy_fini(port);
+	for (i = 1; i < 3; i++) {
+		struct parport *slave = port->slaves[i-1];
+		if (!slave)
+			continue;
+		detach_driver_chain(slave);
+		parport_daisy_fini(slave);
+	}
 #endif
 
-	spin_lock(&parportlist_lock);
-
-	/* We are protected from other people changing the list, but
-	 * they can still see it (using parport_enumerate).  So be
-	 * careful about the order of writes.. */
-	if (portlist == port) {
-		if ((portlist = port->next) == NULL)
-			portlist_tail = NULL;
-	} else {
-		for (p = portlist; (p != NULL) && (p->next != port); 
-		     p=p->next);
-		if (p) {
-			if ((p->next = port->next) == NULL)
-				portlist_tail = p;
-		}
-		else printk (KERN_WARNING
-			     "%s not found in port list!\n", port->name);
+	port->ops = &dead_ops;
+	unlink_from_list(port);
+	for (i = 1; i < 3; i++) {
+		struct parport *slave = port->slaves[i-1];
+		if (slave)
+			unlink_from_list(slave);
 	}
-	spin_unlock(&parportlist_lock);
+
 	up(&registration_lock);
 
 	/* Yes, parport_enumerate _is_ unsafe.  Don't use it. */
+	for (i = 1; i < 3; i++) {
+		struct parport *slave = port->slaves[i-1];
+		if (slave)
+			parport_put_port(slave);
+	}
 	parport_put_port (port);
 }
 
diff -puN include/linux/parport.h~parport-06-refcounting-fixes include/linux/parport.h
--- 25/include/linux/parport.h~parport-06-refcounting-fixes	2004-02-18 23:43:57.000000000 -0800
+++ 25-akpm/include/linux/parport.h	2004-02-18 23:43:57.000000000 -0800
@@ -313,6 +313,7 @@ struct parport {
 	atomic_t ref_count;
 
 	struct list_head full_list;
+	struct parport *slaves[3];
 };
 
 #define DEFAULT_SPIN_TIME 500 /* us */

_