patch-2.3.34 linux/drivers/usb/usb_scsi.c

Next file: linux/drivers/usb/usb_scsi.h
Previous file: linux/drivers/usb/usb.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.33/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
@@ -26,7 +26,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -144,9 +143,8 @@
 			result = usb_bulk_msg(us->pusb_dev, pipe, buf,
 					      this_xfer, &partial, HZ*5);
 
-			if (result != 0 || partial != this_xfer)
-				US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
-					  result, partial, this_xfer);
+			US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
+				  result, partial, this_xfer);
 
 			if (result == USB_ST_STALL) {
 				US_DEBUGP("clearing endpoint halt for pipe %x\n", pipe);
@@ -157,7 +155,7 @@
 			/* we want to retry if the device reported NAK */
 			if (result == USB_ST_TIMEOUT) {
 				if (partial != this_xfer) {
-					return 0;	/* I do not like this */
+					return 0;   /* I do not like this */
 				}
 				if (!maxtry--)
 					break;
@@ -244,10 +242,13 @@
 {
 	struct us_data *us = (struct us_data *)dev_id;
 
+	US_DEBUGP("pop_CBI_irq() called!!\n");
+
 	if (state != USB_ST_REMOVED) {
 		us->ip_data = le16_to_cpup((__u16 *)buffer);
-		/* US_DEBUGP("Interrupt Status %x\n", us->ip_data); */
+		US_DEBUGP("Interrupt Status %x\n", us->ip_data);
 	}
+  
 	if (us->ip_wanted) {
 		us->ip_wanted = 0;
 		wake_up(&us->ip_waitq);
@@ -291,13 +292,13 @@
 	int retry = 5;
 	int done_start = 0;
 
+	/* we'll try this up to 5 times? */
 	while (retry--) {
-
 		if (us->flags & US_FL_FIXED_COMMAND) {
 			memset(cmd, 0, us->fixedlength);
-
+      
 			/* fix some commands */
-
+      
 			switch (srb->cmnd[0]) {
 			case WRITE_6:
 			case READ_6:
@@ -323,37 +324,52 @@
 				us->mode_xlate = 0;
 				memcpy(cmd, srb->cmnd, srb->cmd_len);
 				break;
-			}
+			} /* switch */
+
 			result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
 						 US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
 						 0, us->ifnum,
 						 cmd, us->fixedlength, HZ*5);
-			if (!done_start && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/)
-			    && cmd[0] == TEST_UNIT_READY && result) {
+			US_DEBUGP("First usb_control_msg returns %d\n", result);
+
+			/* For UFI, if this is the first time we've sent this TEST_UNIT_READY 
+			 * command, we can try again
+			 */
+			if (!done_start && (us->subclass == US_SC_UFI)
+			    && (cmd[0] == TEST_UNIT_READY) && (result < 0)) {
+
 				/* as per spec try a start command, wait and retry */
+				wait_ms(100);
 
 				done_start++;
 				memset(cmd, 0, sizeof(cmd));
 				cmd[0] = START_STOP;
 				cmd[4] = 1;		/* start */
+
 				result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
-							 US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
+							 US_CBI_ADSC, 
+							 USB_TYPE_CLASS | USB_RT_INTERFACE,
 							 0, us->ifnum,
 							 cmd, us->fixedlength, HZ*5);
-				wait_ms(100);
+				US_DEBUGP("Next usb_control_msg returns %d\n", result);
+
+				/* allow another retry */
 				retry++;
 				continue;
 			}
-		} else {
+		} else { /* !US_FL_FIXED_COMMAND */
 			result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
 						 US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
 						 0, us->ifnum,
 						 srb->cmnd, srb->cmd_len, HZ*5);
 		}
+    
+		/* return an answer if we've got one */
 		if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
 			return result;
 	}
 
+	/* all done -- return our status */
 	return result;
 }
 
@@ -375,9 +391,9 @@
 
 		while (retry--) {
 			result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0),
