patch-2.3.99-pre7 linux/drivers/usb/usb-storage.c
Next file: linux/drivers/usb/usb-storage.h
Previous file: linux/drivers/usb/usb-ohci.c
Back to the patch index
Back to the overall index
- Lines: 805
- Date:
Tue May 2 13:15:41 2000
- Orig file:
v2.3.99-pre6/linux/drivers/usb/usb-storage.c
- Orig date:
Wed Apr 26 16:34:08 2000
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
@@ -66,59 +66,59 @@
/* we allocate one of these for every device that we remember */
struct us_data {
- struct us_data *next; /* next device */
+ struct us_data *next; /* next device */
/* the device we're working with */
- struct semaphore dev_semaphore; /* protect pusb_dev */
- struct usb_device *pusb_dev; /* this usb_device */
+ struct semaphore dev_semaphore; /* protect pusb_dev */
+ struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */
/* information about the device -- always good */
- char vendor[32];
- char product[32];
- char serial[32];
- char *transport_name;
- char *protocol_name;
- __u8 subclass;
- __u8 protocol;
+ char vendor[USB_STOR_STRING_LEN];
+ char product[USB_STOR_STRING_LEN];
+ char serial[USB_STOR_STRING_LEN];
+ char *transport_name;
+ char *protocol_name;
+ u8 subclass;
+ u8 protocol;
/* information about the device -- only good if device is attached */
- __u8 ifnum; /* interface number */
- __u8 ep_in; /* bulk in endpoint */
- __u8 ep_out; /* bulk out endpoint */
- __u8 ep_int; /* interrupt endpoint */
- __u8 ep_interval; /* interrupt interval */
+ u8 ifnum; /* interface number */
+ u8 ep_in; /* bulk in endpoint */
+ u8 ep_out; /* bulk out endpoint */
+ struct usb_endpoint_descriptor *ep_int; /* interrupt endpoint */
/* function pointers for this device */
- trans_cmnd transport; /* transport function */
- trans_reset transport_reset; /* transport device reset */
- proto_cmnd proto_handler; /* protocol handler */
+ trans_cmnd transport; /* transport function */
+ trans_reset transport_reset; /* transport device reset */
+ proto_cmnd proto_handler; /* protocol handler */
/* SCSI interfaces */
- GUID(guid); /* unique dev id */
+ GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */
- Scsi_Host_Template htmplt; /* own host template */
- int host_number; /* to find us */
- int host_no; /* allocated by scsi */
- Scsi_Cmnd *srb; /* current srb */
+ Scsi_Host_Template htmplt; /* own host template */
+ int host_number; /* to find us */
+ int host_no; /* allocated by scsi */
+ Scsi_Cmnd *srb; /* current srb */
/* thread information */
Scsi_Cmnd *queue_srb; /* the single queue slot */
- int action; /* what to do */
- int pid; /* control thread */
+ int action; /* what to do */
+ int pid; /* control thread */
/* interrupt info for CBI devices -- only good if attached */
- struct semaphore ip_waitq; /* for CBI interrupts */
- __u16 ip_data; /* interrupt data */
- int ip_wanted; /* is an IRQ expected? */
- void *irq_handle; /* for USB int requests */
- unsigned int irqpipe; /* pipe for release_irq */
+ struct semaphore ip_waitq; /* for CBI interrupts */
+ int ip_wanted; /* is an IRQ expected? */
+
+ struct semaphore irq_urb_sem; /* to protect irq_urb */
+ struct urb *irq_urb; /* for USB int requests */
+ unsigned char irqbuf[2]; /* buffer for USB IRQ */
/* mutual exclusion structures */
- struct semaphore notify; /* thread begin/end */
- struct semaphore sleeper; /* to sleep the thread on */
- struct semaphore queue_exclusion; /* to protect data structs */
+ struct semaphore notify; /* thread begin/end */
+ struct semaphore sleeper; /* to sleep the thread on */
+ struct semaphore queue_exclusion; /* to protect data structs */
};
/*
@@ -151,7 +151,7 @@
* Transfer one SCSI scatter-gather buffer via bulk transfer
*
* Note that this function is necessary because we want the ability to
- * use scatter-gather memory. Good performance is achived by a combination
+ * use scatter-gather memory. Good performance is achieved by a combination
* of scatter-gather and clustering (which makes each chunk bigger).
*
* Note that the lower layer will always retry when a NAK occurs, up to the
@@ -166,7 +166,7 @@
/* transfer the data */
US_DEBUGP("Bulk xfer 0x%x(%d)\n", (unsigned int)buf, length);
- result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ);
+ result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, 5*HZ);
US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
result, partial, length);
@@ -226,7 +226,7 @@
*/
sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
- result = us_transfer_partial(us, pipe, sg[i].address,
+ result = us_transfer_partial(us, pipe, sg[i].address,
sg[i].length);
if (result)
break;
@@ -234,7 +234,7 @@
}
else
/* no scatter-gather, just make the request */
- result = us_transfer_partial(us, pipe, srb->request_buffer,
+ result = us_transfer_partial(us, pipe, srb->request_buffer,
srb->request_bufflen);
/* return the result in the data structure itself */
@@ -251,7 +251,7 @@
struct scatterlist *sg;
/* support those devices which need the length calculated
- * differently
+ * differently
*/
if (us->flags & US_FL_ALT_LENGTH) {
if (srb->cmnd[0] == INQUIRY) {
@@ -374,18 +374,18 @@
srb->cmnd[3] = 0;
srb->cmnd[4] = 18;
srb->cmnd[5] = 0;
-
+
/* set the buffer length for transfer */
old_request_buffer = srb->request_buffer;
old_request_bufflen = srb->request_bufflen;
- old_sg = srb->use_sg;
+ old_sg = srb->use_sg;
srb->use_sg = 0;
srb->request_bufflen = 18;
srb->request_buffer = srb->sense_buffer;
/* issue the auto-sense command */
temp_result = us->transport(us->srb, us);
- if (temp_result == USB_STOR_TRANSPORT_ERROR) {
+ if (temp_result != USB_STOR_TRANSPORT_GOOD) {
/* FIXME: we need to invoke a transport reset here */
US_DEBUGP("-- auto-sense failure\n");
srb->result = DID_ERROR << 16;
@@ -433,20 +433,22 @@
/*
* Control/Bulk/Interrupt transport
*/
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
+static void CBI_irq(struct urb *urb)
{
- struct us_data *us = (struct us_data *)dev_id;
+ struct us_data *us = (struct us_data *)urb->context;
US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
- US_DEBUGP("-- IRQ data length is %d\n", len);
- US_DEBUGP("-- IRQ state is %d\n", state);
+ US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
+ US_DEBUGP("-- IRQ state is %d\n", urb->status);
/* is the device removed? */
- if (state != -ENOENT) {
+ if (urb->status != -ENOENT) {
/* save the data for interpretation later */
- us->ip_data = le16_to_cpup((__u16 *)buffer);
- US_DEBUGP("-- Interrupt Status 0x%x\n", us->ip_data);
-
+ US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
+ ((unsigned char*)urb->transfer_buffer)[0],
+ ((unsigned char*)urb->transfer_buffer)[1]);
+
+
/* was this a wanted interrupt? */
if (us->ip_wanted) {
us->ip_wanted = 0;
@@ -455,12 +457,6 @@
US_DEBUGP("ERROR: Unwanted interrupt received!\n");
} else
US_DEBUGP("-- device has been removed\n");
-
- /* This return code is truly meaningless -- and I mean truly. It gets
- * ignored by other layers. It used to indicate if we wanted to get
- * another interrupt or disable the interrupt callback
- */
- return 0;
}
static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
@@ -480,7 +476,7 @@
/* STALL must be cleared when they are detected */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
- result = usb_clear_halt(us->pusb_dev,
+ result = usb_clear_halt(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,
0));
US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
@@ -513,7 +509,9 @@
return USB_STOR_TRANSPORT_ERROR;
}
- US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+ US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
+ ((unsigned char*)us->irq_urb->transfer_buffer)[0],
+ ((unsigned char*)us->irq_urb->transfer_buffer)[1]);
/* UFI gives us ASC and ASCQ, like a request sense
*
@@ -527,7 +525,7 @@
srb->cmnd[0] == INQUIRY)
return USB_STOR_TRANSPORT_GOOD;
else
- if (us->ip_data)
+ if (((unsigned char*)us->irq_urb->transfer_buffer)[0])
return USB_STOR_TRANSPORT_FAILED;
else
return USB_STOR_TRANSPORT_GOOD;
@@ -537,10 +535,14 @@
* The first byte should always be a 0x0
* The second byte & 0x0F should be 0x0 for good, otherwise error
*/
- switch ((us->ip_data & 0xFF0F)) {
- case 0x0000:
+ if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) {
+ US_DEBUGP("CBI IRQ data showed reserved bType\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ switch (((unsigned char*)us->irq_urb->transfer_buffer)[1] & 0x0F) {
+ case 0x00:
return USB_STOR_TRANSPORT_GOOD;
- case 0x0001:
+ case 0x01:
return USB_STOR_TRANSPORT_FAILED;
default:
return USB_STOR_TRANSPORT_ERROR;
@@ -609,8 +611,8 @@
int partial;
/* set up the command wrapper */
- bcb.Signature = US_BULK_CB_SIGN;
- bcb.DataTransferLength = us_transfer_length(srb, us);
+ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
@@ -625,8 +627,8 @@
/* send it to out endpoint */
US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
- bcb.Signature, bcb.Tag, bcb.Lun, bcb.DataTransferLength,
- bcb.Flags, bcb.Length);
+ le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun,
+ bcb.DataTransferLength, bcb.Flags, bcb.Length);
result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
US_BULK_CB_WRAP_LEN, &partial, HZ*5);
US_DEBUGP("Bulk command transfer result=%d\n", result);
@@ -657,17 +659,17 @@
/* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n");
result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ);
+ US_BULK_CS_WRAP_LEN, &partial, HZ*2);
/* did the attempt to read the CSW fail? */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
usb_clear_halt(us->pusb_dev, pipe);
-
+
/* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ);
+ US_BULK_CS_WRAP_LEN, &partial, HZ*2);
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
@@ -685,8 +687,10 @@
/* check bulk status */
US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
- bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
- if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+ le32_to_cpu(bcs.Signature), bcs.Tag,
+ bcs.Residue, bcs.Status);
+ if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
+ bcs.Tag != bcb.Tag ||
bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
US_DEBUGP("Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR;
@@ -718,7 +722,7 @@
static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
-
+
/* Fix some commands -- this is a form of mode translation
* ATAPI devices only accept 12 byte long commands
*
@@ -770,10 +774,10 @@
srb->cmnd[0] = srb->cmnd[0] | 0x20;
break;
} /* end switch on cmnd[0] */
-
+
/* send the command to the transport layer */
invoke_transport(srb, us);
-
+
/* Fix the MODE_SENSE data if we translated the command
*/
if (old_cmnd == MODE_SENSE) {
@@ -802,7 +806,7 @@
static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
-
+
/* fix some commands -- this is a form of mode translation
* UFI devices only accept 12 byte long commands
*
@@ -831,7 +835,7 @@
srb->cmnd[10] = 0;
srb->cmnd[9] = 0;
- /* if we're sending data, we send all. If getting data,
+ /* if we're sending data, we send all. If getting data,
* get the minimum */
if (srb->cmnd[0] == MODE_SELECT)
srb->cmnd[8] = srb->cmnd[4];
@@ -853,7 +857,7 @@
srb->cmnd[7] = 0;
srb->cmnd[8] = 8;
break;
-
+
/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
case REQUEST_SENSE:
srb->cmnd[4] = 18;
@@ -912,48 +916,48 @@
* so some devices do not support them
*/
if (us->flags & US_FL_MODE_XLATE) {
-
+
/* translate READ_6 to READ_10 */
if (srb->cmnd[0] == 0x08) {
-
+
/* get the control */
srb->cmnd[9] = us->srb->cmnd[5];
-
+
/* get the length */
srb->cmnd[8] = us->srb->cmnd[6];
srb->cmnd[7] = 0;
-
+
/* set the reserved area to 0 */
srb->cmnd[6] = 0;
-
+
/* get LBA */
srb->cmnd[5] = us->srb->cmnd[3];
srb->cmnd[4] = us->srb->cmnd[2];
srb->cmnd[3] = 0;
srb->cmnd[2] = 0;
-
+
/* LUN and other info in cmnd[1] can stay */
-
+
/* fix command code */
srb->cmnd[0] = 0x28;
-
+
US_DEBUGP("Changing READ_6 to READ_10\n");
US_DEBUG(us_show_command(srb));
}
-
+
/* translate WRITE_6 to WRITE_10 */
if (srb->cmnd[0] == 0x0A) {
-
+
/* get the control */
srb->cmnd[9] = us->srb->cmnd[5];
-
+
/* get the length */
srb->cmnd[8] = us->srb->cmnd[4];
srb->cmnd[7] = 0;
-
+
/* set the reserved area to 0 */
srb->cmnd[6] = 0;
-
+
/* get LBA */
srb->cmnd[5] = us->srb->cmnd[3];
srb->cmnd[4] = us->srb->cmnd[2];
@@ -961,7 +965,7 @@
srb->cmnd[2] = 0;
/* LUN and other info in cmnd[1] can stay */
-
+
/* fix command code */
srb->cmnd[0] = 0x2A;
@@ -1226,7 +1230,7 @@
SPRINTF(" Host scsi%d: usb-storage\n", hostno);
/* print product, vendor, and serial number strings */
- SPRINTF(" Vendor: %s\n", us->vendor);
+ SPRINTF(" Vendor: %s\n", us->vendor);
SPRINTF(" Product: %s\n", us->product);
SPRINTF("Serial Number: %s\n", us->serial);
@@ -1235,7 +1239,7 @@
SPRINTF(" Transport: %s\n", us->transport_name);
/* show the GUID of the device */
- SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+ SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
/* release our lock on the data structures */
up(&us_list_semaphore);
@@ -1334,7 +1338,7 @@
action = us->action;
us->action = 0;
us->srb = us->queue_srb;
-
+
/* release the queue lock as fast as possible */
up(&(us->queue_exclusion));
@@ -1380,8 +1384,8 @@
sizeof(sense_notready));
us->srb->result = GOOD;
} else {
- memcpy(us->srb->sense_buffer,
- sense_notready,
+ memcpy(us->srb->sense_buffer,
+ sense_notready,
sizeof(sense_notready));
us->srb->result = CHECK_CONDITION;
}
@@ -1395,7 +1399,7 @@
up(&(us->dev_semaphore));
/* indicate that the command is done */
- US_DEBUGP("scsi cmd done, result=0x%x\n",
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
us->srb = NULL;
@@ -1428,15 +1432,22 @@
static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x057b, 0x0000, 0x0114,
"Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN },
+ { 0x059b, 0x0030, 0x0100,
+ "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN },
{ 0x0781, 0x0001, 0x0200,
- "Sandisk ImageMate", US_SC_SCSI, US_PR_CB,
+ "Sandisk ImageMate (w/eject button)", US_SC_SCSI, US_PR_CB,
US_FL_SINGLE_LUN | US_FL_START_STOP },
{ 0x0781, 0x0002, 0x0009,
- "** SECRET DEVICE **", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN },
- { 0x04e6, 0x0002, 0x0100,
- "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ "** SECRET DEVICE **", US_SC_SCSI, US_PR_BULK,
+ US_FL_SINGLE_LUN | US_FL_IGNORE_SER },
{ 0x07af, 0x0005, 0x0100,
- "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x04e6, 0x0002, 0x0100,
+ "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x04e6, 0x0006, 0x0100,
+ "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x03f0, 0x0107, 0x0200,
+ "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0},
{ 0x0000, 0x0000, 0x0,
"", 0, 0, 0}
};
@@ -1446,8 +1457,8 @@
* defining how we should support this device, or NULL if it's not in the
* list
*/
-static struct us_unusual_dev* us_find_dev(__u16 idVendor, __u16 idProduct,
- __u16 bcdDevice)
+static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
+ u16 bcdDevice)
{
struct us_unusual_dev* ptr;
@@ -1472,14 +1483,64 @@
return ptr;
}
+/* Set up the IRQ pipe and handler
+ * Note that this function assumes that all the data in the us_data
+ * strucuture is current. This includes the ep_int field, which gives us
+ * the endpoint for the interrupt.
+ * Returns non-zero on failure, zero on success
+ */
+static int usb_stor_allocate_irq(struct us_data *ss)
+{
+ unsigned int pipe;
+ int maxp;
+ int result;
+
+ US_DEBUGP("Allocating IRQ for CBI transport\n");
+
+ /* lock access to the data structure */
+ down(&(ss->irq_urb_sem));
+
+ /* allocate the URB */
+ ss->irq_urb = usb_alloc_urb(0);
+ if (!ss->irq_urb) {
+ up(&(ss->irq_urb_sem));
+ US_DEBUGP("couldn't allocate interrupt URB");
+ return 1;
+ }
+
+ /* calculate the pipe and max packet size */
+ pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+ maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
+ if (maxp > sizeof(ss->irqbuf))
+ maxp = sizeof(ss->irqbuf);
+
+ /* fill in the URB with our data */
+ FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp,
+ CBI_irq, ss, ss->ep_int->bInterval);
+
+ /* submit the URB for processing */
+ result = usb_submit_urb(ss->irq_urb);
+ US_DEBUGP("usb_submit_urb() returns %d\n", result);
+ if (result) {
+ usb_free_urb(ss->irq_urb);
+ up(&(ss->irq_urb_sem));
+ return 2;
+ }
+
+ /* unlock the data structure and return success */
+ up(&(ss->irq_urb_sem));
+ return 0;
+}
+
/* Probe to see if a new device is actually a SCSI device */
static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
{
int i;
char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */
- char serial[USB_STOR_STRING_LEN]; /* serial number */
- GUID(guid); /* Global Unique Identifier */
+ char serial[USB_STOR_STRING_LEN]; /* serial number */
+ GUID(guid); /* Global Unique Identifier */
unsigned int flags;
struct us_unusual_dev *unusual_dev;
struct us_data *ss = NULL;
@@ -1488,12 +1549,11 @@
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
*/
- __u8 ep_in = 0;
- __u8 ep_out = 0;
- __u8 ep_int = 0;
- __u8 ep_interval = 0;
- __u8 subclass = 0;
- __u8 protocol = 0;
+ struct usb_endpoint_descriptor *ep_in = NULL;
+ struct usb_endpoint_descriptor *ep_out = NULL;
+ struct usb_endpoint_descriptor *ep_int = NULL;
+ u8 subclass = 0;
+ u8 protocol = 0;
/* the altsettting 0 on the interface we're probing */
struct usb_interface_descriptor *altsetting =
@@ -1550,23 +1610,19 @@
/* BULK in or out? */
if (altsetting->endpoint[i].bEndpointAddress &
USB_DIR_IN)
- ep_in = altsetting->endpoint[i].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
+ ep_in = &altsetting->endpoint[i];
else
- ep_out = altsetting->endpoint[i].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
+ ep_out = &altsetting->endpoint[i];
}
/* is it an interrupt endpoint? */
if ((altsetting->endpoint[i].bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
- ep_int = altsetting->endpoint[i].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- ep_interval = altsetting->endpoint[i].bInterval;
+ ep_int = &altsetting->endpoint[i];
}
}
- US_DEBUGP("Endpoints: In %d Out %d Int %d (Period %d)\n",
- ep_in, ep_out, ep_int, ep_interval);
+ US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
+ ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
/* set the interface -- STALL is an acceptable response here */
result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
@@ -1582,7 +1638,7 @@
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
- US_DEBUGP("Sanity check failed. Rejecting device.\n");
+ US_DEBUGP("Sanity check failed. Rejecting device.\n");
return NULL;
}
@@ -1591,14 +1647,14 @@
/* clear the GUID and fetch the strings */
GUID_CLEAR(guid);
if (dev->descriptor.iManufacturer)
- usb_string(dev, dev->descriptor.iManufacturer, mf,
- sizeof(mf));
+ usb_string(dev, dev->descriptor.iManufacturer,
+ mf, sizeof(mf));
if (dev->descriptor.iProduct)
- usb_string(dev, dev->descriptor.iProduct, prod,
- sizeof(prod));
- if (dev->descriptor.iSerialNumber)
- usb_string(dev, dev->descriptor.iSerialNumber, serial,
- sizeof(serial));
+ usb_string(dev, dev->descriptor.iProduct,
+ prod, sizeof(prod));
+ if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER))
+ usb_string(dev, dev->descriptor.iSerialNumber,
+ serial, sizeof(serial));
/* Create a GUID for this device */
if (dev->descriptor.iSerialNumber && serial[0]) {
@@ -1633,22 +1689,20 @@
ss->ifnum = ifnum;
ss->pusb_dev = dev;
- /* hook up the IRQ handler again */
- if (ss->protocol == US_PR_CBI) {
- /* set up so we'll wait for notification */
- init_MUTEX_LOCKED(&(ss->ip_waitq));
-
- /* set up the IRQ pipe and handler */
- US_DEBUGP("Allocating IRQ for CBI transport\n");
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, ss->ep_interval,
- (void *)ss,
- &(ss->irq_handle));
- US_DEBUGP("-- usb_request_irq returned %d\n", result);
- }
+ /* 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_int = ep_int;
+
+ /* allocate an IRQ callback if one is needed */
+ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+ return NULL;
} else {
- /* New device -- Allocate memory and initialize */
+ /* New device -- allocate memory and initialize */
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
@@ -1662,7 +1716,9 @@
/* Initialize the mutexes only when the struct is new */
init_MUTEX_LOCKED(&(ss->sleeper));
init_MUTEX_LOCKED(&(ss->notify));
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
init_MUTEX(&(ss->queue_exclusion));
+ init_MUTEX(&(ss->irq_urb_sem));
init_MUTEX(&(ss->dev_semaphore));
/* copy over the subclass and protocol data */
@@ -1671,10 +1727,13 @@
ss->flags = flags;
/* copy over the endpoint data */
- ss->ep_in = ep_in;
- ss->ep_out = ep_out;
+ 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_int = ep_int;
- ss->ep_interval = ep_interval;
/* establish the connection to the new device */
ss->ifnum = ifnum;
@@ -1739,7 +1798,7 @@
case US_SC_QIC:
ss->protocol_name = "QIC-157";
- US_DEBUGP("Sorry, device not supported. Please\n");
+ US_DEBUGP("Sorry, device not supported. Please\n");
US_DEBUGP("contact [email protected]\n");
US_DEBUGP("if you see this message.\n");
up(&us_list_semaphore);
@@ -1771,19 +1830,9 @@
}
US_DEBUGP("Protocol: %s\n", ss->protocol_name);
- if (ss->protocol == US_PR_CBI) {
- /* set up so we'll wait for notification */
- init_MUTEX_LOCKED(&(ss->ip_waitq));
-
- /* set up the IRQ pipe and handler */
- US_DEBUGP("Allocating IRQ for CBI transport\n");
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, ss->ep_interval,
- (void *)ss,
- &(ss->irq_handle));
- US_DEBUGP("-- usb_request_irq returned %d\n", result);
- }
+ /* allocate an IRQ callback if one is needed */
+ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+ return NULL;
/*
* Since this is a new device, we need to generate a scsi
@@ -1803,7 +1852,7 @@
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
- /* start up our thread */
+ /* start up our control thread */
ss->pid = kernel_thread(usb_stor_control_thread, ss,
CLONE_FS | CLONE_FILES |
CLONE_SIGHAND);
@@ -1814,10 +1863,10 @@
return NULL;
}
- /* wait for it to start */
+ /* wait for the thread to start */
down(&(ss->notify));
- /* now register - our detect function will be called */
+ /* now register - our detect function will be called */
ss->htmplt.module = THIS_MODULE;
scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
@@ -1845,7 +1894,7 @@
int result;
US_DEBUGP("storage_disconnect() called\n");
-
+
/* this is the odd case -- we disconnected but weren't using it */
if (!ss) {
US_DEBUGP("-- device was not in use\n");
@@ -1856,13 +1905,15 @@
down(&(ss->dev_semaphore));
/* release the IRQ, if we have one */
- if (ss->irq_handle) {
+ down(&(ss->irq_urb_sem));
+ if (ss->irq_urb) {
US_DEBUGP("-- releasing irq handle\n");
- result = usb_release_irq(ss->pusb_dev, ss->irq_handle,
- ss->irqpipe);
- US_DEBUGP("-- usb_release_irq() returned %d\n", result);
- ss->irq_handle = NULL;
+ result = usb_unlink_urb(ss->irq_urb);
+ ss->irq_urb = NULL;
+ US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+ usb_free_urb(ss->irq_urb);
}
+ up(&(ss->irq_urb_sem));
/* mark the device as gone */
ss->pusb_dev = NULL;
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen (who was at: [email protected])