ChangeSet 1.1079.1.3, 2003/07/14 09:48:18-07:00, stern@rowland.harvard.edu

[PATCH] USB: Implement US_FL_FIX_CAPACITY for 2.4

On Wed, 9 Jul 2003, Greg KH wrote:

> After applying all three patches here (as49, as50, as51) I get the
> following build error:
>
> In file included from usb.c:190:
> unusual_devs.h:562: `US_FL_FIX_CAPACITY' undeclared here (not in a function)
> unusual_devs.h:562: initializer element is not constant
> unusual_devs.h:562: (near initialization for `us_unusual_dev_list[72].flags')
>
> Care to send me a patch to fix this up?

This should fix everything.  It defines the new flag and adds the
corresponding implementation.


 drivers/usb/storage/protocol.c |   54 ++++++++++++++++++++++++++++++++++-------
 drivers/usb/storage/usb.h      |    1 
 2 files changed, 47 insertions(+), 8 deletions(-)


diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
--- a/drivers/usb/storage/protocol.c	Mon Jul 14 10:04:02 2003
+++ b/drivers/usb/storage/protocol.c	Mon Jul 14 10:04:02 2003
@@ -54,6 +54,22 @@
  * Helper routines
  ***********************************************************************/
 
+static void *
+find_data_location(Scsi_Cmnd *srb) {
+	if (srb->use_sg) {
+		/*
+		 * This piece of code only works if the first page is
+		 * big enough to hold more than 3 bytes -- which is
+		 * _very_ likely.
+		 */
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) srb->request_buffer;
+		return (void *) sg[0].address;
+	} else
+		return (void *) srb->request_buffer;
+}
+
 /* Fix-up the return data from an INQUIRY command to show 
  * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
  */
@@ -67,19 +83,37 @@
 
 	US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n");
 
-	/* find the location of the data */
-	if (srb->use_sg) {
-		struct scatterlist *sg;
-
-		sg = (struct scatterlist *) srb->request_buffer;
-		data_ptr = (unsigned char *) sg[0].address;
-	} else
-		data_ptr = (unsigned char *)srb->request_buffer;
+	data_ptr = find_data_location(srb);
 
 	/* Change the SCSI revision number */
 	data_ptr[2] = (data_ptr[2] & ~7) | 2;
 }
 
+/*
+ * Fix-up the return data from a READ CAPACITY command. My Feiya reader
+ * returns a value that is 1 too large.
+ */
+static void fix_read_capacity(Scsi_Cmnd *srb)
+{
+	unsigned char *dp;
+	unsigned long capacity;
+
+	/* verify that it's a READ CAPACITY command */
+	if (srb->cmnd[0] != READ_CAPACITY)
+		return;
+
+	dp = find_data_location(srb);
+
+	capacity = (dp[0]<<24) + (dp[1]<<16) + (dp[2]<<8) + (dp[3]);
+	US_DEBUGP("US: Fixing capacity: from %ld to %ld\n",
+	       capacity+1, capacity);
+	capacity--;
+	dp[0] = (capacity >> 24);
+	dp[1] = (capacity >> 16);
+	dp[2] = (capacity >> 8);
+	dp[3] = (capacity);
+}
+
 /***********************************************************************
  * Protocol routines
  ***********************************************************************/
@@ -345,6 +379,10 @@
 
 		/* fix the INQUIRY data if necessary */
 		fix_inquiry_data(srb);
+
+		/* Fix the READ CAPACITY result if necessary */
+		if (us->flags & US_FL_FIX_CAPACITY)
+			fix_read_capacity(srb);
 	}
 }
 
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Mon Jul 14 10:04:02 2003
+++ b/drivers/usb/storage/usb.h	Mon Jul 14 10:04:02 2003
@@ -102,6 +102,7 @@
 #define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
 #define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets */
 #define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing */
+#define US_FL_FIX_CAPACITY    0x00000080 /* READ CAPACITY response too big */
 
 #define USB_STOR_STRING_LEN 32
 