-						 USB_REQ_GET_STATUS, USB_DIR_IN | USB_TYPE_STANDARD | USB_RT_DEVICE,
-						 0, us->ifnum,
-						 status, sizeof(status), HZ*5);
+						 USB_REQ_GET_STATUS, USB_DIR_IN |
+						 USB_TYPE_STANDARD | USB_RT_DEVICE,
+						 0, us->ifnum, status, sizeof(status), HZ*5);
 			if (result != USB_ST_TIMEOUT)
 				break;
 		}
@@ -398,20 +414,14 @@
 
 		/* add interrupt transfer, marked for removal */
 		us->ip_wanted = 1;
-		us->irqpipe = usb_rcvintpipe(us->pusb_dev, us->ep_int);
-		result = usb_request_irq(us->pusb_dev, us->irqpipe, pop_CBI_irq,
-					 IRQ_PERIOD, (void *)us, &us->irq_handle);
-		if (result) {
-			US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
-				  result);
-			return DID_ABORT << 16;
-		}
 
+		/* go to sleep until we get this interrup */
 		sleep_on(&us->ip_waitq);
-#ifdef REWRITE_PROJECT
-		usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
-		us->irq_handle = NULL;
-#endif
+
+		/* NO! We don't release this IRQ.  We just re-use the handler 
+		   usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
+		   us->irq_handle = NULL;
+		*/
 
 		if (us->ip_wanted) {
 			US_DEBUGP("Did not get interrupt on CBI\n");
@@ -447,10 +457,12 @@
 {
 	int result;
 
-	/* run the command */
+	US_DEBUGP("CBI gets a command:\n");
+	us_show_command(srb);
 
-	if ((result = pop_CB_command(srb))) {
-		US_DEBUGP("CBI command %x\n", result);
+	/* run the command */
+	if ((result = pop_CB_command(srb)) < 0) {
+		US_DEBUGP("Call to pop_CB_command returned %d\n", result);
 		if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) {
 			return (DID_OK << 16) | 2;
 		}
@@ -458,11 +470,12 @@
 	}
 
 	/* transfer the data */
-
 	if (us_transfer_length(srb)) {
 		result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-		if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) {
-			US_DEBUGP("CBI transfer %x\n", result);
+		if ((result < 0) && 
+		    (result != USB_ST_DATAUNDERRUN) && 
+		    (result != USB_ST_STALL)) {
+			US_DEBUGP("CBI attempted to transfer data, result is %x\n", result);
 			return DID_ERROR << 16;
 		}
 #if 0
@@ -578,6 +591,8 @@
 		US_DEBUGP("Bulk logical error\n");
 		return DID_ABORT << 16;
 	}
+
+	/* We need to fix some of this status handling. */
 	switch (bcs.Status) {
 	case US_BULK_STAT_OK:
 		return DID_OK << 16;
@@ -593,7 +608,7 @@
 		return DID_ERROR << 16;
 	}
 
-	return (DID_OK << 16) | 2;		/* check sense required */
+	return (DID_OK << 16) | 2;	    /* check sense required */
 }
 
 /* Host functions */
@@ -605,20 +620,28 @@
 	struct us_data *us = (struct us_data *)sht->proc_dir;
 	char name[32];
 
+	/* set up our name */
 	sprintf(name, "usbscsi%d", us->host_number);
 	sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
 	if (!sht->proc_name)
 		return 0;
 	strcpy(sht->proc_name, name);
+
+	/* we start with no /proc directory entry */
 	sht->proc_dir = NULL;
+
+	/* register the host */
 	us->host = scsi_register(sht, sizeof(us));
 	if (us->host) {
 		us->host->hostdata[0] = (unsigned long)us;
 		us->host_no = us->host->host_no;
 		return 1;
 	}
+
+	/* odd... didn't register properly.  Abort and free pointers */
 	kfree(sht->proc_name);
-	sht->proc_name = sht->name = NULL;
+	sht->proc_name = NULL;
+	sht->name = NULL;
 	return 0;
 }
 
@@ -695,55 +718,80 @@
 	return 0;
 }
 
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+/* we use this macro to help us write into the buffer */
 #undef SPRINTF
