patch-2.3.38 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: 576
- Date:
Fri Jan 7 16:07:14 2000
- Orig file:
v2.3.37/linux/drivers/usb/usb_scsi.c
- Orig date:
Thu Jan 6 12:57:48 2000
diff -u --recursive --new-file v2.3.37/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
@@ -3,9 +3,6 @@
* (c) 1999 Michael Gee (michael@linuxspecific.com)
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
- * In order to support various 'strange' devices, this module supports plug-in
- * device-specific filter modules, which can do their own thing when required.
- *
* Further reference:
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
@@ -29,7 +26,6 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
-#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
@@ -55,25 +51,17 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-#ifdef REWRITE_PROJECT
-#define IRQ_PERIOD 255
-#else
-#define IRQ_PERIOD 0 /* single IRQ transfer then remove it */
-#endif
-
/*
* Per device data
*/
static int my_host_number;
-int usbscsi_debug = 1;
+int usb_stor_debug = 1;
struct us_data {
- struct us_data *next; /* next device */
+ struct us_data *next; /* next device */
struct usb_device *pusb_dev;
- struct usb_scsi_filter *filter; /* filter driver */
- void *fdata; /* filter data */
unsigned int flags; /* from filter initially */
__u8 ifnum; /* interface number */
__u8 ep_in; /* in endpoint */
@@ -115,19 +103,20 @@
static struct us_data *us_list;
-static struct usb_scsi_filter *filters;
-
-static void * scsi_probe(struct usb_device *dev, unsigned int ifnum);
-static void scsi_disconnect(struct usb_device *dev, void *ptr);
-static struct usb_driver scsi_driver = {
- "usb_scsi",
- scsi_probe,
- scsi_disconnect,
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
+static void storage_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_driver storage_driver = {
+ "usb-storage",
+ storage_probe,
+ storage_disconnect,
{ NULL, NULL }
};
-/* Data handling, using SG if required */
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+/* transfer one buffer (breaking into packets if necessary) */
static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
{
int max_size = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe)) * 16;
@@ -135,17 +124,23 @@
int result;
unsigned long partial;
int maxtry = 100;
+
+ /* while we have data to transfer */
while (length) {
+
+ /* calculate how long this will be -- maximum or a remainder */
this_xfer = length > max_size ? max_size : length;
length -= this_xfer;
+
do {
+ /* transfer the data */
US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);
result = usb_bulk_msg(us->pusb_dev, pipe, buf,
this_xfer, &partial, HZ*5);
-
US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
result, partial, this_xfer);
+ /* if we stall, we need to clear it before we go on */
if (result == USB_ST_STALL) {
US_DEBUGP("clearing endpoint halt for pipe %x\n", pipe);
usb_clear_halt(us->pusb_dev,
@@ -154,33 +149,50 @@
/* 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 */
- }
+
+ /* if our try counter reaches 0, bail out */
if (!maxtry--)
break;
+
+ /* otherwise, we did transmit some data, and we update pointers */
this_xfer -= partial;
buf += partial;
+
} else if (!result && partial != this_xfer) {
- /* short data - assume end */
+ /* result is an error, not a NAK, and short data - assume end */
result = USB_ST_DATAUNDERRUN;
break;
+
} else if (result == USB_ST_STALL && us->protocol == US_PR_CB) {
+ /* for CB devices, a stall isn't fatal? */
+
+ /* if our try counter reaches 0, bail out */
if (!maxtry--)
break;
+
this_xfer -= partial;
buf += partial;
- } else
- break;
+ }
+
+ /* continue until this transfer is done */
} while ( this_xfer );
+
+ /* if we have some nonzero result, we return it here */
if (result)
return result;
+
+ /* otherwise, we advance the buf pointer
+ * note that the code above doesn't advance the pointer if all
+ * goes well
+ */
buf += this_xfer;
}
+ /* if we get here, we're done and successful */
return 0;
}
+/* transfer one SCSI command, using scatter-gather if requested */
static int us_transfer(Scsi_Cmnd *srb, int dir_in)
{
struct us_data *us = (struct us_data *)srb->host_scribble;
@@ -207,6 +219,9 @@
return result;
}
+/* calculate the length of the data transfer (not the command) for any
+ * given SCSI command
+ */
static unsigned int us_transfer_length(Scsi_Cmnd *srb)
{
int i;
@@ -238,11 +253,15 @@
return srb->request_bufflen;
}
-static int pop_CBI_irq(int state, void *buffer, int len, void *dev_id)
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+static int CBI_irq(int state, void *buffer, int len, void *dev_id)
{
struct us_data *us = (struct us_data *)dev_id;
- US_DEBUGP("pop_CBI_irq() called!!\n");
+ US_DEBUGP("CBI_irq() called!!\n");
if (state != USB_ST_REMOVED) {
us->ip_data = le16_to_cpup((__u16 *)buffer);
@@ -254,7 +273,7 @@
wake_up(&us->ip_waitq);
}
- /* we don't want another interrupt */
+ /* this return code is truly meaningless */
return 0;
}
@@ -458,7 +477,7 @@
int result;
US_DEBUGP("CBI gets a command:\n");
- us_show_command(srb);
+ US_DEBUG(us_show_command(srb));
/* run the command */
if ((result = pop_CB_command(srb)) < 0) {
@@ -658,10 +677,8 @@
usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
us->irq_handle = NULL;
}
- if (us->filter)
- us->filter->release(us->fdata);
if (us->pusb_dev)
- usb_deregister(&scsi_driver);
+ usb_deregister(&storage_driver);
/* FIXME - leaves hanging host template copy */
/* (because scsi layer uses it after removal !!!) */
@@ -709,6 +726,7 @@
{
struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ US_DEBUGP("Bus reset requested\n");
us->pop_reset(us);
return SUCCESS;
}
@@ -726,7 +744,7 @@
#undef SPRINTF
#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 usb_stor_proc_info (char *buffer, char **start, off_t offset,
int length, int hostno, int inout)
{
struct us_data *us = us_list;
@@ -814,7 +832,7 @@
NULL, /* next */
NULL, /* module */
NULL, /* proc_dir */
- usb_scsi_proc_info,
+ usb_stor_proc_info,
NULL, /* name - points to unique */
us_detect,
us_release,
@@ -861,7 +879,7 @@
0x00
};
-static int usbscsi_control_thread(void * __us)
+static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
int action;
@@ -872,9 +890,7 @@
* This thread doesn't need any user-level access,
* so get rid of all our resources..
*/
- exit_mm(current);
- exit_files(current);
- //exit_fs(current);
+ daemonize();
sprintf(current->comm, "usbscsi%d", us->host_number);
@@ -911,11 +927,9 @@
} else {
US_DEBUG(us_show_command(us->srb));
- if (us->filter && us->filter->command)
- us->srb->result = us->filter->command(us->fdata, us->srb);
- else if (us->srb->cmnd[0] == START_STOP &&
- us->pusb_dev->descriptor.idProduct == 0x0001 &&
- us->pusb_dev->descriptor.idVendor == 0x04e6)
+ if (us->srb->cmnd[0] == START_STOP &&
+ us->pusb_dev->descriptor.idProduct == 0x0001 &&
+ us->pusb_dev->descriptor.idVendor == 0x04e6)
us->srb->result = DID_OK << 16;
else {
unsigned int savelen = us->srb->request_bufflen;
@@ -1162,8 +1176,8 @@
spin_unlock_irq(¤t->sigmask_lock);
if (signr == SIGUSR2) {
- usbscsi_debug = !usbscsi_debug;
- printk(USB_SCSI "debug toggle = %d\n", usbscsi_debug);
+ usb_stor_debug = !usb_stor_debug;
+ printk(USB_SCSI "debug toggle = %d\n", usb_stor_debug);
} else {
break; /* exit the loop on any other signal */
}
@@ -1172,14 +1186,13 @@
// MOD_DEC_USE_COUNT;
- printk("usbscsi_control_thread exiting\n");
+ printk("usb_stor_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)
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
int i;
@@ -1187,8 +1200,6 @@
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); /* Global Unique Identifier */
struct us_data *prev;
@@ -1204,77 +1215,54 @@
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) {
- flags = filter->flags;
- printk(KERN_INFO "USB Scsi filter %s\n", filter->name);
- break;
- }
- filter = filter->next;
- }
- }
-
- /* generic devices next */
-
- /* MDD: Isn't this always true? */
- if (fdata == NULL) {
+ /* let's examine the device now */
- /* We make an exception for the shuttle E-USB */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- protocol = US_PR_CB;
- subclass = US_SC_8070; /* an assumption */
- } else if (dev->descriptor.bDeviceClass != 0 ||
- 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;
- }
+ /* We make an exception for the shuttle E-USB */
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ protocol = US_PR_CB;
+ subclass = US_SC_8070; /* an assumption */
+ } else if (dev->descriptor.bDeviceClass != 0 ||
+ 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;
+ }
- /* At this point, we know we've got a live one */
- US_DEBUGP("USB Mass Storage device detected\n");
+ /* 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) ) {
- /* 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 {
- /* We don't have a serial number, so we use 0 */
- make_guid(guid, dev->descriptor.idVendor,
- dev->descriptor.idProduct, "0");
- }
+ /* Create a GUID for this device */
+ if (dev->descriptor.iSerialNumber &&
+ usb_string(dev, dev->descriptor.iSerialNumber) ) {
+ /* 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 {
+ /* We don't have a serial number, so we use 0 */
+ make_guid(guid, dev->descriptor.idVendor,
+ dev->descriptor.idProduct, "0");
+ }
- /* 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;
- }
+ /* 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) {
printk(KERN_WARNING USB_SCSI "Out of memory\n");
- if (filter)
- filter->release(fdata);
return NULL;
}
memset(ss, 0, sizeof(struct us_data));
@@ -1282,8 +1270,6 @@
/* 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;
@@ -1365,8 +1351,7 @@
kfree(ss->htmplt->name);
kfree(ss->htmplt);
}
- if (filter)
- filter->release(fdata);
+
kfree(ss);
return NULL;
}
@@ -1420,8 +1405,7 @@
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;
}
@@ -1451,19 +1435,12 @@
US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
init_waitqueue_head(&ss->ip_waitq);
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe, pop_CBI_irq,
- IRQ_PERIOD, (void *)ss, &ss->irq_handle);
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
+ 255, (void *)ss, &ss->irq_handle);
if (result)
return NULL;
interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6);
-#ifdef REWRITE_PROJECT
- /* FIXME: Don't know if this release_irq() call is at the
- right place/time. */
- usb_release_irq(ss->pusb_dev, ss->irq_handle, ss->irqpipe);
- ss->irq_handle = NULL;
-#endif
-
} else if (ss->protocol == US_PR_CBI)
{
int result;
@@ -1473,7 +1450,7 @@
/* 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,
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
255, (void *)ss, &ss->irq_handle);
if (result) {
US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
@@ -1489,13 +1466,12 @@
init_waitqueue_head(&ss->waitq);
ss->notify = &sem;
- ss->pid = kernel_thread(usbscsi_control_thread, ss,
+ ss->pid = kernel_thread(usb_stor_control_thread, ss,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (ss->pid < 0) {
printk(KERN_WARNING USB_SCSI "Unable to start control thread\n");
kfree(htmplt);
- if (filter)
- filter->release(fdata);
+
kfree(ss);
return NULL;
}
@@ -1523,14 +1499,13 @@
}
/* Handle a disconnect event from the USB core */
-static void scsi_disconnect(struct usb_device *dev, void *ptr)
+static void storage_disconnect(struct usb_device *dev, void *ptr)
{
struct us_data *ss = ptr;
if (!ss)
return;
- if (ss->filter)
- ss->filter->release(ss->fdata);
+
ss->pusb_dev = NULL;
// MOD_DEC_USE_COUNT;
}
@@ -1540,49 +1515,26 @@
* Initialization and registration
***********************************************************************/
-int usb_scsi_init(void)
+int usb_stor_init(void)
{
// MOD_INC_USE_COUNT;
- if (usb_register(&scsi_driver) < 0)
+ if (usb_register(&storage_driver) < 0)
return -1;
printk(KERN_INFO "USB SCSI support registered.\n");
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;
-
- while (prev->next)
- prev = prev->next;
- prev->next = filter;
- return 0;
-}
-
-void usb_scsi_deregister(struct usb_scsi_filter *filter)
-{
- struct usb_scsi_filter *prev = (struct usb_scsi_filter *)&filters;
-
- while (prev->next && prev->next != filter)
- prev = prev->next;
- if (prev->next)
- prev->next = filter->next;
-}
-
#ifdef MODULE
int init_module(void)
{
/* MDD: Perhaps we should register the host here */
- return usb_scsi_init();
+ return usb_stor_init();
}
void cleanup_module(void)
{
- usb_deregister(&scsi_driver);
+ usb_deregister(&storage_driver);
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)