patch-2.4.15 linux/drivers/usb/storage/freecom.c
Next file: linux/drivers/usb/storage/isd200.c
Previous file: linux/drivers/usb/serial/visor.h
Back to the patch index
Back to the overall index
- Lines: 293
- Date:
Tue Nov 13 09:19:41 2001
- Orig file:
v2.4.14/linux/drivers/usb/storage/freecom.c
- Orig date:
Sun Aug 12 13:28:00 2001
diff -u --recursive --new-file v2.4.14/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c
@@ -1,6 +1,6 @@
/* Driver for Freecom USB/IDE adaptor
*
- * $Id: freecom.c,v 1.15 2001/06/27 23:50:28 mdharm Exp $
+ * $Id: freecom.c,v 1.19 2001/11/11 05:42:34 mdharm Exp $
*
* Freecom v0.1:
*
@@ -81,27 +81,28 @@
/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
* register. */
-#define FCM_INT_STATUS INDEX_STAT
+#define FCM_INT_STATUS 0x02 /* INDEX_STAT */
+#define FCM_STATUS_BUSY 0x80
/* These are the packet types. The low bit indicates that this command
* should wait for an interrupt. */
-#define FCM_PACKET_ATAPI 0x21
-#define FCM_PACKET_STATUS 0x20
+#define FCM_PACKET_ATAPI 0x21
+#define FCM_PACKET_STATUS 0x20
/* Receive data from the IDE interface. The ATAPI packet has already
* waited, so the data should be immediately available. */
-#define FCM_PACKET_INPUT 0x81
+#define FCM_PACKET_INPUT 0x81
/* Send data to the IDE interface. */
-#define FCM_PACKET_OUTPUT 0x01
+#define FCM_PACKET_OUTPUT 0x01
/* Write a value to an ide register. Or the ide register to write after
* munging the address a bit. */
-#define FCM_PACKET_IDE_WRITE 0x40
-#define FCM_PACKET_IDE_READ 0xC0
+#define FCM_PACKET_IDE_WRITE 0x40
+#define FCM_PACKET_IDE_READ 0xC0
/* All packets (except for status) are 64 bytes long. */
-#define FCM_PACKET_LENGTH 64
+#define FCM_PACKET_LENGTH 64
/*
* Transfer an entire SCSI command's worth of data payload over the bulk
@@ -132,6 +133,12 @@
sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
+ US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred);
+
+ /* End this if we're done */
+ if (transfer_amount == total_transferred)
+ break;
+
/* transfer the lesser of the next buffer or the
* remaining data */
if (transfer_amount - total_transferred >=
@@ -139,10 +146,12 @@
result = usb_stor_transfer_partial(us,
sg[i].address, sg[i].length);
total_transferred += sg[i].length;
- } else
+ } else {
result = usb_stor_transfer_partial(us,
sg[i].address,
transfer_amount - total_transferred);
+ total_transferred += transfer_amount - total_transferred;
+ }
/* if we get an error, end the loop here */
if (result)
@@ -158,7 +167,7 @@
srb->result = result;
}
-
+#if 0
/* Write a value to an ide register. */
static int
freecom_ide_write (struct us_data *us, int reg, int value)
@@ -197,7 +206,9 @@
return USB_STOR_TRANSPORT_GOOD;
}
+#endif
+#if 0 /* Unused at this time */
/* Read a value from an ide register. */
static int
freecom_ide_read (struct us_data *us, int reg, int *value)
@@ -221,6 +232,8 @@
else
reg = 0x0e;
+ US_DEBUGP("IDE in request for register 0x%02x\n", reg);
+
idein->Type = FCM_PACKET_IDE_READ | reg;
memset (idein->Pad, 0, sizeof (idein->Pad));
@@ -245,16 +258,18 @@
else
return USB_STOR_TRANSPORT_ERROR;
}
+ US_DEBUGP("IDE in partial is %d\n", partial);
if (desired_length == 1)
*value = buffer[0];
else
*value = le16_to_cpu (*(__u16 *) buffer);
- US_DEBUGP("IDE in 0x%02x -> 0x%02x\n", reg, *value);
+ US_DEBUGP("IDE in 0x%02x -> 0x%02x\n", reg, *value);
return USB_STOR_TRANSPORT_GOOD;
}
+#endif
static int
freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
@@ -364,13 +379,6 @@
opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);
-#if 0
- /* Yuck, let's see if this helps us. Artificially increase the
- * length on this. */
- if (srb->cmnd[0] == 0x03 && srb->cmnd[4] == 0x12)
- srb->cmnd[4] = 0x0E;
-#endif
-
/* The ATAPI Command always goes out first. */
fcb->Type = FCM_PACKET_ATAPI | 0x00;
fcb->Timeout = 0;
@@ -412,17 +420,25 @@
US_DEBUG(pdump ((void *) fst, partial));
- /* while we haven't received the IRQ */
- while (!(fst->Status & 0x2)) {
- /* send a command to re-fetch the status */
- US_DEBUGP("Re-attempting to get status...\n");
+ /* The firmware will time-out commands after 20 seconds. Some commands
+ * can legitimately take longer than this, so we use a different
+ * command that only waits for the interrupt and then sends status,
+ * without having to send a new ATAPI command to the device.
+ *
+ * NOTE: There is some indication that a data transfer after a timeout
+ * may not work, but that is a condition that should never happen.
+ */
+ while (fst->Status & FCM_STATUS_BUSY) {
+ US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occured!\n");
+ US_DEBUGP("fst->Status is %x\n", fst->Status);
+ /* Get the status again */
fcb->Type = FCM_PACKET_STATUS;
fcb->Timeout = 0;
- memset (fcb->Atapi, 0, 12);
+ memset (fcb->Atapi, 0, sizeof(fcb->Filler));
memset (fcb->Filler, 0, sizeof (fcb->Filler));
- /* Send it out. */
+ /* Send it out. */
result = usb_stor_bulk_msg (us, fcb, opipe,
FCM_PACKET_LENGTH, &partial);
@@ -443,10 +459,12 @@
return USB_STOR_TRANSPORT_ERROR;
}
- /* actually get the status info */
- result = usb_stor_bulk_msg (us, fst, ipipe,
+ /* get the data */
+ result = usb_stor_bulk_msg (us, fst, ipipe,
FCM_PACKET_LENGTH, &partial);
+
US_DEBUGP("bar Status result %d %d\n", result, partial);
+
/* -ENOENT -- we canceled this transfer */
if (result == -ENOENT) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
@@ -470,13 +488,15 @@
US_DEBUGP("Device indicates that it has %d bytes available\n",
le16_to_cpu (fst->Count));
- /* Find the length we desire to read. It is the lesser of the SCSI
- * layer's requested length, and the length the device claims to
- * have available. */
+ /* Find the length we desire to read. */
length = usb_stor_transfer_length (srb);
US_DEBUGP("SCSI requested %d\n", length);
- if (length > le16_to_cpu (fst->Count))
- length = le16_to_cpu (fst->Count);
+
+ /* verify that this amount is legal */
+ if (length > srb->request_bufflen) {
+ length = srb->request_bufflen;
+ US_DEBUGP("Truncating request to match buffer length: %d\n", length);
+ }
/* What we do now depends on what direction the data is supposed to
* move in. */
@@ -522,7 +542,6 @@
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
-#if 1
US_DEBUGP("FCM: Waiting for status\n");
result = usb_stor_bulk_msg (us, fst, ipipe,
FCM_PACKET_LENGTH, &partial);
@@ -540,7 +559,7 @@
US_DEBUGP("Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
-#endif
+
US_DEBUGP("Transfer happy\n");
break;
@@ -570,8 +589,7 @@
int
freecom_init (struct us_data *us)
{
- int result, value;
- int counter;
+ int result;
char buffer[33];
/* Allocate a buffer for us. The upper usb transport code will
@@ -591,42 +609,29 @@
buffer[32] = '\0';
US_DEBUGP("String returned from FC init is: %s\n", buffer);
- result = freecom_ide_write (us, 0x06, 0xA0);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
- result = freecom_ide_write (us, 0x01, 0x00);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- counter = 50;
- do {
- result = freecom_ide_read (us, 0x07, &value);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
- if (counter-- < 0) {
- US_DEBUGP("Timeout in freecom");
- return USB_STOR_TRANSPORT_ERROR;
- }
- } while ((value & 0x80) != 0);
+ /* Special thanks to the people at Freecom for providing me with
+ * this "magic sequence", which they use in their Windows and MacOS
+ * drivers to make sure that all the attached perhiperals are
+ * properly reset.
+ */
- result = freecom_ide_write (us, 0x07, 0x08);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- counter = 50;
- do {
- result = freecom_ide_read (us, 0x07, &value);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
- if (counter-- < 0) {
- US_DEBUGP("Timeout in freecom");
- return USB_STOR_TRANSPORT_ERROR;
- }
- } while ((value & 0x80) != 0);
+ /* send reset */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev, 0),
+ 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
+ US_DEBUGP("result from activate reset is %d\n", result);
+
+ /* wait 250ms */
+ mdelay(250);
+
+ /* clear reset */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev, 0),
+ 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
+ US_DEBUGP("result from clear reset is %d\n", result);
- result = freecom_ide_write (us, 0x08, 0x08);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
+ /* wait 3 seconds */
+ mdelay(3 * 1000);
return USB_STOR_TRANSPORT_GOOD;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)