-#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
+#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0)
 
-int usb_scsi_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int usb_scsi_proc_info (char *buffer, char **start, off_t offset, 
+			int length, int hostno, int inout)
 {
 	struct us_data *us = us_list;
 	char *pos = buffer;
-	char *vendor;
-	char *product;
-	char *style = "";
+	char *tmp_ptr;
 
 	/* find our data from hostno */
-
 	while (us) {
 		if (us->host_no == hostno)
 			break;
 		us = us->next;
 	}
 
+	/* if we couldn't find it, we return an error */
 	if (!us)
 		return -ESRCH;
 
-	/* null on outward */
-
+	/* if someone is sending us data, just throw it away */
 	if (inout)
 		return length;
 
-	if (!us->pusb_dev || !(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer)))
-		vendor = "?";
-	if (!us->pusb_dev || !(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct)))
-		product = "?";
+	/* print the controler name */
+	SPRINTF ("Host scsi%d: usb-scsi\n", hostno);
+
+	/* print product and vendor strings */
+	if (!us->pusb_dev) {
+		SPRINTF("Vendor: Unknown Vendor\n");
+		SPRINTF("Product: Unknown Product\n");
+	} else {
+		SPRINTF("Vendor: ");
+		tmp_ptr = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer);
+		if (!tmp_ptr)
+			SPRINTF("Unknown Vendor\n");
+		else
+			SPRINTF("%s\n", tmp_ptr);
+    
+		SPRINTF("Product: ");
+		tmp_ptr = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct);
+		if (!tmp_ptr)
+			SPRINTF("Unknown Vendor\n");
+		else
+			SPRINTF("%s\n", tmp_ptr);
+	}
 
+	SPRINTF("Protocol: ");
 	switch (us->protocol) {
 	case US_PR_CB:
-		style = "Control/Bulk";
+		SPRINTF("Control/Bulk\n");
 		break;
-
+    
 	case US_PR_CBI:
-		style = "Control/Bulk/Interrupt";
+		SPRINTF("Control/Bulk/Interrupt\n");
 		break;
-
-	case US_PR_ZIP:
-		style = "Bulk only";
+    
+	case US_PR_BULK:
+		SPRINTF("Bulk only\n");
+		break;
+    
+	default:
+		SPRINTF("Unknown Protocol\n");
 		break;
-
 	}
