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
- Lines: 981
- Date:
Mon Dec 20 14:16:59 1999
- Orig file:
v2.3.33/linux/drivers/usb/usb_scsi.c
- Orig date:
Wed Dec 8 14:11:27 1999
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)