From: viro@parcelfarce.linux.theplanet.co.uk

* starting to kill imm_detect - we move the "probe a single port" logics
  into a separate function and shift scanning into imm_driver_init().  Later
  that will give us a parport_driver ->attach().



---

 25-akpm/drivers/scsi/imm.c |  219 +++++++++++++++++++--------------------------
 1 files changed, 97 insertions(+), 122 deletions(-)

diff -puN drivers/scsi/imm.c~IMM4-imm_probe-RC1 drivers/scsi/imm.c
--- 25/drivers/scsi/imm.c~IMM4-imm_probe-RC1	Wed Jan 14 13:30:34 2004
+++ 25-akpm/drivers/scsi/imm.c	Wed Jan 14 13:30:34 2004
@@ -100,112 +100,98 @@ static inline void imm_pb_release(imm_st
  *                   Parallel port probing routines                        *
  ***************************************************************************/
 
-static int imm_detect(Scsi_Host_Template * host)
+static Scsi_Host_Template imm_template;
+
+static int imm_probe(imm_struct *dev, struct parport *pb)
 {
-	struct Scsi_Host *hreg;
+	struct Scsi_Host *host;
 	int ports;
-	int i, nhosts, try_again;
-	struct parport *pb;
+	int modes, ppb;
+	int err;
 
-	pb = parport_enumerate();
+	dev->dev = parport_register_device(pb, "imm", NULL, imm_wakeup,
+						NULL, 0, dev);
 
-	printk("imm: Version %s\n", IMM_VERSION);
-	nhosts = 0;
-	try_again = 0;
+	if (!dev->dev)
+		return -ENOMEM;
 
-	if (!pb) {
-		printk("imm: parport reports no devices.\n");
-		return 0;
+	/* Claim the bus so it remembers what we do to the control
+	 * registers. [ CTR and ECP ]
+	 */
+	err = -EBUSY;
+	if (imm_pb_claim(dev)) {
+		unsigned long now = jiffies;
+		while (dev->p_busy) {
+			schedule();	/* We are safe to schedule here */
+			if (time_after(jiffies, now + 3 * HZ)) {
+				printk(KERN_ERR
+				       "imm%d: failed to claim parport because a "
+				       "pardevice is owning the port for too longtime!\n",
+				       dev - imm_hosts);
+				goto out;
+			}
+		}
 	}
-      retry_entry:
-	for (i = 0; pb; i++, pb = pb->next) {
-		imm_struct *dev = &imm_hosts[i];
-		int modes, ppb;
+	ppb = dev->base = dev->dev->port->base;
+	dev->base_hi = dev->dev->port->base_hi;
+	w_ctr(ppb, 0x0c);
+	modes = dev->dev->port->modes;
 
-		dev->dev =
-		    parport_register_device(pb, "imm", NULL, imm_wakeup,
-					    NULL, 0, dev);
+	/* Mode detection works up the chain of speed
+	 * This avoids a nasty if-then-else-if-... tree
+	 */
+	dev->mode = IMM_NIBBLE;
 
-		if (!dev->dev)
-			continue;
+	if (modes & PARPORT_MODE_TRISTATE)
+		dev->mode = IMM_PS2;
 
-		/* Claim the bus so it remembers what we do to the control
-		 * registers. [ CTR and ECP ]
-		 */
-		if (imm_pb_claim(dev)) {
-			unsigned long now = jiffies;
-			while (dev->p_busy) {
-				schedule();	/* We are safe to schedule here */
-				if (time_after(jiffies, now + 3 * HZ)) {
-					printk(KERN_ERR
-					       "imm%d: failed to claim parport because a "
-					       "pardevice is owning the port for too longtime!\n",
-					       i);
-					parport_unregister_device(dev->dev);
-					return 0;
-				}
-			}
-		}
-		ppb = dev->base = dev->dev->port->base;
-		dev->base_hi = dev->dev->port->base_hi;
-		w_ctr(ppb, 0x0c);
-		modes = dev->dev->port->modes;
+	/* Done configuration */
 
-		/* Mode detection works up the chain of speed
-		 * This avoids a nasty if-then-else-if-... tree
-		 */
-		dev->mode = IMM_NIBBLE;
+	err = imm_init(dev);
 
-		if (modes & PARPORT_MODE_TRISTATE)
-			dev->mode = IMM_PS2;
+	imm_pb_release(dev);
 
-		/* Done configuration */
+	if (err)
+		goto out;
 
-		if (imm_init(dev)) {
-			imm_pb_release(dev);
-			parport_unregister_device(dev->dev);
-			continue;
-		}
-		imm_pb_release(dev);
+	/* now the glue ... */
+	switch (dev->mode) {
+	case IMM_NIBBLE:
+	case IMM_PS2:
+		ports = 3;
+		break;
+	case IMM_EPP_8:
+	case IMM_EPP_16:
+	case IMM_EPP_32:
+		ports = 8;
+		break;
+	default:	/* Never gets here */
+		BUG();
+	}
 
-		/* now the glue ... */
-		switch (dev->mode) {
-		case IMM_NIBBLE:
-			ports = 3;
-			break;
-		case IMM_PS2:
-			ports = 3;
-			break;
-		case IMM_EPP_8:
-		case IMM_EPP_16:
-		case IMM_EPP_32:
-			ports = 8;
-			break;
-		default:	/* Never gets here */
-			continue;
-		}
+	INIT_WORK(&dev->imm_tq, imm_interrupt, dev);
 
-		INIT_WORK(&dev->imm_tq, imm_interrupt, dev);
+	err = -ENOMEM;
+	host = scsi_host_alloc(&imm_template, 0);
+	if (!host)
+		goto out;
+	list_add_tail(&host->sht_legacy_list, &imm_template.legacy_hosts);
+	host->io_port = pb->base;
+	host->n_io_port = ports;
+	host->dma_channel = -1;
+	host->unique_id = dev - imm_hosts;
+	err = scsi_add_host(host, NULL);
+	if (err)
+		goto out1;
+	scsi_scan_host(host);
+	return 0;
 
-		hreg = scsi_host_alloc(host, 0);
-		if (hreg == NULL)
-			continue;
-		list_add_tail(&hreg->sht_legacy_list, &host->legacy_hosts);
-		hreg->io_port = pb->base;
-		hreg->n_io_port = ports;
-		hreg->dma_channel = -1;
-		hreg->unique_id = i;
-		nhosts++;
-	}
-	if (nhosts == 0) {
-		if (try_again == 1) {
-			return 0;
-		}
-		try_again = 1;
-		goto retry_entry;
-	} else {
-		return 1;	/* return number of hosts detected */
-	}
+out1:
+	list_del(&host->sht_legacy_list);
+	scsi_host_put(host);
+out:
+	parport_unregister_device(dev->dev);
+	return err;
 }
 
 /* This is to give the imm driver a way to modify the timings (and other
@@ -700,7 +686,7 @@ static int imm_select(imm_struct *dev, i
 static int imm_init(imm_struct *dev)
 {
 	if (imm_connect(dev, 0) != 1)
-		return 1;
+		return -EIO;
 	imm_reset_pulse(dev->base);
 	udelay(1000);	/* Delay to allow devices to settle */
 	imm_disconnect(dev);
@@ -1165,9 +1151,8 @@ static int device_check(imm_struct *dev)
 				dev->mode = old_mode;
 				goto second_pass;
 			}
-			printk
-			    ("imm: Unable to establish communication, aborting driver load.\n");
-			return 1;
+			printk("imm: Unable to establish communication\n");
+			return -EIO;
 		}
 		w_ctr(ppb, 0x0c);
 