-	SPRINTF ("Host scsi%d: usb-scsi\n", hostno);
-	SPRINTF ("Device: %s %s - GUID " GUID_FORMAT "\n", vendor, product, GUID_ARGS(us->guid) );
-	SPRINTF ("Style: %s\n", style);
+
+	/* show the GUID of the device */
+	SPRINTF("GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
 
 	/*
 	 * Calculate start of next buffer, and return value.
@@ -763,50 +811,50 @@
  */
 
 static Scsi_Host_Template my_host_template = {
-	NULL,			/* next */
-	NULL,			/* module */
-	NULL,			/* proc_dir */
+	NULL,			    /* next */
+	NULL,			    /* module */
+	NULL,			    /* proc_dir */
 	usb_scsi_proc_info,
-	NULL,			/* name - points to unique */
+	NULL,			    /* name - points to unique */
 	us_detect,
 	us_release,
-	NULL,			/* info */
-	NULL,			/* ioctl */
+	NULL,			    /* info */
+	NULL,			    /* ioctl */
 	us_command,
 	us_queuecommand,
-	NULL,			/* eh_strategy */
+	NULL,			    /* eh_strategy */
 	us_abort,
 	us_bus_reset,
 	us_bus_reset,
 	us_host_reset,
-	NULL,			/* abort */
-	NULL,			/* reset */
-	NULL,			/* slave_attach */
-	NULL,			/* bios_param */
-	1,				/* can_queue */
-	-1,				/* this_id */
-	SG_ALL,			/* sg_tablesize */
-	1,				/* cmd_per_lun */
-	0,				/* present */
-	FALSE,			/* unchecked_isa_dma */
-	FALSE,			/* use_clustering */
-	TRUE,			/* use_new_eh_code */
-	TRUE			/* emulated */
+	NULL,			    /* abort */
+	NULL,			    /* reset */
+	NULL,			    /* slave_attach */
+	NULL,			    /* bios_param */
+	1,			    /* can_queue */
+	-1,			    /* this_id */
+	SG_ALL,			    /* sg_tablesize */
+	1,			    /* cmd_per_lun */
+	0,			    /* present */
+	FALSE,			    /* unchecked_isa_dma */
+	FALSE,			    /* use_clustering */
+	TRUE,			    /* use_new_eh_code */
+	TRUE			    /* emulated */
 };
 
 static unsigned char sense_notready[] = {
-	0x70,			/* current error */
+	0x70,			    /* current error */
 	0x00,
-	0x02,			/* not ready */
+	0x02,			    /* not ready */
 	0x00,
 	0x00,
-	10,				/* additional length */
+	10,			    /* additional length */
 	0x00,
 	0x00,
 	0x00,
 	0x00,
-	0x04,			/* not ready */
-	0x03,			/* manual intervention */
+	0x04,			    /* not ready */
+	0x03,			    /* manual intervention */
 	0x00,
 	0x00,
 	0x00,
@@ -863,8 +911,6 @@
 			} else {
 				US_DEBUG(us_show_command(us->srb));
 
-				/* check for variable length - do properly if so */
-
 				if (us->filter && us->filter->command)
 					us->srb->result = us->filter->command(us->fdata, us->srb);
 				else if (us->srb->cmnd[0] == START_STOP &&
@@ -875,6 +921,7 @@
 					unsigned int savelen = us->srb->request_bufflen;
 					unsigned int saveallocation = 0;
 
+					/* check for variable length - do properly if so */
 					switch (us->srb->cmnd[0]) {
 					case REQUEST_SENSE:
 						if (us->srb->request_bufflen > 18)
@@ -917,6 +964,66 @@
 					default:
 						break;
 					} /* end switch on cmnd[0] */
+
+#if 0
+					/* translate READ_6 to READ_10 */
+					if (us->srb->cmnd[0] == 0x08) {
+
+						/* get the control */
+						us->srb->cmnd[9] = us->srb->cmnd[5];
+
+						/* get the length */
+						us->srb->cmnd[8] = us->srb->cmnd[6];
+						us->srb->cmnd[7] = 0;
+
+						/* set the reserved area to 0 */
+						us->srb->cmnd[6] = 0;	    
+
+						/* get LBA */
+						us->srb->cmnd[5] = us->srb->cmnd[3];
+						us->srb->cmnd[4] = us->srb->cmnd[2];
+						us->srb->cmnd[3] = 0;
+						us->srb->cmnd[2] = 0;
+
+						/* LUN and other info in cmnd[1] can stay */
+	    
+						/* fix command code */
+						us->srb->cmnd[0] = 0x28;
+
+						US_DEBUGP("Changing READ_6 to READ_10\n");
+						US_DEBUG(us_show_command(us->srb));
+					}
+
+					/* translate WRITE_6 to WRITE_10 */
+					if (us->srb->cmnd[0] == 0x0A) {
+
+						/* get the control */
+						us->srb->cmnd[9] = us->srb->cmnd[5];
+
+						/* get the length */
+						us->srb->cmnd[8] = us->srb->cmnd[4];
+						us->srb->cmnd[7] = 0;
+
+						/* set the reserved area to 0 */
+						us->srb->cmnd[6] = 0;	    
+
+						/* get LBA */
+						us->srb->cmnd[5] = us->srb->cmnd[3];
+						us->srb->cmnd[4] = us->srb->cmnd[2];
+						us->srb->cmnd[3] = 0;
+						us->srb->cmnd[2] = 0;
+
+						/* LUN and other info in cmnd[1] can stay */
+	    
+						/* fix command code */
+						us->srb->cmnd[0] = 0x2A;
+
+						US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
+						US_DEBUG(us_show_command(us->srb));
+					}
+#endif
+
+					/* let's do the command */
 					us->srb->result = us->pop(us->srb);
 
 					if (savelen != us->srb->request_bufflen &&
@@ -927,9 +1034,9 @@
 						/* set correct length and retry */
 						switch (us->srb->cmnd[0]) {
 						case REQUEST_SENSE:
-				/* simply return 18 bytes */
+							/* simply return 18 bytes */
 							p[7] = 10;
-							length = us->srb->request_bufflen;;
+							length = us->srb->request_bufflen;
 							break;
 
 						case INQUIRY:
@@ -938,8 +1045,9 @@
 							break;
 
 						case MODE_SENSE:
-							length = p[0] + 4 > savelen ? savelen : p[0] + 4;
-							us->srb->cmnd[4] = 4;
+							US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]);
+							length = p[0] + 1 > savelen ? savelen : p[0] + 1;
+							us->srb->cmnd[4] = length;
 							break;
 
 						case LOG_SENSE:
@@ -949,7 +1057,9 @@
 							break;
 
 						case MODE_SENSE_10:
-							length = ((p[0] << 8) + p[1]) + 8 > savelen ? savelen : ((p[0] << 8) + p[1]) + 8;
+							US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n",
+								  (p[0] << 8) + p[1]);
+							length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6;
 							us->srb->cmnd[7] = length >> 8;
 							us->srb->cmnd[8] = length;
 							break;
@@ -967,8 +1077,13 @@
 
 						us->srb->request_bufflen = savelen;
 						switch (us->srb->cmnd[0]) {
-						case REQUEST_SENSE:
 						case INQUIRY:
+							if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) { 
+								US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
+								((unsigned char*)us->srb->request_buffer)[2] |= 2;
+							}
+							/* FALL THROUGH */
+						case REQUEST_SENSE:
 						case MODE_SENSE:
 							if (us->srb->use_sg == 0 && length > 0) {
 								int i;
@@ -1050,42 +1165,51 @@
 				usbscsi_debug = !usbscsi_debug;
 				printk(USB_SCSI "debug toggle = %d\n", usbscsi_debug);
 			} else {
-				break;	/* exit the loop on any other signal */
+				break;	    /* exit the loop on any other signal */
 			}
 		}
 	}
 
