# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.516   -> 1.517  
#	drivers/usb/storage/usb.c	1.23    -> 1.24   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/18	mdharm-usb@one-eyed-alien.net	1.517
# [PATCH] USB storage: cleanup storage_probe()
# 
# Attached is a BK patch which cleans up the usb-storage driver
# storage_probe() function.  This patch is courtsey Alan Stern.
# 
# Basically, it removes some redundant checks, moves all the error-path code
# to one place (reducing code duplication), and fixes some spelling errors.
# --------------------------------------------
#
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Tue Jun 18 17:02:02 2002
+++ b/drivers/usb/storage/usb.c	Tue Jun 18 17:02:02 2002
@@ -557,9 +557,8 @@
 	unsigned int flags;
 	struct us_unusual_dev *unusual_dev;
 	struct us_data *ss = NULL;
-#ifdef CONFIG_USB_STORAGE_SDDR09
 	int result;
-#endif
+	int new_device = 0;
 
 	/* these are temporary copies -- we test on these, then put them
 	 * in the us-data structure 
@@ -570,13 +569,13 @@
 	u8 subclass = 0;
 	u8 protocol = 0;
 
-	/* the altsettting on the interface we're probing that matched our
+	/* the altsetting on the interface we're probing that matched our
 	 * usb_match_id table
 	 */
 	struct usb_interface *intf = dev->actconfig->interface;
 	struct usb_interface_descriptor *altsetting =
 		intf[ifnum].altsetting + intf[ifnum].act_altsetting;
-	US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting);
+	US_DEBUGP("act_altsetting is %d\n", intf[ifnum].act_altsetting);
 
 	/* clear the temporary strings */
 	memset(mf, 0, sizeof(mf));
@@ -663,7 +662,7 @@
 		return NULL;
 	}
 
-	/* At this point, we're committed to using the device */
+	/* At this point, we've decided to try to use the device */
 	usb_get_dev(dev);
 
 	/* clear the GUID and fetch the strings */
@@ -696,7 +695,8 @@
 	 */
 	ss = us_list;
 	while ((ss != NULL) && 
-	       ((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid)))
+	           ((atomic_read(&ss->device_state) == US_STATE_ATTACHED) ||
+		    !GUID_EQUAL(guid, ss->guid)))
 		ss = ss->next;
 
 	if (ss != NULL) {
@@ -713,26 +713,20 @@
 		atomic_set(&ss->device_state, US_STATE_ATTACHED);
 
 		/* copy over the endpoint data */
-		if (ep_in)
-			ss->ep_in = ep_in->bEndpointAddress & 
-				USB_ENDPOINT_NUMBER_MASK;
-		if (ep_out)
-			ss->ep_out = ep_out->bEndpointAddress & 
-				USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_in = ep_in->bEndpointAddress & 
+			USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_out = ep_out->bEndpointAddress & 
+			USB_ENDPOINT_NUMBER_MASK;
 		ss->ep_int = ep_int;
 
 		/* allocate an IRQ callback if one is needed */
-		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) {
-			usb_put_dev(dev);
-			return NULL;
-		}
+		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+			goto BadDevice;
 
 		/* allocate the URB we're going to use */
 		ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!ss->current_urb) {
-			usb_put_dev(dev);
-			return NULL;
-		}
+		if (!ss->current_urb)
+			goto BadDevice;
 
                 /* Re-Initialize the device if it needs it */
 		if (unusual_dev && unusual_dev->initFunction)
@@ -752,14 +746,12 @@
 			return NULL;
 		}
 		memset(ss, 0, sizeof(struct us_data));
+		new_device = 1;
 
 		/* allocate the URB we're going to use */
 		ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!ss->current_urb) {
-			kfree(ss);
-			usb_put_dev(dev);
-			return NULL;
-		}
+		if (!ss->current_urb)
+			goto BadDevice;
 
 		/* Initialize the mutexes only when the struct is new */
 		init_completion(&(ss->notify));