@@ -1192,8 +1177,8 @@ static int device_check(imm_struct *dev)
 				goto second_pass;
 			}
 			printk
-			    ("imm: Unable to establish communication, aborting driver load.\n");
-			return 1;
+			    ("imm: Unable to establish communication\n");
+			return -EIO;
 		}
 		imm_disconnect(dev);
 		printk
@@ -1206,11 +1191,11 @@ static int device_check(imm_struct *dev)
 		udelay(1000);
 		return 0;
 	}
-	printk("imm: No devices found, aborting driver load.\n");
-	return 1;
+	printk("imm: No devices found\n");
+	return -ENODEV;
 }
 
-static Scsi_Host_Template driver_template = {
+static Scsi_Host_Template imm_template = {
 	.module			= THIS_MODULE,
 	.proc_name		= "imm",
 	.proc_info		= imm_proc_info,
@@ -1229,34 +1214,24 @@ static Scsi_Host_Template driver_templat
 
 static int __init imm_driver_init(void)
 {
-	struct scsi_host_template *sht = &driver_template;
-	struct Scsi_Host *shost;
-	struct list_head *l;
-	int error;
-
-	INIT_LIST_HEAD(&sht->legacy_hosts);
-
-	imm_detect(sht);
-	if (list_empty(&sht->legacy_hosts))
-		return -ENODEV;
-
-	list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) {
-		error = scsi_add_host(shost, NULL);
-		if (error)
-			goto fail;
-		scsi_scan_host(shost);
+	struct parport *pb = parport_enumerate();
+	int i, nhosts;
+
+	INIT_LIST_HEAD(&imm_template.legacy_hosts);
+
+	printk("imm: Version %s\n", IMM_VERSION);
+
+	for (i = 0, nhosts = 0; pb; i++, pb = pb->next) {
+		imm_struct *dev = &imm_hosts[i];
+		if (imm_probe(dev, pb) == 0)
+			nhosts++;
 	}
-	return 0;
- fail:
-	l = &shost->sht_legacy_list;
-	while ((l = l->prev) != &sht->legacy_hosts)
-		scsi_remove_host(list_entry(l, struct Scsi_Host, sht_legacy_list));
-	return error;
+	return nhosts ? 0 : -ENODEV;
 }
 
 static void __exit imm_driver_exit(void)
 {
-	struct scsi_host_template *sht = &driver_template;
+	struct scsi_host_template *sht = &imm_template;
 	struct Scsi_Host *host, *s;
 
 	list_for_each_entry(host, &sht->legacy_hosts, sht_legacy_list)

_