-	MOD_DEC_USE_COUNT;
+	//  MOD_DEC_USE_COUNT;
 
 	printk("usbscsi_control_thread exiting\n");
 
 	return 0;
 }	
 
+
+/* Probe to see if a new device is actually a SCSI device */
 static void * scsi_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface_descriptor *interface;
 	int i;
-	char *mf;		/* manufacturer */
-	char *prod;		/* product */
-	char *serial;		/* serial number */
+	char *mf;		     /* manufacturer */
+	char *prod;		     /* product */
+	char *serial;		     /* serial number */
 	struct us_data *ss = NULL;
 	struct usb_scsi_filter *filter = filters;
 	void *fdata = NULL;
 	unsigned int flags = 0;
-	GUID(guid);
+	GUID(guid);		     /* Global Unique Identifier */
 	struct us_data *prev;
 	Scsi_Host_Template *htmplt;
 	int protocol = 0;
 	int subclass = 0;
+	struct usb_interface_descriptor *altsetting = 
+		&(dev->actconfig->interface[ifnum].altsetting[0]); 
 
+	/* clear the GUID and fetch the strings */
 	GUID_CLEAR(guid);
 	mf = usb_string(dev, dev->descriptor.iManufacturer);
 	prod = usb_string(dev, dev->descriptor.iProduct);
 	serial = usb_string(dev, dev->descriptor.iSerialNumber);
 
 	/* probe with filters first */