@@ -776,12 +768,10 @@
 		ss->unusual_dev = unusual_dev;
 
 		/* copy over the endpoint data */
-		if (ep_in)
-			ss->ep_in = ep_in->bEndpointAddress & 
-				USB_ENDPOINT_NUMBER_MASK;
-		if (ep_out)
-			ss->ep_out = ep_out->bEndpointAddress & 
-				USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_in = ep_in->bEndpointAddress & 
+			USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_out = ep_out->bEndpointAddress & 
+			USB_ENDPOINT_NUMBER_MASK;
 		ss->ep_int = ep_int;
 
 		/* establish the connection to the new device */
@@ -904,12 +894,8 @@
 #endif
 
 		default:
-			ss->transport_name = "Unknown";
-			kfree(ss->current_urb);
-			kfree(ss);
-			usb_put_dev(dev);
-			return NULL;
-			break;
+			/* ss->transport_name = "Unknown"; */
+			goto BadDevice;
 		}
 		US_DEBUGP("Transport: %s\n", ss->transport_name);
 
@@ -959,22 +945,14 @@
 #endif
 
 		default:
-			ss->protocol_name = "Unknown";
-			kfree(ss->current_urb);
-			kfree(ss);
-			usb_put_dev(dev);
-			return NULL;
-			break;
+			/* ss->protocol_name = "Unknown"; */
+			goto BadDevice;
 		}
 		US_DEBUGP("Protocol: %s\n", ss->protocol_name);
 
 		/* allocate an IRQ callback if one is needed */
-		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) {
-			kfree(ss->current_urb);
-			kfree(ss);
-			usb_put_dev(dev);
-			return NULL;
-		}
+		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+			goto BadDevice;
 
 		/*
 		 * Since this is a new device, we need to generate a scsi 
@@ -1007,10 +985,7 @@
 		if (ss->pid < 0) {
 			printk(KERN_WARNING USB_STORAGE 
 			       "Unable to start control thread\n");
-			kfree(ss->current_urb);
-			kfree(ss);
-			usb_put_dev(dev);
-			return NULL;
+			goto BadDevice;
 		}
 
 		/* wait for the thread to start */
@@ -1018,7 +993,17 @@
 
 		/* now register	 - our detect function will be called */
 		ss->htmplt.module = THIS_MODULE;
-		scsi_register_host(&(ss->htmplt));
+		result = scsi_register_host(&(ss->htmplt));
+		if (result) {
+			printk(KERN_WARNING USB_STORAGE
+				"Unable to register the scsi host\n");
+
+			/* tell the control thread to exit */
+			ss->action = US_ACT_EXIT;
+			up(&ss->sema);
+			wait_for_completion(&ss->notify);
+			goto BadDevice;
+		}
 
 		/* lock access to the data structures */
 		down(&us_list_semaphore);
@@ -1038,6 +1023,31 @@
 
 	/* return a pointer for the disconnect function */
 	return ss;
+
+	/* we come here if there are any problems */
+	BadDevice:
+	US_DEBUGP("storage_probe() failed\n");
+	down(&ss->irq_urb_sem);
+	if (ss->irq_urb) {
+		usb_unlink_urb(ss->irq_urb);
+		usb_free_urb(ss->irq_urb);
+		ss->irq_urb = NULL;
+	}
+	up(&ss->irq_urb_sem);
+	if (ss->current_urb) {
+		usb_unlink_urb(ss->current_urb);
+		usb_free_urb(ss->current_urb);
+		ss->current_urb = NULL;
+	}
+
+	atomic_set(&ss->device_state, US_STATE_DETACHED);
+	ss->pusb_dev = NULL;
+	if (new_device)
+		kfree(ss);
+	else
+		up(&ss->dev_semaphore);
+	usb_put_dev(dev);
+	return NULL;
 }
 
 /* Handle a disconnect event from the USB core */
