LWN.net Logo

Lexar SmartMedia reader support

From:  Jonathan Corbet <corbet@lwn.net>
To:  linux-usb-devel@lists.sourceforge.net
Subject:  [linux-usb-devel] [PATCH] Lexar SmartMedia reader support
Date:  Fri, 23 Aug 2002 16:37:11 -0600

I stumbled across one of those inexpensive Lexar SmartMedia card readers
the other day, and picked it up.  So what better thing to do than to blow
off no end of truly pressing concerns and spend a day making it work?

This patch is a hack.  Essentially, the bulk SCSI stuff *almost* works for
the Lexar, except for the (seemingly random) number of cruft blocks before
the real data begins.  So this driver intercepts reads on block 0 (which is
all zeros on the card) and stuffs in a little fake partition table.  All
there is to it.

This is my first time trying to do anything of any consequence with the USB
code, and I'm sure there's something really stupid here.  Be kind...:)

jon

diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/Config.in linux-2.4.19/drivers/usb/Config.in
--- linux-2.4.19-vanilla/drivers/usb/Config.in	2002-08-23 16:21:28.000000000 -0600
+++ linux-2.4.19/drivers/usb/Config.in	2002-08-23 15:42:59.000000000 -0600
@@ -45,6 +45,7 @@
       dep_mbool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
       dep_mbool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
       dep_mbool '    Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+      dep_mbool '    Lexar SmartMedia Reader' CONFIG_USB_STORAGE_LEXAR_SM $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
 
diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/storage/Makefile linux-2.4.19/drivers/usb/storage/Makefile
--- linux-2.4.19-vanilla/drivers/usb/storage/Makefile	2002-08-23 16:21:29.000000000 -0600
+++ linux-2.4.19/drivers/usb/storage/Makefile	2002-08-23 15:45:12.000000000 -0600
@@ -20,6 +20,7 @@
 usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)	+= isd200.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)   += datafab.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)  += jumpshot.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_LEXAR_SM)  += lexar-sm.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/storage/lexar-sm.c linux-2.4.19/drivers/usb/storage/lexar-sm.c
--- linux-2.4.19-vanilla/drivers/usb/storage/lexar-sm.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.4.19/drivers/usb/storage/lexar-sm.c	2002-08-23 15:58:22.000000000 -0600
@@ -0,0 +1,101 @@
+/*
+ * Hack driver for Lexar SmartMedia reader.
+ *
+ * (c) 2002 Jonathan Corbet corbet@lwn.net
+ *
+ * Distributable under the terms of the GNU GPL version 2
+ */
+
+#include <linux/genhd.h>
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include <asm/unaligned.h>
+
+struct lexar_sm_extra {
+	unsigned int sectors;
+};
+
+/*
+ * Map approximate size to beginning sector number.  Note that only 32mb
+ * and 128mb are tested - those are the cards I have.
+ */
+static struct lexar_smap {
+	unsigned int sectors;
+	unsigned int offset;
+} SMap[] =
+{
+	{ 250000, 47 },  /* 128mb */
+	{ 124000, 55 },  /*  64mb */
+	{  63000, 35 },  /*  32mb */
+	{  31000, 41 },  /*  16mb */
+	{  14000, 25 },  /*   8mb */
+	{   7000, 27 },  /*   4mb */
+	{ 0, 0 }
+};
+
+static int lexar_fake_partition(Scsi_Cmnd *srb, struct us_data *us,
+		unsigned bufflen)
+{
+	unsigned char *buffer;
+	struct partition *part;
+	unsigned int i, offset = 0, sectors;
+
+	if (!us->extra)
+		return USB_STOR_TRANSPORT_ABORTED;
+	sectors = ((struct lexar_sm_extra *) us->extra)->sectors;
+	/*
+	 * Figure out what our offset will be.
+	 */
+	for (i = 0; SMap[i].sectors > 0; i++)
+		if (SMap[i].sectors <= sectors) {
+			offset = SMap[i].offset;
+			break;
+		}
+	/*
+	 * Fake up a partition table.
+	 */
+	buffer = (unsigned char *) srb->request_buffer;
+	memset (buffer, 0, bufflen);  /* It's all junk anyway */
+	part = (struct partition *) (buffer + 0x1be);
+	put_unaligned(6, &part->sys_ind);  /* DOS partition */
+	part->start_sect = cpu_to_le32(offset);
+	part->nr_sects = cpu_to_le32(sectors - offset);
+	buffer[510] = 0x55;
+	buffer[511] = 0xAA;
+	return USB_STOR_TRANSPORT_GOOD;
+}
+		
+/*
+ * The transport function.  There is really very little we have to do
+ * here, other than get the higher levels to skip the waste area at
+ * the beginning of the card.  We could remap I/O, but I chose instead
+ * to trap reads to sector zero and return a fake partition table.
+ */
+
+int lexar_sm_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	unsigned int block;
+	int result;
+	
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+		if (block == 0) 
+			return lexar_fake_partition(srb, us, srb->bufflen);
+	}
+	result = usb_stor_Bulk_transport(srb, us);
+
+	/* Remember our capacity as it goes by */
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		unsigned int *cap = (unsigned int *) srb->request_buffer;
+		if (!us->extra)
+			us->extra = (struct lexar_sm_extra *)
+				kmalloc(sizeof(struct lexar_sm_extra), GFP_NOIO);
+		if (us->extra)
+			((struct lexar_sm_extra *)us->extra)->sectors =
+				be32_to_cpu(*cap);
+	}
+	return result;
+}
+				
diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/storage/lexar-sm.h linux-2.4.19/drivers/usb/storage/lexar-sm.h
--- linux-2.4.19-vanilla/drivers/usb/storage/lexar-sm.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.4.19/drivers/usb/storage/lexar-sm.h	2002-08-23 14:22:53.000000000 -0600
@@ -0,0 +1,6 @@
+/* Lexar SmartMedia card reader.
+ *
+ * (c) 2002 Jonathan Corbet corbet@lwn.net
+ */
+
+extern int lexar_sm_transport(Scsi_Cmnd *srb, struct us_data *us);
diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/storage/transport.h linux-2.4.19/drivers/usb/storage/transport.h
--- linux-2.4.19-vanilla/drivers/usb/storage/transport.h	2002-08-23 16:21:29.000000000 -0600
+++ linux-2.4.19/drivers/usb/storage/transport.h	2002-08-23 16:29:55.000000000 -0600
@@ -72,6 +72,10 @@
 #define US_PR_JUMPSHOT  0xf3            /* Lexar Jumpshot */
 #endif
 