-
+	/* MDD: What are filters?  What do they do? 
+	 * They look like some way to catch certain specific devices and set
+	 * flags for them.  Probably a good idea if we have lots of different
+	 * types of devices.
+	 */
 	if (mf && prod) {
 		while (filter) {
 			if ((fdata = filter->probe(dev, mf, prod, serial)) != NULL) {
@@ -1098,45 +1222,56 @@
 	}
 
 	/* generic devices next */
-
+    
+	/* MDD: Isn't this always true? */
 	if (fdata == NULL) {
 
-		/* some exceptions */
+		/* We make an exception for the shuttle E-USB */
 		if (dev->descriptor.idVendor == 0x04e6 &&
 		    dev->descriptor.idProduct == 0x0001) {
-			/* shuttle E-USB */
 			protocol = US_PR_CB;
-			subclass = US_SC_8070;	/* an assumption */
+			subclass = US_SC_8070;	    /* an assumption */
 		} else if (dev->descriptor.bDeviceClass != 0 ||
-			   dev->actconfig->interface[ifnum].altsetting[0].bInterfaceClass !=
-			   USB_CLASS_MASS_STORAGE ||
-			   dev->actconfig->interface[ifnum].altsetting[0].bInterfaceSubClass < US_SC_MIN ||
-			   dev->actconfig->interface[ifnum].altsetting[0].bInterfaceSubClass > US_SC_MAX) {
+			   altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+			   altsetting->bInterfaceSubClass < US_SC_MIN ||
+			   altsetting->bInterfaceSubClass > US_SC_MAX) {
+			/* if it's not a mass storage, we go no further */
 			return NULL;
 		}
 
-		/* now check if we have seen it before */
+		/* At this point, we know we've got a live one */
+		US_DEBUGP("USB Mass Storage device detected\n");
 
+		/* Create a GUID for this device */
 		if (dev->descriptor.iSerialNumber &&
 		    usb_string(dev, dev->descriptor.iSerialNumber) ) {
-			make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
+			/* If we have a serial number, and it's a non-NULL string */
+			make_guid(guid, dev->descriptor.idVendor, 
+				  dev->descriptor.idProduct,
 				  usb_string(dev, dev->descriptor.iSerialNumber));
 		} else {
-			make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
-				  "0");
+			/* We don't have a serial number, so we use 0 */
+			make_guid(guid, dev->descriptor.idVendor, 
+				  dev->descriptor.idProduct, "0");
 		}
-		for (ss = us_list; ss; ss = ss->next) {
-			if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid))	{
+
+		/* Now check if we have seen this GUID before, and restore
+		 * the flags if we find it
+		 */
+		for (ss = us_list; ss != NULL; ss = ss->next) {
+			if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid))    {
 				US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
 					  GUID_ARGS(guid));
 				flags = ss->flags;
 				break;
 			}
 		}
-	}
+	} /* if (fdata == NULL) */
 
+	/* If ss == NULL, then this is a new device.  Allocate memory for it */
 	if (!ss) {
-		if ((ss = (struct us_data *)kmalloc(sizeof(*ss), GFP_KERNEL)) == NULL) {
+		if ((ss = (struct us_data *)kmalloc(sizeof(*ss), 
+						    GFP_KERNEL)) == NULL) {
 			printk(KERN_WARNING USB_SCSI "Out of memory\n");
 			if (filter)
 				filter->release(fdata);
@@ -1145,10 +1280,18 @@
 		memset(ss, 0, sizeof(struct us_data));
 	}
 
-	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	/* Initialize the us_data structure with some useful info */
+	interface = altsetting;
 	ss->filter = filter;
 	ss->fdata = fdata;
 	ss->flags = flags;
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->attention_done = 0;
+
+	/* If the device has subclass and protocol, then use that.  Otherwise, 
+	 * take data from the specific interface.
+	 */
 	if (subclass) {
 		ss->subclass = subclass;
 		ss->protocol = protocol;
@@ -1156,11 +1299,9 @@
 		ss->subclass = interface->bInterfaceSubClass;
 		ss->protocol = interface->bInterfaceProtocol;
 	}
-	ss->attention_done = 0;
-
-	/* set the protocol op */
 
-	US_DEBUGP("Protocol ");
+	/* set the handler pointers based on the protocol */
+	US_DEBUGP("Protocol: ");
 	switch (ss->protocol) {
 	case US_PR_CB:
 		US_DEBUGPX("Control/Bulk\n");
@@ -1174,11 +1315,17 @@
 		ss->pop_reset = pop_CB_reset;
 		break;
 
-	default:
+	case US_PR_BULK:
 		US_DEBUGPX("Bulk\n");
 		ss->pop = pop_Bulk;
 		ss->pop_reset = pop_Bulk_reset;
 		break;
+
+	default:
+		US_DEBUGPX("Unknown\n");    
+		kfree(ss);
+		return NULL;
+		break;
 	}
 
 	/*
@@ -1186,9 +1333,9 @@
 	 * An optional interrupt is OK (necessary for CBI protocol).
 	 * We will ignore any others.
 	 */
-
 	for (i = 0; i < interface->bNumEndpoints; i++) {
-		if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+		/* is it an BULK endpoint? */
+		if ((interface->endpoint[i].bmAttributes &  USB_ENDPOINT_XFERTYPE_MASK)
 		    == USB_ENDPOINT_XFER_BULK) {
 			if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
 				ss->ep_in = interface->endpoint[i].bEndpointAddress &
@@ -1196,8 +1343,11 @@
 			else
 				ss->ep_out = interface->endpoint[i].bEndpointAddress &
 					USB_ENDPOINT_NUMBER_MASK;
-		} else if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			   == USB_ENDPOINT_XFER_INT) {
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 
+		    == USB_ENDPOINT_XFER_INT) {
 			ss->ep_int = interface->endpoint[i].bEndpointAddress &
 				USB_ENDPOINT_NUMBER_MASK;
 		}
@@ -1205,13 +1355,10 @@
 	US_DEBUGP("Endpoints In %d Out %d Int %d\n",
 		  ss->ep_in, ss->ep_out, ss->ep_int);
 
-	/* save the interface number */
-	ss->ifnum = ifnum;
-
-	/* exit if strange looking */
-
+	/* Do some basic sanity checks, and bail if we find a problem */
 	if (usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
-	    !ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+	    !ss->ep_in || !ss->ep_out || 
+	    (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
 		US_DEBUGP("Problems with device\n");
 		if (ss->host) {
 			scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt);
@@ -1221,78 +1368,82 @@
 		if (filter)
 			filter->release(fdata);
 		kfree(ss);
-		return NULL;			/* no endpoints */
+		return NULL;
 	}
 
-	if (dev->actconfig->iConfiguration && usb_string(dev, dev->actconfig->iConfiguration))
-		US_DEBUGP("Configuration %s\n",
-			  usb_string(dev, dev->actconfig->iConfiguration));
-	if (interface->iInterface && usb_string(dev, interface->iInterface))
-		US_DEBUGP("Interface %s\n",
-			  usb_string(dev, interface->iInterface));
-
-	ss->pusb_dev = dev;
-
-	/* Now generate a scsi host definition, and register with scsi above us */
-
+	/* If this is a new device (i.e. we haven't seen it before), we need to
+	 * generate a scsi host definition, and register with scsi above us 
+	 */
 	if (!ss->host) {
-
-		/* make unique id if possible */
-
+		/* copy the GUID we created before */
 		US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
 		memcpy(ss->guid, guid, sizeof(guid));
 
 		/* set class specific stuff */
-
-		US_DEBUGP("SubClass ");
+		US_DEBUGP("SubClass: ");
 		switch (ss->subclass) {
 		case US_SC_RBC:
 			US_DEBUGPX("Reduced Block Commands\n");
 			break;
+
 		case US_SC_8020:
 			US_DEBUGPX("8020\n");
 			break;
+
 		case US_SC_QIC:
 			US_DEBUGPX("QIC157\n");
 			break;
+
 		case US_SC_8070:
 			US_DEBUGPX("8070\n");
 			ss->flags |= US_FL_FIXED_COMMAND;
 			ss->fixedlength = 12;
 			break;
+
 		case US_SC_SCSI:
 			US_DEBUGPX("Transparent SCSI\n");
 			break;
+
 		case US_SC_UFI:
-			US_DEBUGPX(" UFF\n");
+			US_DEBUGPX("UFI\n");
 			ss->flags |= US_FL_FIXED_COMMAND;
 			ss->fixedlength = 12;
 			break;
 
 		default:
+			US_DEBUGPX("Unknown\n");
 			break;
 		}
 
-		/* create unique host template */
+		/* Allocate memory for the SCSI Host Template */
+		if ((htmplt = (Scsi_Host_Template *)
+		     kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) {
 
-		if ((htmplt = (Scsi_Host_Template *)kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) {
 			printk(KERN_WARNING USB_SCSI "Out of memory\n");
 			if (filter)
 				filter->release(fdata);
 			kfree(ss);
 			return NULL;
 		}
+
+		/* Initialize the host template based on the default one */
 		memcpy(htmplt, &my_host_template, sizeof(my_host_template));
+
+		/* Grab the next host number */
 		ss->host_number = my_host_number++;
 
-		(struct us_data *)htmplt->proc_dir = ss;
+		/* MDD: FIXME: this is bad.  We abuse this pointer so we
+		 * can pass the ss pointer to the host controler thread
+		 * in us_detect
+		 */
+		(struct us_data *)htmplt->proc_dir = ss; 
 
+		/* shuttle E-USB */	
 		if (dev->descriptor.idVendor == 0x04e6 &&
 		    dev->descriptor.idProduct == 0x0001) {
 			__u8 qstat[2];
 			int result;
-
-			/* shuttle E-USB */
+	    
 			result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0),
 						 1, 0xC0,
 						 0, ss->ifnum,
@@ -1314,10 +1465,24 @@
 #endif
 
 		} else if (ss->protocol == US_PR_CBI)
+		{
+			int result; 
+
 			init_waitqueue_head(&ss->ip_waitq);
 
-		/* start up our thread */
+			/* set up the IRQ pipe and handler */
+			/* FIXME: This needs to get the period from the device */
+			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, pop_CBI_irq,
+						 255, (void *)ss, &ss->irq_handle);
+			if (result) {
+				US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
+					  result);
+			}
+		}
+    
 
+		/* start up our thread */
 		{
 			DECLARE_MUTEX_LOCKED(sem);
 
@@ -1336,7 +1501,6 @@
 			}
 
 			/* wait for it to start */
-
 			down(&sem);
 		}
 
@@ -1352,12 +1516,13 @@
 		prev->next = ss;
 	}
 
-	printk(KERN_WARNING "DANGEROUS: USB SCSI driver data integrity not assured !!!\n");
+	printk(KERN_WARNING "WARNING: USB SCSI data integrity not assured\n");
 	printk(KERN_INFO "USB SCSI device found at address %d\n", dev->devnum);
 
 	return ss;
 }
 
+/* Handle a disconnect event from the USB core */
 static void scsi_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct us_data *ss = ptr;
@@ -1367,19 +1532,17 @@
 	if (ss->filter)
 		ss->filter->release(ss->fdata);
 	ss->pusb_dev = NULL;
-	MOD_DEC_USE_COUNT;
+	//  MOD_DEC_USE_COUNT;
 }
 
+
+/***********************************************************************
+ * Initialization and registration
+ ***********************************************************************/
+
 int usb_scsi_init(void)
 {
-	MOD_INC_USE_COUNT;
-
-#ifdef CONFIG_USB_HP4100
-	hp4100_init();
-#endif
-#ifdef CONFIG_USB_ZIP
-	usb_zip_init();
-#endif
+	//  MOD_INC_USE_COUNT;
 
 	if (usb_register(&scsi_driver) < 0)
 		return -1;
@@ -1388,6 +1551,9 @@
 	return 0;
 }
 
+/* Functions to handle filters.	 These are designed to allow us to handle
+ * certain odd devices 
+ */
 int usb_scsi_register(struct usb_scsi_filter *filter)
 {
 	struct usb_scsi_filter *prev = (struct usb_scsi_filter *)&filters;
@@ -1411,6 +1577,7 @@
 #ifdef MODULE
 int init_module(void)
 {
+	/* MDD: Perhaps we should register the host here */
 	return usb_scsi_init();
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)