+#ifdef CONFIG_USB_STORAGE_LEXAR_SM
+#define US_PR_LEXAR_SM 0xf4	        /* Lexar SmartMedia reader */
+#endif
+
 /*
  * Bulk only data structures
  */
diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/storage/unusual_devs.h linux-2.4.19/drivers/usb/storage/unusual_devs.h
--- linux-2.4.19-vanilla/drivers/usb/storage/unusual_devs.h	2002-08-23 16:21:29.000000000 -0600
+++ linux-2.4.19/drivers/usb/storage/unusual_devs.h	2002-08-23 16:11:06.000000000 -0600
@@ -292,6 +292,14 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+#ifdef CONFIG_USB_STORAGE_LEXAR_SM
+UNUSUAL_DEV( 0x5dc, 0x0002, 0x0000, 0x0001,
+		"Lexar",
+		"SM READER",
+		US_SC_SCSI, US_PR_LEXAR_SM, NULL,
+		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_IGNORE_SER ),
+#endif
+
 /* Reported by Carlos Villegas <cav@uniscope.co.jp>
  * This device needs an INQUIRY of exactly 36-bytes to function.
  * That is the only reason this entry is needed.
diff -Naur -X dontdiff linux-2.4.19-vanilla/drivers/usb/storage/usb.c linux-2.4.19/drivers/usb/storage/usb.c
--- linux-2.4.19-vanilla/drivers/usb/storage/usb.c	2002-08-23 16:21:29.000000000 -0600
+++ linux-2.4.19/drivers/usb/storage/usb.c	2002-08-23 15:44:42.000000000 -0600
@@ -75,7 +75,9 @@
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 #include "jumpshot.h"
 #endif
-
+#ifdef CONFIG_USB_STORAGE_LEXAR_SM
+#include "lexar-sm.h"
+#endif
 
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -900,6 +902,15 @@
                         break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_LEXAR_SM
+ 	        case US_PR_LEXAR_SM:
+ 		        ss->transport_name = "Lexar SM/Bulk";
+			ss->transport = lexar_sm_transport;
+           		ss->transport_reset = usb_stor_Bulk_reset;
+                       ss->max_lun = 1;
+			break;
+#endif
+
 		default:
 			ss->transport_name = "Unknown";
 			kfree(ss->current_urb);


-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Copyright © 2002, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds