aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2005-12-07 15:54:12 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2005-12-07 15:54:12 -0800
commit4bd956d2e2f9072faecd767e9b27da06b89481f0 (patch)
treefe9ce13110e1673e019ba876768a549a01f80f1f /usb
parentdc4d53eedb18d77f3782c1c8109ebca0424cf976 (diff)
downloadpatches-4bd956d2e2f9072faecd767e9b27da06b89481f0.tar.gz
w1 and usb patches
Diffstat (limited to 'usb')
-rw-r--r--usb/uhci-add-missing-memory-barriers.patch35
-rw-r--r--usb/uhci-edit-some-comments.patch273
-rw-r--r--usb/usb-driver-owner-removal.patch13
-rw-r--r--usb/usb-let-usbmon-collect-less-garbage.patch47
-rw-r--r--usb/usb-storage-add-alauda-support.patch1361
-rw-r--r--usb/usb-storage-cleanups-of-sddr09.patch264
-rw-r--r--usb/usb-storage-make-onetouch-pm-aware.patch131
-rw-r--r--usb/usb-storage-more-sddr09-cleanups.patch101
-rw-r--r--usb/usb-storage-sddr09-cleanups.patch395
-rw-r--r--usb/usb-storage-update-maintainers.patch29
10 files changed, 2637 insertions, 12 deletions
diff --git a/usb/uhci-add-missing-memory-barriers.patch b/usb/uhci-add-missing-memory-barriers.patch
new file mode 100644
index 0000000000000..da6b104098ef9
--- /dev/null
+++ b/usb/uhci-add-missing-memory-barriers.patch
@@ -0,0 +1,35 @@
+From stern@rowland.harvard.edu Wed Nov 30 14:16:10 2005
+Date: Wed, 30 Nov 2005 17:12:10 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: UHCI: add missing memory barriers
+Message-ID: <Pine.LNX.4.44L0.0511301711050.5778-100000@iolanthe.rowland.org>
+
+This patch (as617) adds a couple of memory barriers that Ben H. forgot in
+his recent suspend/resume fix.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-hcd.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.c
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.c
+@@ -710,6 +710,7 @@ static int uhci_suspend(struct usb_hcd *
+ * at the source, so we must turn off PIRQ.
+ */
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
++ mb();
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ uhci->hc_inaccessible = 1;
+ hcd->poll_rh = 0;
+@@ -731,6 +732,7 @@ static int uhci_resume(struct usb_hcd *h
+ * really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0
+ */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++ mb();
+
+ if (uhci->rh_state == UHCI_RH_RESET) /* Dead */
+ return 0;
diff --git a/usb/uhci-edit-some-comments.patch b/usb/uhci-edit-some-comments.patch
new file mode 100644
index 0000000000000..4100e1890215e
--- /dev/null
+++ b/usb/uhci-edit-some-comments.patch
@@ -0,0 +1,273 @@
+From stern@rowland.harvard.edu Wed Nov 30 14:21:45 2005
+Date: Wed, 30 Nov 2005 17:16:19 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: UHCI: edit some comments
+Message-ID: <Pine.LNX.4.44L0.0511301712200.5778-100000@iolanthe.rowland.org>
+
+
+This patch (as615b) edits a large number of comments in the uhci-hcd code,
+mainly removing excess apostrophes.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-debug.c | 12 ++++++------
+ drivers/usb/host/uhci-hcd.c | 17 +++++++++--------
+ drivers/usb/host/uhci-hcd.h | 24 ++++++++++++------------
+ drivers/usb/host/uhci-q.c | 18 +++++++++---------
+ 4 files changed, 36 insertions(+), 35 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -80,7 +80,7 @@ static inline void uhci_fill_td(struct u
+ }
+
+ /*
+- * We insert Isochronous URB's directly into the frame list at the beginning
++ * We insert Isochronous URBs directly into the frame list at the beginning
+ */
+ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
+ {
+@@ -369,7 +369,7 @@ static void uhci_append_queued_urb(struc
+ uhci_fixup_toggle(urb,
+ uhci_toggle(td_token(lltd)) ^ 1));
+
+- /* All qh's in the queue need to link to the next queue */
++ /* All qhs in the queue need to link to the next queue */
+ urbp->qh->link = eurbp->qh->link;
+
+ wmb(); /* Make sure we flush everything */
+@@ -502,7 +502,7 @@ static void uhci_destroy_urb_priv(struct
+ }
+
+ /* Check to see if the remove list is empty. Set the IOC bit */
+- /* to force an interrupt so we can remove the TD's*/
++ /* to force an interrupt so we can remove the TDs*/
+ if (list_empty(&uhci->td_remove_list))
+ uhci_set_next_interrupt(uhci);
+
+@@ -612,7 +612,7 @@ static int uhci_submit_control(struct uh
+ }
+
+ /*
+- * Build the DATA TD's
++ * Build the DATA TDs
+ */
+ while (len > 0) {
+ int pktsze = len;
+@@ -744,7 +744,7 @@ static int uhci_result_control(struct uh
+
+ urb->actual_length = 0;
+
+- /* The rest of the TD's (but the last) are data */
++ /* The rest of the TDs (but the last) are data */
+ tmp = tmp->next;
+ while (tmp != head && tmp->next != head) {
+ unsigned int ctrlstat;
+@@ -848,7 +848,7 @@ static int uhci_submit_common(struct uhc
+ status |= TD_CTRL_SPD;
+
+ /*
+- * Build the DATA TD's
++ * Build the DATA TDs
+ */
+ do { /* Allow zero length packets */
+ int pktsze = maxsze;
+@@ -1025,7 +1025,7 @@ static int isochronous_find_limits(struc
+ list_for_each_entry(up, &uhci->urb_list, urb_list) {
+ struct urb *u = up->urb;
+
+- /* look for pending URB's with identical pipe handle */
++ /* look for pending URBs with identical pipe handle */
+ if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+ (u->status == -EINPROGRESS) && (u != urb)) {
+ if (!last_urb)
+@@ -1355,7 +1355,7 @@ static void uhci_unlink_generic(struct u
+
+ uhci_delete_queued_urb(uhci, urb);
+
+- /* The interrupt loop will reclaim the QH's */
++ /* The interrupt loop will reclaim the QHs */
+ uhci_remove_qh(uhci, urbp->qh);
+ urbp->qh = NULL;
+ }
+@@ -1413,7 +1413,7 @@ static int uhci_fsbr_timeout(struct uhci
+ list_for_each_entry(td, head, list) {
+ /*
+ * Make sure we don't do the last one (since it'll have the
+- * TERM bit set) as well as we skip every so many TD's to
++ * TERM bit set) as well as we skip every so many TDs to
+ * make sure it doesn't hog the bandwidth
+ */
+ if (td->list.next != head && (count % DEPTH_INTERVAL) ==
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.c
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.c
+@@ -62,10 +62,10 @@ Alan Stern"
+
+ /*
+ * debug = 0, no debugging messages
+- * debug = 1, dump failed URB's except for stalls
+- * debug = 2, dump all failed URB's (including stalls)
++ * debug = 1, dump failed URBs except for stalls
++ * debug = 2, dump all failed URBs (including stalls)
+ * show all queues in /debug/uhci/[pci_addr]
+- * debug = 3, show all TD's in URB's when dumping
++ * debug = 3, show all TDs in URBs when dumping
+ */
+ #ifdef DEBUG
+ static int debug = 1;
+@@ -88,7 +88,7 @@ static void uhci_get_current_frame_numbe
+ #define FSBR_DELAY msecs_to_jiffies(50)
+
+ /* When we timeout an idle transfer for FSBR, we'll switch it over to */
+-/* depth first traversal. We'll do it in groups of this number of TD's */
++/* depth first traversal. We'll do it in groups of this number of TDs */
+ /* to make sure it doesn't hog all of the bandwidth */
+ #define DEPTH_INTERVAL 5
+
+@@ -728,8 +728,9 @@ static int uhci_resume(struct usb_hcd *h
+
+ dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+
+- /* We aren't in D3 state anymore, we do that even if dead as I
+- * really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0
++ /* Since we aren't in D3 any more, it's safe to set this flag
++ * even if the controller was dead. It might not even be dead
++ * any more, if the firmware or quirks code has reset it.
+ */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ mb();
+@@ -879,7 +880,7 @@ static int __init uhci_hcd_init(void)
+
+ init_failed:
+ if (kmem_cache_destroy(uhci_up_cachep))
+- warn("not all urb_priv's were freed!");
++ warn("not all urb_privs were freed!");
+
+ up_failed:
+ debugfs_remove(uhci_debugfs_root);
+@@ -897,7 +898,7 @@ static void __exit uhci_hcd_cleanup(void
+ pci_unregister_driver(&uhci_pci_driver);
+
+ if (kmem_cache_destroy(uhci_up_cachep))
+- warn("not all urb_priv's were freed!");
++ warn("not all urb_privs were freed!");
+
+ debugfs_remove(uhci_debugfs_root);
+ kfree(errbuf);
+--- gregkh-2.6.orig/drivers/usb/host/uhci-debug.c
++++ gregkh-2.6/drivers/usb/host/uhci-debug.c
+@@ -2,8 +2,8 @@
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+- * Kernel visible pointers are surrounded in []'s and bus
+- * visible pointers are surrounded in ()'s
++ * Kernel visible pointers are surrounded in []s and bus
++ * visible pointers are surrounded in ()s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2001 Johannes Erdfelt
+@@ -19,7 +19,7 @@
+
+ static struct dentry *uhci_debugfs_root = NULL;
+
+-/* Handle REALLY large printk's so we don't overflow buffers */
++/* Handle REALLY large printks so we don't overflow buffers */
+ static inline void lprintk(char *buf)
+ {
+ char *p;
+@@ -160,7 +160,7 @@ static int uhci_show_qh(struct uhci_qh *
+ }
+
+ if (active && ni > i) {
+- out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
++ out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
+ tmp = ntmp;
+ td = ntd;
+ i = ni;
+@@ -173,7 +173,7 @@ static int uhci_show_qh(struct uhci_qh *
+ if (list_empty(&urbp->queue_list) || urbp->queued)
+ goto out;
+
+- out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
++ out += sprintf(out, "%*sQueued QHs:\n", -space, "--");
+
+ head = &urbp->queue_list;
+ tmp = head->next;
+@@ -464,7 +464,7 @@ static int uhci_sprint_schedule(struct u
+ } while (tmp != head);
+ }
+
+- out += sprintf(out, "Skeleton QH's\n");
++ out += sprintf(out, "Skeleton QHs\n");
+
+ for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+ int shown = 0;
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.h
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.h
+@@ -223,10 +223,10 @@ static u32 inline td_status(struct uhci_
+ */
+
+ /*
+- * The UHCI driver places Interrupt, Control and Bulk into QH's both
+- * to group together TD's for one transfer, and also to faciliate queuing
+- * of URB's. To make it easy to insert entries into the schedule, we have
+- * a skeleton of QH's for each predefined Interrupt latency, low-speed
++ * The UHCI driver places Interrupt, Control and Bulk into QHs both
++ * to group together TDs for one transfer, and also to facilitate queuing
++ * of URBs. To make it easy to insert entries into the schedule, we have
++ * a skeleton of QHs for each predefined Interrupt latency, low-speed
+ * control, full-speed control and terminating QH (see explanation for
+ * the terminating QH below).
+ *
+@@ -257,8 +257,8 @@ static u32 inline td_status(struct uhci_
+ * reclamation.
+ *
+ * Isochronous transfers are stored before the start of the skeleton
+- * schedule and don't use QH's. While the UHCI spec doesn't forbid the
+- * use of QH's for Isochronous, it doesn't use them either. And the spec
++ * schedule and don't use QHs. While the UHCI spec doesn't forbid the
++ * use of QHs for Isochronous, it doesn't use them either. And the spec
+ * says that queues never advance on an error completion status, which
+ * makes them totally unsuitable for Isochronous transfers.
+ */
+@@ -359,7 +359,7 @@ struct uhci_hcd {
+ struct dma_pool *td_pool;
+
+ struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
+- struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
++ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */
+
+ spinlock_t lock;
+
+@@ -389,22 +389,22 @@ struct uhci_hcd {
+ unsigned long resuming_ports;
+ unsigned long ports_timeout; /* Time to stop signalling */
+
+- /* Main list of URB's currently controlled by this HC */
++ /* Main list of URBs currently controlled by this HC */
+ struct list_head urb_list;
+
+- /* List of QH's that are done, but waiting to be unlinked (race) */
++ /* List of QHs that are done, but waiting to be unlinked (race) */
+ struct list_head qh_remove_list;
+ unsigned int qh_remove_age; /* Age in frames */
+
+- /* List of TD's that are done, but waiting to be freed (race) */
++ /* List of TDs that are done, but waiting to be freed (race) */
+ struct list_head td_remove_list;
+ unsigned int td_remove_age; /* Age in frames */
+
+- /* List of asynchronously unlinked URB's */
++ /* List of asynchronously unlinked URBs */
+ struct list_head urb_remove_list;
+ unsigned int urb_remove_age; /* Age in frames */
+
+- /* List of URB's awaiting completion callback */
++ /* List of URBs awaiting completion callback */
+ struct list_head complete_list;
+
+ int rh_numports; /* Number of root-hub ports */
diff --git a/usb/usb-driver-owner-removal.patch b/usb/usb-driver-owner-removal.patch
index 017c6b73aac4e..307b54acbe95a 100644
--- a/usb/usb-driver-owner-removal.patch
+++ b/usb/usb-driver-owner-removal.patch
@@ -127,11 +127,10 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/storage/libusual.c | 1 -
drivers/usb/storage/usb.c | 1 -
drivers/usb/usb-skeleton.c | 1 -
- drivers/w1/dscore.c | 1 -
include/linux/usb.h | 4 ----
sound/usb/usbaudio.c | 1 -
sound/usb/usx2y/usbusx2y.c | 1 -
- 123 files changed, 126 deletions(-)
+ 122 files changed, 125 deletions(-)
--- gregkh-2.6.orig/drivers/usb/core/devio.c
+++ gregkh-2.6/drivers/usb/core/devio.c
@@ -1313,16 +1312,6 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
.name = "em28xx",
.probe = em28xx_usb_probe,
.disconnect = em28xx_usb_disconnect,
---- gregkh-2.6.orig/drivers/w1/dscore.c
-+++ gregkh-2.6/drivers/w1/dscore.c
-@@ -52,7 +52,6 @@ static int ds_send_control_cmd(struct ds
-
-
- static struct usb_driver ds_driver = {
-- .owner = THIS_MODULE,
- .name = "DS9490R",
- .probe = ds_probe,
- .disconnect = ds_disconnect,
--- gregkh-2.6.orig/drivers/net/irda/irda-usb.c
+++ gregkh-2.6/drivers/net/irda/irda-usb.c
@@ -1539,7 +1539,6 @@ static void irda_usb_disconnect(struct u
diff --git a/usb/usb-let-usbmon-collect-less-garbage.patch b/usb/usb-let-usbmon-collect-less-garbage.patch
new file mode 100644
index 0000000000000..a92598af3da3b
--- /dev/null
+++ b/usb/usb-let-usbmon-collect-less-garbage.patch
@@ -0,0 +1,47 @@
+From zaitcev@redhat.com Sat Dec 3 21:54:59 2005
+Date: Sat, 3 Dec 2005 21:52:10 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Subject: USB: Let usbmon collect less garbage
+Message-Id: <20051203215210.48150824.zaitcev@redhat.com>
+
+Alan Stern pointed out that (in 2.6 kernel) one successful submission results
+in one callback, even for ISO-out transfers. Thus, the silly check can be
+removed from usbmon. This reduces the amount of garbage printed in case
+of ISO and Interrupt transfers.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/mon/mon_text.c | 19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/mon/mon_text.c
++++ gregkh-2.6/drivers/usb/mon/mon_text.c
+@@ -97,19 +97,12 @@ static inline char mon_text_get_data(str
+ if (len >= DATA_MAX)
+ len = DATA_MAX;
+
+- /*
+- * Bulk is easy to shortcut reliably.
+- * XXX Other pipe types need consideration. Currently, we overdo it
+- * and collect garbage for them: better more than less.
+- */
+- if (usb_pipebulk(pipe) || usb_pipecontrol(pipe)) {
+- if (usb_pipein(pipe)) {
+- if (ev_type == 'S')
+- return '<';
+- } else {
+- if (ev_type == 'C')
+- return '>';
+- }
++ if (usb_pipein(pipe)) {
++ if (ev_type == 'S')
++ return '<';
++ } else {
++ if (ev_type == 'C')
++ return '>';
+ }
+
+ /*
diff --git a/usb/usb-storage-add-alauda-support.patch b/usb/usb-storage-add-alauda-support.patch
new file mode 100644
index 0000000000000..0d7e2c25dabe8
--- /dev/null
+++ b/usb/usb-storage-add-alauda-support.patch
@@ -0,0 +1,1361 @@
+From mdharm@multivac.one-eyed-alien.net Sun Dec 4 22:07:07 2005
+Date: Sun, 4 Dec 2005 22:02:44 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB Storage: add alauda support
+Message-ID: <20051205060244.GE15047@one-eyed-alien.net>
+Content-Disposition: inline
+
+This patch adds another usb-storage subdriver, which supports two fairly
+old dual-XD/SmartMedia reader-writers (USB1.1 devices).
+
+This driver was written by Daniel Drake <dsd@gentoo.org> -- he notes
+that he wrote this driver without specs, however a vendor-supplied GPL
+driver for the previous generation of products ("sma03") did prove to be
+quite useful, as did the sddr09 driver which also has to deal with
+low-level physical block layout on SmartMedia.
+
+The original patch has been reformed by me, as it clashed with the
+libusual patches.
+
+We really need to consolidate some of this common SmartMedia code, and
+get together with the MTD guys to share it with them as well.
+
+Signed-off-by: Daniel Drake <dsd@gentoo.org>
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/storage/Kconfig | 9
+ drivers/usb/storage/Makefile | 1
+ drivers/usb/storage/alauda.c | 1119 +++++++++++++++++++++++++++++++++++++
+ drivers/usb/storage/alauda.h | 100 +++
+ drivers/usb/storage/unusual_devs.h | 14
+ drivers/usb/storage/usb.c | 12
+ include/linux/usb_usual.h | 3
+ 7 files changed, 1258 insertions(+)
+
+--- /dev/null
++++ gregkh-2.6/drivers/usb/storage/alauda.c
+@@ -0,0 +1,1119 @@
++/*
++ * Driver for Alauda-based card readers
++ *
++ * Current development and maintenance by:
++ * (c) 2005 Daniel Drake <dsd@gentoo.org>
++ *
++ * The 'Alauda' is a chip manufacturered by RATOC for OEM use.
++ *
++ * Alauda implements a vendor-specific command set to access two media reader
++ * ports (XD, SmartMedia). This driver converts SCSI commands to the commands
++ * which are accepted by these devices.
++ *
++ * The driver was developed through reverse-engineering, with the help of the
++ * sddr09 driver which has many similarities, and with some help from the
++ * (very old) vendor-supplied GPL sma03 driver.
++ *
++ * For protocol info, see http://alauda.sourceforge.net
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2, or (at your option) any
++ * later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++
++#include "usb.h"
++#include "transport.h"
++#include "protocol.h"
++#include "debug.h"
++#include "alauda.h"
++
++#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
++#define LSB_of(s) ((s)&0xFF)
++#define MSB_of(s) ((s)>>8)
++
++#define MEDIA_PORT(us) us->srb->device->lun
++#define MEDIA_INFO(us) ((struct alauda_info *)us->extra)->port[MEDIA_PORT(us)]
++
++#define PBA_LO(pba) ((pba & 0xF) << 5)
++#define PBA_HI(pba) (pba >> 3)
++#define PBA_ZONE(pba) (pba >> 11)
++
++/*
++ * Media handling
++ */
++
++struct alauda_card_info {
++ unsigned char id; /* id byte */
++ unsigned char chipshift; /* 1<<cs bytes total capacity */
++ unsigned char pageshift; /* 1<<ps bytes in a page */
++ unsigned char blockshift; /* 1<<bs pages per block */
++ unsigned char zoneshift; /* 1<<zs blocks per zone */
++};
++
++static struct alauda_card_info alauda_card_ids[] = {
++ /* NAND flash */
++ { 0x6e, 20, 8, 4, 8}, /* 1 MB */
++ { 0xe8, 20, 8, 4, 8}, /* 1 MB */
++ { 0xec, 20, 8, 4, 8}, /* 1 MB */
++ { 0x64, 21, 8, 4, 9}, /* 2 MB */
++ { 0xea, 21, 8, 4, 9}, /* 2 MB */
++ { 0x6b, 22, 9, 4, 9}, /* 4 MB */
++ { 0xe3, 22, 9, 4, 9}, /* 4 MB */
++ { 0xe5, 22, 9, 4, 9}, /* 4 MB */
++ { 0xe6, 23, 9, 4, 10}, /* 8 MB */
++ { 0x73, 24, 9, 5, 10}, /* 16 MB */
++ { 0x75, 25, 9, 5, 10}, /* 32 MB */
++ { 0x76, 26, 9, 5, 10}, /* 64 MB */
++ { 0x79, 27, 9, 5, 10}, /* 128 MB */
++ { 0x71, 28, 9, 5, 10}, /* 256 MB */
++
++ /* MASK ROM */
++ { 0x5d, 21, 9, 4, 8}, /* 2 MB */
++ { 0xd5, 22, 9, 4, 9}, /* 4 MB */
++ { 0xd6, 23, 9, 4, 10}, /* 8 MB */
++ { 0x57, 24, 9, 4, 11}, /* 16 MB */
++ { 0x58, 25, 9, 4, 12}, /* 32 MB */
++ { 0,}
++};
++
++static struct alauda_card_info *alauda_card_find_id(unsigned char id) {
++ int i;
++
++ for (i = 0; alauda_card_ids[i].id != 0; i++)
++ if (alauda_card_ids[i].id == id)
++ return &(alauda_card_ids[i]);
++ return NULL;
++}
++
++/*
++ * ECC computation.
++ */
++
++static unsigned char parity[256];
++static unsigned char ecc2[256];
++
++static void nand_init_ecc(void) {
++ int i, j, a;
++
++ parity[0] = 0;
++ for (i = 1; i < 256; i++)
++ parity[i] = (parity[i&(i-1)] ^ 1);
++
++ for (i = 0; i < 256; i++) {
++ a = 0;
++ for (j = 0; j < 8; j++) {
++ if (i & (1<<j)) {
++ if ((j & 1) == 0)
++ a ^= 0x04;
++ if ((j & 2) == 0)
++ a ^= 0x10;
++ if ((j & 4) == 0)
++ a ^= 0x40;
++ }
++ }
++ ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
++ }
++}
++
++/* compute 3-byte ecc on 256 bytes */
++static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
++ int i, j, a;
++ unsigned char par, bit, bits[8];
++
++ par = 0;
++ for (j = 0; j < 8; j++)
++ bits[j] = 0;
++
++ /* collect 16 checksum bits */
++ for (i = 0; i < 256; i++) {
++ par ^= data[i];
++ bit = parity[data[i]];
++ for (j = 0; j < 8; j++)
++ if ((i & (1<<j)) == 0)
++ bits[j] ^= bit;
++ }
++
++ /* put 4+4+4 = 12 bits in the ecc */
++ a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
++ ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
++
++ a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
++ ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
++
++ ecc[2] = ecc2[par];
++}
++
++static int nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
++ return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
++}
++
++static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
++ memcpy(data, ecc, 3);
++}
++
++/*
++ * Alauda driver
++ */
++
++/*
++ * Forget our PBA <---> LBA mappings for a particular port
++ */
++static void alauda_free_maps (struct alauda_media_info *media_info)
++{
++ unsigned int shift = media_info->zoneshift
++ + media_info->blockshift + media_info->pageshift;
++ unsigned int num_zones = media_info->capacity >> shift;
++ unsigned int i;
++
++ if (media_info->lba_to_pba != NULL)
++ for (i = 0; i < num_zones; i++) {
++ kfree(media_info->lba_to_pba[i]);
++ media_info->lba_to_pba[i] = NULL;
++ }
++
++ if (media_info->pba_to_lba != NULL)
++ for (i = 0; i < num_zones; i++) {
++ kfree(media_info->pba_to_lba[i]);
++ media_info->pba_to_lba[i] = NULL;
++ }
++}
++
++/*
++ * Returns 2 bytes of status data
++ * The first byte describes media status, and second byte describes door status
++ */
++static int alauda_get_media_status(struct us_data *us, unsigned char *data)
++{
++ int rc;
++ unsigned char command;
++
++ if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
++ command = ALAUDA_GET_XD_MEDIA_STATUS;
++ else
++ command = ALAUDA_GET_SM_MEDIA_STATUS;
++
++ rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
++ command, 0xc0, 0, 1, data, 2);
++
++ US_DEBUGP("alauda_get_media_status: Media status %02X %02X\n",
++ data[0], data[1]);
++
++ return rc;
++}
++
++/*
++ * Clears the "media was changed" bit so that we know when it changes again
++ * in the future.
++ */
++static int alauda_ack_media(struct us_data *us)
++{
++ unsigned char command;
++
++ if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
++ command = ALAUDA_ACK_XD_MEDIA_CHANGE;
++ else
++ command = ALAUDA_ACK_SM_MEDIA_CHANGE;
++
++ return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
++ command, 0x40, 0, 1, NULL, 0);
++}
++
++/*
++ * Retrieves a 4-byte media signature, which indicates manufacturer, capacity,
++ * and some other details.
++ */
++static int alauda_get_media_signature(struct us_data *us, unsigned char *data)
++{
++ unsigned char command;
++
++ if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
++ command = ALAUDA_GET_XD_MEDIA_SIG;
++ else
++ command = ALAUDA_GET_SM_MEDIA_SIG;
++
++ return usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
++ command, 0xc0, 0, 0, data, 4);
++}
++
++/*
++ * Resets the media status (but not the whole device?)
++ */
++static int alauda_reset_media(struct us_data *us)
++{
++ unsigned char *command = us->iobuf;
++
++ memset(command, 0, 9);
++ command[0] = ALAUDA_BULK_CMD;
++ command[1] = ALAUDA_BULK_RESET_MEDIA;
++ command[8] = MEDIA_PORT(us);
++
++ return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ command, 9, NULL);
++}
++
++/*
++ * Examines the media and deduces capacity, etc.
++ */
++static int alauda_init_media(struct us_data *us)
++{
++ unsigned char *data = us->iobuf;
++ int ready = 0;
++ struct alauda_card_info *media_info;
++ unsigned int num_zones;
++
++ while (ready == 0) {
++ msleep(20);
++
++ if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD)
++ return USB_STOR_TRANSPORT_ERROR;
++
++ if (data[0] & 0x10)
++ ready = 1;
++ }
++
++ US_DEBUGP("alauda_init_media: We are ready for action!\n");
++
++ if (alauda_ack_media(us) != USB_STOR_XFER_GOOD)
++ return USB_STOR_TRANSPORT_ERROR;
++
++ msleep(10);
++
++ if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD)
++ return USB_STOR_TRANSPORT_ERROR;
++
++ if (data[0] != 0x14) {
++ US_DEBUGP("alauda_init_media: Media not ready after ack\n");
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++
++ if (alauda_get_media_signature(us, data) != USB_STOR_XFER_GOOD)
++ return USB_STOR_TRANSPORT_ERROR;
++
++ US_DEBUGP("alauda_init_media: Media signature: %02X %02X %02X %02X\n",
++ data[0], data[1], data[2], data[3]);
++ media_info = alauda_card_find_id(data[1]);
++ if (media_info == NULL) {
++ printk("alauda_init_media: Unrecognised media signature: "
++ "%02X %02X %02X %02X\n",
++ data[0], data[1], data[2], data[3]);
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++
++ MEDIA_INFO(us).capacity = 1 << media_info->chipshift;
++ US_DEBUGP("Found media with capacity: %ldMB\n",
++ MEDIA_INFO(us).capacity >> 20);
++
++ MEDIA_INFO(us).pageshift = media_info->pageshift;
++ MEDIA_INFO(us).blockshift = media_info->blockshift;
++ MEDIA_INFO(us).zoneshift = media_info->zoneshift;
++
++ MEDIA_INFO(us).pagesize = 1 << media_info->pageshift;
++ MEDIA_INFO(us).blocksize = 1 << media_info->blockshift;
++ MEDIA_INFO(us).zonesize = 1 << media_info->zoneshift;
++
++ MEDIA_INFO(us).uzonesize = ((1 << media_info->zoneshift) / 128) * 125;
++ MEDIA_INFO(us).blockmask = MEDIA_INFO(us).blocksize - 1;
++
++ num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
++ + MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
++ MEDIA_INFO(us).pba_to_lba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
++ MEDIA_INFO(us).lba_to_pba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
++
++ if (alauda_reset_media(us) != USB_STOR_XFER_GOOD)
++ return USB_STOR_TRANSPORT_ERROR;
++
++ return USB_STOR_TRANSPORT_GOOD;
++}
++
++/*
++ * Examines the media status and does the right thing when the media has gone,
++ * appeared, or changed.
++ */
++static int alauda_check_media(struct us_data *us)
++{
++ struct alauda_info *info = (struct alauda_info *) us->extra;
++ unsigned char status[2];
++ int rc;
++
++ rc = alauda_get_media_status(us, status);
++
++ /* Check for no media or door open */
++ if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)
++ || ((status[1] & 0x01) == 0)) {
++ US_DEBUGP("alauda_check_media: No media, or door open\n");
++ alauda_free_maps(&MEDIA_INFO(us));
++ info->sense_key = 0x02;
++ info->sense_asc = 0x3A;
++ info->sense_ascq = 0x00;
++ return USB_STOR_TRANSPORT_FAILED;
++ }
++
++ /* Check for media change */
++ if (status[0] & 0x08) {
++ US_DEBUGP("alauda_check_media: Media change detected\n");
++ alauda_free_maps(&MEDIA_INFO(us));
++ alauda_init_media(us);
++
++ info->sense_key = UNIT_ATTENTION;
++ info->sense_asc = 0x28;
++ info->sense_ascq = 0x00;
++ return USB_STOR_TRANSPORT_FAILED;
++ }
++
++ return USB_STOR_TRANSPORT_GOOD;
++}
++
++/*
++ * Checks the status from the 2nd status register
++ * Returns 3 bytes of status data, only the first is known
++ */
++static int alauda_check_status2(struct us_data *us)
++{
++ int rc;
++ unsigned char command[] = {
++ ALAUDA_BULK_CMD, ALAUDA_BULK_GET_STATUS2,
++ 0, 0, 0, 0, 3, 0, MEDIA_PORT(us)
++ };
++ unsigned char data[3];
++
++ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ command, 9, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ data, 3, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ US_DEBUGP("alauda_check_status2: %02X %02X %02X\n", data[0], data[1], data[2]);
++ if (data[0] & ALAUDA_STATUS_ERROR)
++ return USB_STOR_XFER_ERROR;
++
++ return USB_STOR_XFER_GOOD;
++}
++
++/*
++ * Gets the redundancy data for the first page of a PBA
++ * Returns 16 bytes.
++ */
++static int alauda_get_redu_data(struct us_data *us, u16 pba, unsigned char *data)
++{
++ int rc;
++ unsigned char command[] = {
++ ALAUDA_BULK_CMD, ALAUDA_BULK_GET_REDU_DATA,
++ PBA_HI(pba), PBA_ZONE(pba), 0, PBA_LO(pba), 0, 0, MEDIA_PORT(us)
++ };
++
++ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ command, 9, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ data, 16, NULL);
++}
++
++/*
++ * Finds the first unused PBA in a zone
++ * Returns the absolute PBA of an unused PBA, or 0 if none found.
++ */
++static u16 alauda_find_unused_pba(struct alauda_media_info *info,
++ unsigned int zone)
++{
++ u16 *pba_to_lba = info->pba_to_lba[zone];
++ unsigned int i;
++
++ for (i = 0; i < info->zonesize; i++)
++ if (pba_to_lba[i] == UNDEF)
++ return (zone << info->zoneshift) + i;
++
++ return 0;
++}
++
++/*
++ * Reads the redundancy data for all PBA's in a zone
++ * Produces lba <--> pba mappings
++ */
++static int alauda_read_map(struct us_data *us, unsigned int zone)
++{
++ unsigned char *data = us->iobuf;
++ int result;
++ int i, j;
++ unsigned int zonesize = MEDIA_INFO(us).zonesize;
++ unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
++ unsigned int lba_offset, lba_real, blocknum;
++ unsigned int zone_base_lba = zone * uzonesize;
++ unsigned int zone_base_pba = zone * zonesize;
++ u16 *lba_to_pba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
++ u16 *pba_to_lba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
++ if (lba_to_pba == NULL || pba_to_lba == NULL) {
++ result = USB_STOR_TRANSPORT_ERROR;
++ goto error;
++ }
++
++ US_DEBUGP("alauda_read_map: Mapping blocks for zone %d\n", zone);
++
++ /* 1024 PBA's per zone */
++ for (i = 0; i < zonesize; i++)
++ lba_to_pba[i] = pba_to_lba[i] = UNDEF;
++
++ for (i = 0; i < zonesize; i++) {
++ blocknum = zone_base_pba + i;
++
++ result = alauda_get_redu_data(us, blocknum, data);
++ if (result != USB_STOR_XFER_GOOD) {
++ result = USB_STOR_TRANSPORT_ERROR;
++ goto error;
++ }
++
++ /* special PBAs have control field 0^16 */
++ for (j = 0; j < 16; j++)
++ if (data[j] != 0)
++ goto nonz;
++ pba_to_lba[i] = UNUSABLE;
++ US_DEBUGP("alauda_read_map: PBA %d has no logical mapping\n", blocknum);
++ continue;
++
++ nonz:
++ /* unwritten PBAs have control field FF^16 */
++ for (j = 0; j < 16; j++)
++ if (data[j] != 0xff)
++ goto nonff;
++ continue;
++
++ nonff:
++ /* normal PBAs start with six FFs */
++ if (j < 6) {
++ US_DEBUGP("alauda_read_map: PBA %d has no logical mapping: "
++ "reserved area = %02X%02X%02X%02X "
++ "data status %02X block status %02X\n",
++ blocknum, data[0], data[1], data[2], data[3],
++ data[4], data[5]);
++ pba_to_lba[i] = UNUSABLE;
++ continue;
++ }
++
++ if ((data[6] >> 4) != 0x01) {
++ US_DEBUGP("alauda_read_map: PBA %d has invalid address "
++ "field %02X%02X/%02X%02X\n",
++ blocknum, data[6], data[7], data[11], data[12]);
++ pba_to_lba[i] = UNUSABLE;
++ continue;
++ }
++
++ /* check even parity */
++ if (parity[data[6] ^ data[7]]) {
++ printk("alauda_read_map: Bad parity in LBA for block %d"
++ " (%02X %02X)\n", i, data[6], data[7]);
++ pba_to_lba[i] = UNUSABLE;
++ continue;
++ }
++
++ lba_offset = short_pack(data[7], data[6]);
++ lba_offset = (lba_offset & 0x07FF) >> 1;
++ lba_real = lba_offset + zone_base_lba;
++
++ /*
++ * Every 1024 physical blocks ("zone"), the LBA numbers
++ * go back to zero, but are within a higher block of LBA's.
++ * Also, there is a maximum of 1000 LBA's per zone.
++ * In other words, in PBA 1024-2047 you will find LBA 0-999
++ * which are really LBA 1000-1999. This allows for 24 bad
++ * or special physical blocks per zone.
++ */
++
++ if (lba_offset >= uzonesize) {
++ printk("alauda_read_map: Bad low LBA %d for block %d\n",
++ lba_real, blocknum);
++ continue;
++ }
++
++ if (lba_to_pba[lba_offset] != UNDEF) {
++ printk("alauda_read_map: LBA %d seen for PBA %d and %d\n",
++ lba_real, lba_to_pba[lba_offset], blocknum);
++ continue;
++ }
++
++ pba_to_lba[i] = lba_real;
++ lba_to_pba[lba_offset] = blocknum;
++ continue;
++ }
++
++ MEDIA_INFO(us).lba_to_pba[zone] = lba_to_pba;
++ MEDIA_INFO(us).pba_to_lba[zone] = pba_to_lba;
++ result = 0;
++ goto out;
++
++error:
++ kfree(lba_to_pba);
++ kfree(pba_to_lba);
++out:
++ return result;
++}
++
++/*
++ * Checks to see whether we have already mapped a certain zone
++ * If we haven't, the map is generated
++ */
++static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone)
++{
++ if (MEDIA_INFO(us).lba_to_pba[zone] == NULL
++ || MEDIA_INFO(us).pba_to_lba[zone] == NULL)
++ alauda_read_map(us, zone);
++}
++
++/*
++ * Erases an entire block
++ */
++static int alauda_erase_block(struct us_data *us, u16 pba)
++{
++ int rc;
++ unsigned char command[] = {
++ ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
++ PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, MEDIA_PORT(us)
++ };
++ unsigned char buf[2];
++
++ US_DEBUGP("alauda_erase_block: Erasing PBA %d\n", pba);
++
++ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ command, 9, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ buf, 2, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ US_DEBUGP("alauda_erase_block: Erase result: %02X %02X\n",
++ buf[0], buf[1]);
++ return rc;
++}
++
++/*
++ * Reads data from a certain offset page inside a PBA, including interleaved
++ * redundancy data. Returns (pagesize+64)*pages bytes in data.
++ */
++static int alauda_read_block_raw(struct us_data *us, u16 pba,
++ unsigned int page, unsigned int pages, unsigned char *data)
++{
++ int rc;
++ unsigned char command[] = {
++ ALAUDA_BULK_CMD, ALAUDA_BULK_READ_BLOCK, PBA_HI(pba),
++ PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us)
++ };
++
++ US_DEBUGP("alauda_read_block: pba %d page %d count %d\n",
++ pba, page, pages);
++
++ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ command, 9, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ data, (MEDIA_INFO(us).pagesize + 64) * pages, NULL);
++}
++
++/*
++ * Reads data from a certain offset page inside a PBA, excluding redundancy
++ * data. Returns pagesize*pages bytes in data. Note that data must be big enough
++ * to hold (pagesize+64)*pages bytes of data, but you can ignore those 'extra'
++ * trailing bytes outside this function.
++ */
++static int alauda_read_block(struct us_data *us, u16 pba,
++ unsigned int page, unsigned int pages, unsigned char *data)
++{
++ int i, rc;
++ unsigned int pagesize = MEDIA_INFO(us).pagesize;
++
++ rc = alauda_read_block_raw(us, pba, page, pages, data);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ /* Cut out the redundancy data */
++ for (i = 0; i < pages; i++) {
++ int dest_offset = i * pagesize;
++ int src_offset = i * (pagesize + 64);
++ memmove(data + dest_offset, data + src_offset, pagesize);
++ }
++
++ return rc;
++}
++
++/*
++ * Writes an entire block of data and checks status after write.
++ * Redundancy data must be already included in data. Data should be
++ * (pagesize+64)*blocksize bytes in length.
++ */
++static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data)
++{
++ int rc;
++ struct alauda_info *info = (struct alauda_info *) us->extra;
++ unsigned char command[] = {
++ ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_BLOCK, PBA_HI(pba),
++ PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us)
++ };
++
++ US_DEBUGP("alauda_write_block: pba %d\n", pba);
++
++ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ command, 9, NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ rc = usb_stor_bulk_transfer_buf(us, info->wr_ep, data,
++ (MEDIA_INFO(us).pagesize + 64) * MEDIA_INFO(us).blocksize,
++ NULL);
++ if (rc != USB_STOR_XFER_GOOD)
++ return rc;
++
++ return alauda_check_status2(us);
++}
++
++/*
++ * Write some data to a specific LBA.
++ */
++static int alauda_write_lba(struct us_data *us, u16 lba,
++ unsigned int page, unsigned int pages,
++ unsigned char *ptr, unsigned char *blockbuffer)
++{
++ u16 pba, lbap, new_pba;
++ unsigned char *bptr, *cptr, *xptr;
++ unsigned char ecc[3];
++ int i, result;
++ unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
++ unsigned int zonesize = MEDIA_INFO(us).zonesize;
++ unsigned int pagesize = MEDIA_INFO(us).pagesize;
++ unsigned int blocksize = MEDIA_INFO(us).blocksize;
++ unsigned int lba_offset = lba % uzonesize;
++ unsigned int new_pba_offset;
++ unsigned int zone = lba / uzonesize;
++
++ alauda_ensure_map_for_zone(us, zone);
++
++ pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
++ if (pba == 1) {
++ /* Maybe it is impossible to write to PBA 1.
++ Fake success, but don't do anything. */
++ printk("alauda_write_lba: avoid writing to pba 1\n");
++ return USB_STOR_TRANSPORT_GOOD;
++ }
++
++ new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone);
++ if (!new_pba) {
++ printk("alauda_write_lba: Out of unused blocks\n");
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++
++ /* read old contents */
++ if (pba != UNDEF) {
++ result = alauda_read_block_raw(us, pba, 0,
++ blocksize, blockbuffer);
++ if (result != USB_STOR_XFER_GOOD)
++ return result;
++ } else {
++ memset(blockbuffer, 0, blocksize * (pagesize + 64));
++ }
++
++ lbap = (lba_offset << 1) | 0x1000;
++ if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
++ lbap ^= 1;
++
++ /* check old contents and fill lba */
++ for (i = 0; i < blocksize; i++) {
++ bptr = blockbuffer + (i * (pagesize + 64));
++ cptr = bptr + pagesize;
++ nand_compute_ecc(bptr, ecc);
++ if (!nand_compare_ecc(cptr+13, ecc)) {
++ US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
++ i, pba);
++ nand_store_ecc(cptr+13, ecc);
++ }
++ nand_compute_ecc(bptr + (pagesize / 2), ecc);
++ if (!nand_compare_ecc(cptr+8, ecc)) {
++ US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
++ i, pba);
++ nand_store_ecc(cptr+8, ecc);
++ }
++ cptr[6] = cptr[11] = MSB_of(lbap);
++ cptr[7] = cptr[12] = LSB_of(lbap);
++ }
++
++ /* copy in new stuff and compute ECC */
++ xptr = ptr;
++ for (i = page; i < page+pages; i++) {
++ bptr = blockbuffer + (i * (pagesize + 64));
++ cptr = bptr + pagesize;
++ memcpy(bptr, xptr, pagesize);
++ xptr += pagesize;
++ nand_compute_ecc(bptr, ecc);
++ nand_store_ecc(cptr+13, ecc);
++ nand_compute_ecc(bptr + (pagesize / 2), ecc);
++ nand_store_ecc(cptr+8, ecc);
++ }
++
++ result = alauda_write_block(us, new_pba, blockbuffer);
++ if (result != USB_STOR_XFER_GOOD)
++ return result;
++
++ new_pba_offset = new_pba - (zone * zonesize);
++ MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba;
++ MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba;
++ US_DEBUGP("alauda_write_lba: Remapped LBA %d to PBA %d\n",
++ lba, new_pba);
++
++ if (pba != UNDEF) {
++ unsigned int pba_offset = pba - (zone * zonesize);
++ result = alauda_erase_block(us, pba);
++ if (result != USB_STOR_XFER_GOOD)
++ return result;
++ MEDIA_INFO(us).pba_to_lba[zone][pba_offset] = UNDEF;
++ }
++
++ return USB_STOR_TRANSPORT_GOOD;
++}
++
++/*
++ * Read data from a specific sector address
++ */
++static int alauda_read_data(struct us_data *us, unsigned long address,
++ unsigned int sectors)
++{
++ unsigned char *buffer;
++ u16 lba, max_lba;
++ unsigned int page, len, index, offset;
++ unsigned int blockshift = MEDIA_INFO(us).blockshift;
++ unsigned int pageshift = MEDIA_INFO(us).pageshift;
++ unsigned int blocksize = MEDIA_INFO(us).blocksize;
++ unsigned int pagesize = MEDIA_INFO(us).pagesize;
++ unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
++ int result;
++
++ /*
++ * Since we only read in one block at a time, we have to create
++ * a bounce buffer and move the data a piece at a time between the
++ * bounce buffer and the actual transfer buffer.
++ * We make this buffer big enough to hold temporary redundancy data,
++ * which we use when reading the data blocks.
++ */
++
++ len = min(sectors, blocksize) * (pagesize + 64);
++ buffer = kmalloc(len, GFP_NOIO);
++ if (buffer == NULL) {
++ printk("alauda_read_data: Out of memory\n");
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++
++ /* Figure out the initial LBA and page */
++ lba = address >> blockshift;
++ page = (address & MEDIA_INFO(us).blockmask);
++ max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift);
++
++ result = USB_STOR_TRANSPORT_GOOD;
++ index = offset = 0;
++
++ while (sectors > 0) {
++ unsigned int zone = lba / uzonesize; /* integer division */
++ unsigned int lba_offset = lba - (zone * uzonesize);
++ unsigned int pages;
++ u16 pba;
++ alauda_ensure_map_for_zone(us, zone);
++
++ /* Not overflowing capacity? */
++ if (lba >= max_lba) {
++ US_DEBUGP("Error: Requested lba %u exceeds "
++ "maximum %u\n", lba, max_lba);
++ result = USB_STOR_TRANSPORT_ERROR;
++ break;
++ }
++
++ /* Find number of pages we can read in this block */
++ pages = min(sectors, blocksize - page);
++ len = pages << pageshift;
++
++ /* Find where this lba lives on disk */
++ pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
++
++ if (pba == UNDEF) { /* this lba was never written */
++ US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
++ pages, lba, page);
++
++ /* This is not really an error. It just means
++ that the block has never been written.
++ Instead of returning USB_STOR_TRANSPORT_ERROR
++ it is better to return all zero data. */
++
++ memset(buffer, 0, len);
++ } else {
++ US_DEBUGP("Read %d pages, from PBA %d"
++ " (LBA %d) page %d\n",
++ pages, pba, lba, page);
++
++ result = alauda_read_block(us, pba, page, pages, buffer);
++ if (result != USB_STOR_TRANSPORT_GOOD)
++ break;
++ }
++
++ /* Store the data in the transfer buffer */
++ usb_stor_access_xfer_buf(buffer, len, us->srb,
++ &index, &offset, TO_XFER_BUF);
++
++ page = 0;
++ lba++;
++ sectors -= pages;
++ }
++
++ kfree(buffer);
++ return result;
++}
++
++/*
++ * Write data to a specific sector address
++ */
++static int alauda_write_data(struct us_data *us, unsigned long address,
++ unsigned int sectors)
++{
++ unsigned char *buffer, *blockbuffer;
++ unsigned int page, len, index, offset;
++ unsigned int blockshift = MEDIA_INFO(us).blockshift;
++ unsigned int pageshift = MEDIA_INFO(us).pageshift;
++ unsigned int blocksize = MEDIA_INFO(us).blocksize;
++ unsigned int pagesize = MEDIA_INFO(us).pagesize;
++ u16 lba, max_lba;
++ int result;
++
++ /*
++ * Since we don't write the user data directly to the device,
++ * we have to create a bounce buffer and move the data a piece
++ * at a time between the bounce buffer and the actual transfer buffer.
++ */
++
++ len = min(sectors, blocksize) * pagesize;
++ buffer = kmalloc(len, GFP_NOIO);
++ if (buffer == NULL) {
++ printk("alauda_write_data: Out of memory\n");
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++
++ /*
++ * We also need a temporary block buffer, where we read in the old data,
++ * overwrite parts with the new data, and manipulate the redundancy data
++ */
++ blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO);
++ if (blockbuffer == NULL) {
++ printk("alauda_write_data: Out of memory\n");
++ kfree(buffer);
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++
++ /* Figure out the initial LBA and page */
++ lba = address >> blockshift;
++ page = (address & MEDIA_INFO(us).blockmask);
++ max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift);
++
++ result = USB_STOR_TRANSPORT_GOOD;
++ index = offset = 0;
++
++ while (sectors > 0) {
++ /* Write as many sectors as possible in this block */
++ unsigned int pages = min(sectors, blocksize - page);
++ len = pages << pageshift;
++
++ /* Not overflowing capacity? */
++ if (lba >= max_lba) {
++ US_DEBUGP("alauda_write_data: Requested lba %u exceeds "
++ "maximum %u\n", lba, max_lba);
++ result = USB_STOR_TRANSPORT_ERROR;
++ break;
++ }
++
++ /* Get the data from the transfer buffer */
++ usb_stor_access_xfer_buf(buffer, len, us->srb,
++ &index, &offset, FROM_XFER_BUF);
++
++ result = alauda_write_lba(us, lba, page, pages, buffer,
++ blockbuffer);
++ if (result != USB_STOR_TRANSPORT_GOOD)
++ break;
++
++ page = 0;
++ lba++;
++ sectors -= pages;
++ }
++
++ kfree(buffer);
++ kfree(blockbuffer);
++ return result;
++}
++
++/*
++ * Our interface with the rest of the world
++ */
++
++static void alauda_info_destructor(void *extra)
++{
++ struct alauda_info *info = (struct alauda_info *) extra;
++ int port;
++
++ if (!info)
++ return;
++
++ for (port = 0; port < 2; port++) {
++ struct alauda_media_info *media_info = &info->port[port];
++
++ alauda_free_maps(media_info);
++ kfree(media_info->lba_to_pba);
++ kfree(media_info->pba_to_lba);
++ }
++}
++
++/*
++ * Initialize alauda_info struct and find the data-write endpoint
++ */
++int init_alauda(struct us_data *us)
++{
++ struct alauda_info *info;
++ struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;
++ nand_init_ecc();
++
++ us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO);
++ if (!us->extra) {
++ US_DEBUGP("init_alauda: Gah! Can't allocate storage for"
++ "alauda info struct!\n");
++ return USB_STOR_TRANSPORT_ERROR;
++ }
++ info = (struct alauda_info *) us->extra;
++ us->extra_destructor = alauda_info_destructor;
++
++ info->wr_ep = usb_sndbulkpipe(us->pusb_dev,
++ altsetting->endpoint[0].desc.bEndpointAddress
++ & USB_ENDPOINT_NUMBER_MASK);
++
++ return USB_STOR_TRANSPORT_GOOD;
++}
++
++int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
++{
++ int rc;
++ struct alauda_info *info = (struct alauda_info *) us->extra;
++ unsigned char *ptr = us->iobuf;
++ static unsigned char inquiry_response[36] = {
++ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
++ };
++
++ if (srb->cmnd[0] == INQUIRY) {
++ US_DEBUGP("alauda_transport: INQUIRY. "
++ "Returning bogus response.\n");
++ memcpy(ptr, inquiry_response, sizeof(inquiry_response));
++ fill_inquiry_response(us, ptr, 36);
++ return USB_STOR_TRANSPORT_GOOD;
++ }
++
++ if (srb->cmnd[0] == TEST_UNIT_READY) {
++ US_DEBUGP("alauda_transport: TEST_UNIT_READY.\n");
++ return alauda_check_media(us);
++ }
++
++ if (srb->cmnd[0] == READ_CAPACITY) {
++ unsigned int num_zones;
++ unsigned long capacity;
++
++ rc = alauda_check_media(us);
++ if (rc != USB_STOR_TRANSPORT_GOOD)
++ return rc;
++
++ num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
++ + MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
++
++ capacity = num_zones * MEDIA_INFO(us).uzonesize
++ * MEDIA_INFO(us).blocksize;
++
++ /* Report capacity and page size */
++ ((__be32 *) ptr)[0] = cpu_to_be32(capacity - 1);
++ ((__be32 *) ptr)[1] = cpu_to_be32(512);
++
++ usb_stor_set_xfer_buf(ptr, 8, srb);
++ return USB_STOR_TRANSPORT_GOOD;
++ }
++
++ if (srb->cmnd[0] == READ_10) {
++ unsigned int page, pages;
++
++ rc = alauda_check_media(us);
++ if (rc != USB_STOR_TRANSPORT_GOOD)
++ return rc;
++
++ page = short_pack(srb->cmnd[3], srb->cmnd[2]);
++ page <<= 16;
++ page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
++ pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
++
++ US_DEBUGP("alauda_transport: READ_10: page %d pagect %d\n",
++ page, pages);
++
++ return alauda_read_data(us, page, pages);
++ }
++
++ if (srb->cmnd[0] == WRITE_10) {
++ unsigned int page, pages;
++
++ rc = alauda_check_media(us);
++ if (rc != USB_STOR_TRANSPORT_GOOD)
++ return rc;
++
++ page = short_pack(srb->cmnd[3], srb->cmnd[2]);
++ page <<= 16;
++ page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
++ pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
++
++ US_DEBUGP("alauda_transport: WRITE_10: page %d pagect %d\n",
++ page, pages);
++
++ return alauda_write_data(us, page, pages);
++ }
++
++ if (srb->cmnd[0] == REQUEST_SENSE) {
++ US_DEBUGP("alauda_transport: REQUEST_SENSE.\n");
++
++ memset(ptr, 0, 18);
++ ptr[0] = 0xF0;
++ ptr[2] = info->sense_key;
++ ptr[7] = 11;
++ ptr[12] = info->sense_asc;
++ ptr[13] = info->sense_ascq;
++ usb_stor_set_xfer_buf(ptr, 18, srb);
++
++ return USB_STOR_TRANSPORT_GOOD;
++ }
++
++ if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
++ /* sure. whatever. not like we can stop the user from popping
++ the media out of the device (no locking doors, etc) */
++ return USB_STOR_TRANSPORT_GOOD;
++ }
++
++ US_DEBUGP("alauda_transport: Gah! Unknown command: %d (0x%x)\n",
++ srb->cmnd[0], srb->cmnd[0]);
++ info->sense_key = 0x05;
++ info->sense_asc = 0x20;
++ info->sense_ascq = 0x00;
++ return USB_STOR_TRANSPORT_FAILED;
++}
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/storage/alauda.h
+@@ -0,0 +1,100 @@
++/*
++ * Driver for Alauda-based card readers
++ *
++ * Current development and maintenance by:
++ * (c) 2005 Daniel Drake <dsd@gentoo.org>
++ *
++ * See alauda.c for more explanation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2, or (at your option) any
++ * later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef _USB_ALAUDA_H
++#define _USB_ALAUDA_H
++
++/*
++ * Status bytes
++ */
++#define ALAUDA_STATUS_ERROR 0x01
++#define ALAUDA_STATUS_READY 0x40
++
++/*
++ * Control opcodes (for request field)
++ */
++#define ALAUDA_GET_XD_MEDIA_STATUS 0x08
++#define ALAUDA_GET_SM_MEDIA_STATUS 0x98
++#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a
++#define ALAUDA_ACK_SM_MEDIA_CHANGE 0x9a
++#define ALAUDA_GET_XD_MEDIA_SIG 0x86
++#define ALAUDA_GET_SM_MEDIA_SIG 0x96
++
++/*
++ * Bulk command identity (byte 0)
++ */
++#define ALAUDA_BULK_CMD 0x40
++
++/*
++ * Bulk opcodes (byte 1)
++ */
++#define ALAUDA_BULK_GET_REDU_DATA 0x85
++#define ALAUDA_BULK_READ_BLOCK 0x94
++#define ALAUDA_BULK_ERASE_BLOCK 0xa3
++#define ALAUDA_BULK_WRITE_BLOCK 0xb4
++#define ALAUDA_BULK_GET_STATUS2 0xb7
++#define ALAUDA_BULK_RESET_MEDIA 0xe0
++
++/*
++ * Port to operate on (byte 8)
++ */
++#define ALAUDA_PORT_XD 0x00
++#define ALAUDA_PORT_SM 0x01
++
++/*
++ * LBA and PBA are unsigned ints. Special values.
++ */
++#define UNDEF 0xffff
++#define SPARE 0xfffe
++#define UNUSABLE 0xfffd
++
++int init_alauda(struct us_data *us);
++int alauda_transport(struct scsi_cmnd *srb, struct us_data *us);
++
++struct alauda_media_info {
++ unsigned long capacity; /* total media size in bytes */
++ unsigned int pagesize; /* page size in bytes */
++ unsigned int blocksize; /* number of pages per block */
++ unsigned int uzonesize; /* number of usable blocks per zone */
++ unsigned int zonesize; /* number of blocks per zone */
++ unsigned int blockmask; /* mask to get page from address */
++
++ unsigned char pageshift;
++ unsigned char blockshift;
++ unsigned char zoneshift;
++
++ u16 **lba_to_pba; /* logical to physical block map */
++ u16 **pba_to_lba; /* physical to logical block map */
++};
++
++struct alauda_info {
++ struct alauda_media_info port[2];
++ int wr_ep; /* endpoint to write data out of */
++
++ unsigned char sense_key;
++ unsigned long sense_asc; /* additional sense code */
++ unsigned long sense_ascq; /* additional sense code qualifier */
++};
++
++#endif
++
+--- gregkh-2.6.orig/drivers/usb/storage/Kconfig
++++ gregkh-2.6/drivers/usb/storage/Kconfig
+@@ -112,6 +112,15 @@ config USB_STORAGE_JUMPSHOT
+ Say Y here to include additional code to support the Lexar Jumpshot
+ USB CompactFlash reader.
+
++config USB_STORAGE_ALAUDA
++ bool "Olympus MAUSB-10/Fuji DPC-R1 support (EXPERIMENTAL)"
++ depends on USB_STORAGE && EXPERIMENTAL
++ help
++ Say Y here to include additional code to support the Olympus MAUSB-10
++ and Fujifilm DPC-R1 USB Card reader/writer devices.
++
++ These devices are based on the Alauda chip and support support both
++ XD and SmartMedia cards.
+
+ config USB_STORAGE_ONETOUCH
+ bool "Support OneTouch Button on Maxtor Hard Drives (EXPERIMENTAL)"
+--- gregkh-2.6.orig/drivers/usb/storage/Makefile
++++ gregkh-2.6/drivers/usb/storage/Makefile
+@@ -18,6 +18,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DPC
+ 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_ALAUDA) += alauda.o
+ usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
+
+ usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
+--- gregkh-2.6.orig/include/linux/usb_usual.h
++++ gregkh-2.6/include/linux/usb_usual.h
+@@ -102,6 +102,9 @@ enum { US_DO_ALL_FLAGS };
+ #ifdef CONFIG_USB_STORAGE_JUMPSHOT
+ #define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */
+ #endif
++#ifdef CONFIG_USB_STORAGE_ALAUDA
++#define US_PR_ALAUDA 0xf4 /* Alauda chipsets */
++#endif
+
+ #define US_PR_DEVICE 0xff /* Use device's value */
+
+--- gregkh-2.6.orig/drivers/usb/storage/unusual_devs.h
++++ gregkh-2.6/drivers/usb/storage/unusual_devs.h
+@@ -535,6 +535,13 @@ UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x
+ "Silicon Media R/W",
+ US_SC_DEVICE, US_PR_DEVICE, NULL, 0),
+
++#ifdef CONFIG_USB_STORAGE_ALAUDA
++UNUSUAL_DEV( 0x0584, 0x0008, 0x0102, 0x0102,
++ "Fujifilm",
++ "DPC-R1 (Alauda)",
++ US_SC_SCSI, US_PR_ALAUDA, init_alauda, 0 ),
++#endif
++
+ /* Fabrizio Fellini <fello@libero.it> */
+ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
+ "Fujifilm",
+@@ -784,6 +791,13 @@ UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x
+ US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
+ #endif
+
++#ifdef CONFIG_USB_STORAGE_ALAUDA
++UNUSUAL_DEV( 0x07b4, 0x010a, 0x0102, 0x0102,
++ "Olympus",
++ "MAUSB-10 (Alauda)",
++ US_SC_SCSI, US_PR_ALAUDA, init_alauda, 0 ),
++#endif
++
+ #ifdef CONFIG_USB_STORAGE_DATAFAB
+ UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015,
+ "Datafab",
+--- gregkh-2.6.orig/drivers/usb/storage/usb.c
++++ gregkh-2.6/drivers/usb/storage/usb.c
+@@ -94,6 +94,9 @@
+ #ifdef CONFIG_USB_STORAGE_ONETOUCH
+ #include "onetouch.h"
+ #endif
++#ifdef CONFIG_USB_STORAGE_ALAUDA
++#include "alauda.h"
++#endif
+
+ /* Some informational data */
+ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
+@@ -644,6 +647,15 @@ static int get_protocol(struct us_data *
+ break;
+ #endif
+
++#ifdef CONFIG_USB_STORAGE_ALAUDA
++ case US_PR_ALAUDA:
++ us->transport_name = "Alauda Control/Bulk";
++ us->transport = alauda_transport;
++ us->transport_reset = usb_stor_Bulk_reset;
++ us->max_lun = 1;
++ break;
++#endif
++
+ default:
+ return -EIO;
+ }
diff --git a/usb/usb-storage-cleanups-of-sddr09.patch b/usb/usb-storage-cleanups-of-sddr09.patch
new file mode 100644
index 0000000000000..63b9ae1152db9
--- /dev/null
+++ b/usb/usb-storage-cleanups-of-sddr09.patch
@@ -0,0 +1,264 @@
+From mdharm@multivac.one-eyed-alien.net Sun Dec 4 22:01:36 2005
+Date: Sun, 4 Dec 2005 21:57:51 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB Storage: cleanups of sddr09
+Message-ID: <20051205055751.GB15047@one-eyed-alien.net>
+Content-Disposition: inline
+
+This is the first of three patches to prepare the sddr09 subdriver for
+conversion to the Sim-SCSI framework. This patch (as594) straightens
+out the initialization procedures and headers:
+
+ Some ugly code from usb.c was moved into sddr09.c.
+
+ Set-up of the private data structures was moved into the
+ initialization routine.
+
+ The connection between the "dpcm" version and the standalone
+ version was clarified.
+
+ A private declaration was moved from a header file into the
+ subdriver's .c file.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: Andries Brouwer <Andries.Brouwer@cwi.nl>
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/storage/initializers.h | 4 --
+ drivers/usb/storage/sddr09.c | 74 ++++++++++++++++++++++++++++---------
+ drivers/usb/storage/sddr09.h | 15 +------
+ drivers/usb/storage/unusual_devs.h | 14 +++----
+ drivers/usb/storage/usb.c | 22 -----------
+ 5 files changed, 65 insertions(+), 64 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/storage/unusual_devs.h
++++ gregkh-2.6/drivers/usb/storage/unusual_devs.h
+@@ -284,14 +284,14 @@ UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x
+ UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
+ "Sandisk",
+ "ImageMate SDDR09",
+- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+- US_FL_SINGLE_LUN ),
++ US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,
++ 0),
+
+ /* This entry is from Andries.Brouwer@cwi.nl */
+ UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208,
+ "SCM Microsystems",
+ "eUSB SmartMedia / CompactFlash Adapter",
+- US_SC_SCSI, US_PR_DPCM_USB, sddr09_init,
++ US_SC_SCSI, US_PR_DPCM_USB, usb_stor_sddr09_dpcm_init,
+ 0),
+ #endif
+
+@@ -681,8 +681,8 @@ UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x
+ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
+ "Olympus",
+ "Camedia MAUSB-2",
+- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+- US_FL_SINGLE_LUN ),
++ US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,
++ 0),
+ #endif
+
+ /* Reported by Darsen Lu <darsen@micro.ee.nthu.edu.tw> */
+@@ -747,8 +747,8 @@ UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x
+ UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999,
+ "Sandisk",
+ "ImageMate SDDR-09",
+- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+- US_FL_SINGLE_LUN ),
++ US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,
++ 0),
+ #endif
+
+ #ifdef CONFIG_USB_STORAGE_FREECOM
+--- gregkh-2.6.orig/drivers/usb/storage/sddr09.c
++++ gregkh-2.6/drivers/usb/storage/sddr09.c
+@@ -214,6 +214,20 @@ static void nand_store_ecc(unsigned char
+ * The actual driver starts here.
+ */
+
++struct sddr09_card_info {
++ unsigned long capacity; /* Size of card in bytes */
++ int pagesize; /* Size of page in bytes */
++ int pageshift; /* log2 of pagesize */
++ int blocksize; /* Size of block in pages */
++ int blockshift; /* log2 of blocksize */
++ int blockmask; /* 2^blockshift - 1 */
++ int *lba_to_pba; /* logical to physical map */
++ int *pba_to_lba; /* physical to logical map */
++ int lbact; /* number of available pages */
++ int flags;
++#define SDDR09_WP 1 /* write protected */
++};
++
+ /*
+ * On my 16MB card, control blocks have size 64 (16 real control bytes,
+ * and 48 junk bytes). In reality of course the card uses 16 control bytes,
+@@ -1342,27 +1356,51 @@ sddr09_card_info_destructor(void *extra)
+ kfree(info->pba_to_lba);
+ }
+
+-static void
+-sddr09_init_card_info(struct us_data *us) {
+- if (!us->extra) {
+- us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
+- if (us->extra) {
+- memset(us->extra, 0, sizeof(struct sddr09_card_info));
+- us->extra_destructor = sddr09_card_info_destructor;
+- }
+- }
++static int
++sddr09_common_init(struct us_data *us) {
++ int result;
++
++ /* set the configuration -- STALL is an acceptable response here */
++ if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
++ US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
++ ->actconfig->desc.bConfigurationValue);
++ return -EINVAL;
++ }
++
++ result = usb_reset_configuration(us->pusb_dev);
++ US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
++ if (result == -EPIPE) {
++ US_DEBUGP("-- stall on control interface\n");
++ } else if (result != 0) {
++ /* it's not a stall, but another error -- time to bail */
++ US_DEBUGP("-- Unknown error. Rejecting device\n");
++ return -EINVAL;
++ }
++
++ us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
++ if (!us->extra)
++ return -ENOMEM;
++ us->extra_destructor = sddr09_card_info_destructor;
++
++ nand_init_ecc();
++ return 0;
+ }
+
++
+ /*
+ * This is needed at a very early stage. If this is not listed in the
+ * unusual devices list but called from here then LUN 0 of the combo reader
+ * is not recognized. But I do not know what precisely these calls do.
+ */
+ int
+-sddr09_init(struct us_data *us) {
++usb_stor_sddr09_dpcm_init(struct us_data *us) {
+ int result;
+ unsigned char *data = us->iobuf;
+
++ result = sddr09_common_init(us);
++ if (result)
++ return result;
++
+ result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
+ if (result != USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("sddr09_init: send_command fails\n");
+@@ -1398,7 +1436,7 @@ sddr09_init(struct us_data *us) {
+
+ // test unit ready
+
+- return USB_STOR_TRANSPORT_GOOD; /* not result */
++ return 0; /* not result */
+ }
+
+ /*
+@@ -1427,13 +1465,6 @@ int sddr09_transport(struct scsi_cmnd *s
+ };
+
+ info = (struct sddr09_card_info *)us->extra;
+- if (!info) {
+- nand_init_ecc();
+- sddr09_init_card_info(us);
+- info = (struct sddr09_card_info *)us->extra;
+- if (!info)
+- return USB_STOR_TRANSPORT_ERROR;
+- }
+
+ if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) {
+ /* for a faked command, we have to follow with a faked sense */
+@@ -1606,3 +1637,10 @@ int sddr09_transport(struct scsi_cmnd *s
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
++/*
++ * Initialization routine for the sddr09 subdriver
++ */
++int
++usb_stor_sddr09_init(struct us_data *us) {
++ return sddr09_common_init(us);
++}
+--- gregkh-2.6.orig/drivers/usb/storage/sddr09.h
++++ gregkh-2.6/drivers/usb/storage/sddr09.h
+@@ -31,18 +31,7 @@
+
+ extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+-struct sddr09_card_info {
+- unsigned long capacity; /* Size of card in bytes */
+- int pagesize; /* Size of page in bytes */
+- int pageshift; /* log2 of pagesize */
+- int blocksize; /* Size of block in pages */
+- int blockshift; /* log2 of blocksize */
+- int blockmask; /* 2^blockshift - 1 */
+- int *lba_to_pba; /* logical to physical map */
+- int *pba_to_lba; /* physical to logical map */
+- int lbact; /* number of available pages */
+- int flags;
+-#define SDDR09_WP 1 /* write protected */
+-};
++extern int usb_stor_sddr09_dpcm_init(struct us_data *us);
++extern int usb_stor_sddr09_init(struct us_data *us);
+
+ #endif
+--- gregkh-2.6.orig/drivers/usb/storage/usb.c
++++ gregkh-2.6/drivers/usb/storage/usb.c
+@@ -919,28 +919,6 @@ static int storage_probe(struct usb_inte
+ */
+ get_device_info(us, id);
+
+-#ifdef CONFIG_USB_STORAGE_SDDR09
+- if (us->protocol == US_PR_EUSB_SDDR09 ||
+- us->protocol == US_PR_DPCM_USB) {
+- /* set the configuration -- STALL is an acceptable response here */
+- if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
+- US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
+- ->actconfig->desc.bConfigurationValue);
+- goto BadDevice;
+- }
+- result = usb_reset_configuration(us->pusb_dev);
+-
+- US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
+- if (result == -EPIPE) {
+- US_DEBUGP("-- stall on control interface\n");
+- } else if (result != 0) {
+- /* it's not a stall, but another error -- time to bail */
+- US_DEBUGP("-- Unknown error. Rejecting device\n");
+- goto BadDevice;
+- }
+- }
+-#endif
+-
+ /* Get the transport, protocol, and pipe settings */
+ result = get_transport(us);
+ if (result)
+--- gregkh-2.6.orig/drivers/usb/storage/initializers.h
++++ gregkh-2.6/drivers/usb/storage/initializers.h
+@@ -45,10 +45,6 @@
+ * mode */
+ int usb_stor_euscsi_init(struct us_data *us);
+
+-#ifdef CONFIG_USB_STORAGE_SDDR09
+-int sddr09_init(struct us_data *us);
+-#endif
+-
+ /* This function is required to activate all four slots on the UCR-61S2B
+ * flash reader */
+ int usb_stor_ucr61s2b_init(struct us_data *us);
diff --git a/usb/usb-storage-make-onetouch-pm-aware.patch b/usb/usb-storage-make-onetouch-pm-aware.patch
new file mode 100644
index 0000000000000..a9ffc85dc576d
--- /dev/null
+++ b/usb/usb-storage-make-onetouch-pm-aware.patch
@@ -0,0 +1,131 @@
+From mdharm@multivac.one-eyed-alien.net Sun Dec 4 22:01:27 2005
+Date: Sun, 4 Dec 2005 21:56:51 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB Storage: make OneTouch PM-aware
+Message-ID: <20051205055651.GA15047@one-eyed-alien.net>
+Content-Disposition: inline
+
+The OneTouch subdriver submits its own interrupt URB for notifications
+about button presses. Consequently it needs to know about suspend and
+resume events, so it can cancel or restart the URB.
+
+This patch (as593) adds a hook to struct us_data, to be used for
+notifying subdrivers about Power Management events, and it implements
+the hook in the OneTouch driver.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Nick Sillik <n.sillik@temple.edu>
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/storage/onetouch.c | 27 +++++++++++++++++++++++++++
+ drivers/usb/storage/usb.c | 4 ++++
+ drivers/usb/storage/usb.h | 9 ++++++++-
+ 3 files changed, 39 insertions(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/drivers/usb/storage/usb.c
++++ gregkh-2.6/drivers/usb/storage/usb.c
+@@ -188,6 +188,8 @@ static int storage_suspend(struct usb_in
+ down(&us->dev_semaphore);
+
+ US_DEBUGP("%s\n", __FUNCTION__);
++ if (us->suspend_resume_hook)
++ (us->suspend_resume_hook)(us, US_SUSPEND);
+ iface->dev.power.power_state.event = message.event;
+
+ /* When runtime PM is working, we'll set a flag to indicate
+@@ -204,6 +206,8 @@ static int storage_resume(struct usb_int
+ down(&us->dev_semaphore);
+
+ US_DEBUGP("%s\n", __FUNCTION__);
++ if (us->suspend_resume_hook)
++ (us->suspend_resume_hook)(us, US_RESUME);
+ iface->dev.power.power_state.event = PM_EVENT_ON;
+
+ up(&us->dev_semaphore);
+--- gregkh-2.6.orig/drivers/usb/storage/usb.h
++++ gregkh-2.6/drivers/usb/storage/usb.h
+@@ -93,7 +93,11 @@ struct us_unusual_dev {
+ typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*);
+ typedef int (*trans_reset)(struct us_data*);
+ typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*);
+-typedef void (*extra_data_destructor)(void *); /* extra data destructor */
++typedef void (*extra_data_destructor)(void *); /* extra data destructor */
++typedef void (*pm_hook)(struct us_data *, int); /* power management hook */
++
++#define US_SUSPEND 0
++#define US_RESUME 1
+
+ /* we allocate one of these for every device that we remember */
+ struct us_data {
+@@ -149,6 +153,9 @@ struct us_data {
+ /* subdriver information */
+ void *extra; /* Any extra data */
+ extra_data_destructor extra_destructor;/* extra data destructor */
++#ifdef CONFIG_PM
++ pm_hook suspend_resume_hook;
++#endif
+ };
+
+ /* Convert between us_data and the corresponding Scsi_Host */
+--- gregkh-2.6.orig/drivers/usb/storage/onetouch.c
++++ gregkh-2.6/drivers/usb/storage/onetouch.c
+@@ -52,6 +52,7 @@ struct usb_onetouch {
+ struct urb *irq; /* urb for interrupt in report */
+ unsigned char *data; /* input data */
+ dma_addr_t data_dma;
++ unsigned int is_open:1;
+ };
+
+ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
+@@ -89,6 +90,7 @@ static int usb_onetouch_open(struct inpu
+ {
+ struct usb_onetouch *onetouch = dev->private;
+
++ onetouch->is_open = 1;
+ onetouch->irq->dev = onetouch->udev;
+ if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
+ err("usb_submit_urb failed");
+@@ -103,8 +105,30 @@ static void usb_onetouch_close(struct in
+ struct usb_onetouch *onetouch = dev->private;
+
+ usb_kill_urb(onetouch->irq);
++ onetouch->is_open = 0;
+ }
+
++#ifdef CONFIG_PM
++static void usb_onetouch_pm_hook(struct us_data *us, int action)
++{
++ struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra;
++
++ if (onetouch->is_open) {
++ switch (action) {
++ case US_SUSPEND:
++ usb_kill_urb(onetouch->irq);
++ break;
++ case US_RESUME:
++ if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0)
++ err("usb_submit_urb failed");
++ break;
++ default:
++ break;
++ }
++ }
++}
++#endif /* CONFIG_PM */
++
+ int onetouch_connect_input(struct us_data *ss)
+ {
+ struct usb_device *udev = ss->pusb_dev;
+@@ -185,6 +209,9 @@ int onetouch_connect_input(struct us_dat
+
+ ss->extra_destructor = onetouch_release_input;
+ ss->extra = onetouch;
++#ifdef CONFIG_PM
++ ss->suspend_resume_hook = usb_onetouch_pm_hook;
++#endif
+
+ input_register_device(onetouch->dev);
+
diff --git a/usb/usb-storage-more-sddr09-cleanups.patch b/usb/usb-storage-more-sddr09-cleanups.patch
new file mode 100644
index 0000000000000..fb4be50bd3e0b
--- /dev/null
+++ b/usb/usb-storage-more-sddr09-cleanups.patch
@@ -0,0 +1,101 @@
+From mdharm@multivac.one-eyed-alien.net Sun Dec 4 22:01:57 2005
+Date: Sun, 4 Dec 2005 21:59:45 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB Storage: more sddr09 cleanups
+Message-ID: <20051205055945.GD15047@one-eyed-alien.net>
+Content-Disposition: inline
+
+This is the third of three patches to prepare the sddr09 subdriver for
+conversion to the Sim-SCSI framework. This patch (as596) moves the
+computation of the LBA to the start of the read/write routines, so that
+addresses completely beyond the end of the device can be detected and
+reported differently from transfers that are partially within the
+device's capacity.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: Andries Brouwer <Andries.Brouwer@cwi.nl>
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/storage/sddr09.c | 33 +++++++++++++++++++++++----------
+ 1 file changed, 23 insertions(+), 10 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/storage/sddr09.c
++++ gregkh-2.6/drivers/usb/storage/sddr09.c
+@@ -711,6 +711,13 @@ sddr09_read_data(struct us_data *us,
+ unsigned int len, index, offset;
+ int result;
+
++ // Figure out the initial LBA and page
++ lba = address >> info->blockshift;
++ page = (address & info->blockmask);
++ maxlba = info->capacity >> (info->pageshift + info->blockshift);
++ if (lba >= maxlba)
++ return -EIO;
++
+ // Since we only read in one block at a time, we have to create
+ // a bounce buffer and move the data a piece at a time between the
+ // bounce buffer and the actual transfer buffer.
+@@ -722,11 +729,6 @@ sddr09_read_data(struct us_data *us,
+ return -ENOMEM;
+ }
+
+- // Figure out the initial LBA and page
+- lba = address >> info->blockshift;
+- page = (address & info->blockmask);
+- maxlba = info->capacity >> (info->pageshift + info->blockshift);
+-
+ // This could be made much more efficient by checking for
+ // contiguous LBA's. Another exercise left to the student.
+
+@@ -928,13 +930,20 @@ sddr09_write_data(struct us_data *us,
+ unsigned int sectors) {
+
+ struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+- unsigned int lba, page, pages;
++ unsigned int lba, maxlba, page, pages;
+ unsigned int pagelen, blocklen;
+ unsigned char *blockbuffer;
+ unsigned char *buffer;
+ unsigned int len, index, offset;
+ int result;
+
++ // Figure out the initial LBA and page
++ lba = address >> info->blockshift;
++ page = (address & info->blockmask);
++ maxlba = info->capacity >> (info->pageshift + info->blockshift);
++ if (lba >= maxlba)
++ return -EIO;
++
+ // blockbuffer is used for reading in the old data, overwriting
+ // with the new data, and performing ECC calculations
+
+@@ -961,10 +970,6 @@ sddr09_write_data(struct us_data *us,
+ return -ENOMEM;
+ }
+
+- // Figure out the initial LBA and page
+- lba = address >> info->blockshift;
+- page = (address & info->blockmask);
+-
+ result = 0;
+ index = offset = 0;
+
+@@ -975,6 +980,14 @@ sddr09_write_data(struct us_data *us,
+ pages = min(sectors, info->blocksize - page);
+ len = (pages << info->pageshift);
+
++ /* Not overflowing capacity? */
++ if (lba >= maxlba) {
++ US_DEBUGP("Error: Requested lba %u exceeds "
++ "maximum %u\n", lba, maxlba);
++ result = -EIO;
++ break;
++ }
++
+ // Get the data from the transfer buffer
+ usb_stor_access_xfer_buf(buffer, len, us->srb,
+ &index, &offset, FROM_XFER_BUF);
diff --git a/usb/usb-storage-sddr09-cleanups.patch b/usb/usb-storage-sddr09-cleanups.patch
new file mode 100644
index 0000000000000..ebdd7a55b8219
--- /dev/null
+++ b/usb/usb-storage-sddr09-cleanups.patch
@@ -0,0 +1,395 @@
+From mdharm@multivac.one-eyed-alien.net Sun Dec 4 22:01:52 2005
+Date: Sun, 4 Dec 2005 21:58:52 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB Storage: sddr09 cleanups
+Message-ID: <20051205055852.GC15047@one-eyed-alien.net>
+Content-Disposition: inline
+
+This is the second of three patches to prepare the sddr09 subdriver for
+conversion to the Sim-SCSI framework. This patch (as595) updates the
+code to use standard error values for return codes instead of our
+special-purpose USB_STOR_TRANSPORT_... codes. The reverse update is
+then needed in the transport routine, but with the Sim-SCSI framework
+that routine will go away.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: Andries Brouwer <Andries.Brouwer@cwi.nl>
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/storage/sddr09.c | 103 ++++++++++++++++++++-----------------------
+ 1 file changed, 50 insertions(+), 53 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/storage/sddr09.c
++++ gregkh-2.6/drivers/usb/storage/sddr09.c
+@@ -274,8 +274,11 @@ sddr09_send_command(struct us_data *us,
+
+ rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype,
+ 0, 0, xfer_data, xfer_len);
+- return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD :
+- USB_STOR_TRANSPORT_ERROR);
++ switch (rc) {
++ case USB_STOR_XFER_GOOD: return 0;
++ case USB_STOR_XFER_STALLED: return -EPIPE;
++ default: return -EIO;
++ }
+ }
+
+ static int
+@@ -322,20 +325,12 @@ sddr09_request_sense(struct us_data *us,
+ command[4] = buflen;
+
+ result = sddr09_send_scsi_command(us, command, 12);
+- if (result != USB_STOR_TRANSPORT_GOOD) {
+- US_DEBUGP("request sense failed\n");
++ if (result)
+ return result;
+- }
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ sensebuf, buflen, NULL);
+- if (result != USB_STOR_XFER_GOOD) {
+- US_DEBUGP("request sense bulk in failed\n");
+- return USB_STOR_TRANSPORT_ERROR;
+- } else {
+- US_DEBUGP("request sense worked\n");
+- return USB_STOR_TRANSPORT_GOOD;
+- }
++ return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
+ }
+
+ /*
+@@ -383,7 +378,7 @@ sddr09_readX(struct us_data *us, int x,
+
+ result = sddr09_send_scsi_command(us, command, 12);
+
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
+ x, result);
+ return result;
+@@ -395,9 +390,9 @@ sddr09_readX(struct us_data *us, int x,
+ if (result != USB_STOR_XFER_GOOD) {
+ US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n",
+ x, result);
+- return USB_STOR_TRANSPORT_ERROR;
++ return -EIO;
+ }
+- return USB_STOR_TRANSPORT_GOOD;
++ return 0;
+ }
+
+ /*
+@@ -511,7 +506,7 @@ sddr09_erase(struct us_data *us, unsigne
+
+ result = sddr09_send_scsi_command(us, command, 12);
+
+- if (result != USB_STOR_TRANSPORT_GOOD)
++ if (result)
+ US_DEBUGP("Result for send_control in sddr09_erase %d\n",
+ result);
+
+@@ -569,7 +564,7 @@ sddr09_writeX(struct us_data *us,
+
+ result = sddr09_send_scsi_command(us, command, 12);
+
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
+ result);
+ return result;
+@@ -581,9 +576,9 @@ sddr09_writeX(struct us_data *us,
+ if (result != USB_STOR_XFER_GOOD) {
+ US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
+ result);
+- return USB_STOR_TRANSPORT_ERROR;
++ return -EIO;
+ }
+- return USB_STOR_TRANSPORT_GOOD;
++ return 0;
+ }
+
+ /* erase address, write same address */
+@@ -647,7 +642,7 @@ sddr09_read_sg_test_only(struct us_data
+
+ result = sddr09_send_scsi_command(us, command, 4*nsg+3);
+
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
+ result);
+ return result;
+@@ -655,7 +650,7 @@ sddr09_read_sg_test_only(struct us_data
+
+ buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO);
+ if (!buf)
+- return USB_STOR_TRANSPORT_ERROR;
++ return -ENOMEM;
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ buf, bulklen, NULL);
+@@ -663,10 +658,10 @@ sddr09_read_sg_test_only(struct us_data
+ if (result != USB_STOR_XFER_GOOD) {
+ US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
+ result);
+- return USB_STOR_TRANSPORT_ERROR;
++ return -EIO;
+ }
+
+- return USB_STOR_TRANSPORT_GOOD;
++ return 0;
+ }
+ #endif
+
+@@ -695,14 +690,13 @@ sddr09_read_status(struct us_data *us, u
+ command[1] = LUNBITS;
+
+ result = sddr09_send_scsi_command(us, command, 12);
+- if (result != USB_STOR_TRANSPORT_GOOD)
++ if (result)
+ return result;
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data, 64, NULL);
+ *status = data[0];
+- return (result == USB_STOR_XFER_GOOD ?
+- USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
++ return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
+ }
+
+ static int
+@@ -725,7 +719,7 @@ sddr09_read_data(struct us_data *us,
+ buffer = kmalloc(len, GFP_NOIO);
+ if (buffer == NULL) {
+ printk("sddr09_read_data: Out of memory\n");
+- return USB_STOR_TRANSPORT_ERROR;
++ return -ENOMEM;
+ }
+
+ // Figure out the initial LBA and page
+@@ -736,7 +730,7 @@ sddr09_read_data(struct us_data *us,
+ // This could be made much more efficient by checking for
+ // contiguous LBA's. Another exercise left to the student.
+
+- result = USB_STOR_TRANSPORT_GOOD;
++ result = 0;
+ index = offset = 0;
+
+ while (sectors > 0) {
+@@ -749,7 +743,7 @@ sddr09_read_data(struct us_data *us,
+ if (lba >= maxlba) {
+ US_DEBUGP("Error: Requested lba %u exceeds "
+ "maximum %u\n", lba, maxlba);
+- result = USB_STOR_TRANSPORT_ERROR;
++ result = -EIO;
+ break;
+ }
+
+@@ -763,7 +757,7 @@ sddr09_read_data(struct us_data *us,
+
+ /* This is not really an error. It just means
+ that the block has never been written.
+- Instead of returning USB_STOR_TRANSPORT_ERROR
++ Instead of returning an error
+ it is better to return all zero data. */
+
+ memset(buffer, 0, len);
+@@ -778,7 +772,7 @@ sddr09_read_data(struct us_data *us,
+
+ result = sddr09_read20(us, address>>1,
+ pages, info->pageshift, buffer, 0);
+- if (result != USB_STOR_TRANSPORT_GOOD)
++ if (result)
+ break;
+ }
+
+@@ -844,7 +838,7 @@ sddr09_write_lba(struct us_data *us, uns
+ pba = sddr09_find_unused_pba(info, lba);
+ if (!pba) {
+ printk("sddr09_write_lba: Out of unused blocks\n");
+- return USB_STOR_TRANSPORT_ERROR;
++ return -ENOSPC;
+ }
+ info->pba_to_lba[pba] = lba;
+ info->lba_to_pba[lba] = pba;
+@@ -855,7 +849,7 @@ sddr09_write_lba(struct us_data *us, uns
+ /* Maybe it is impossible to write to PBA 1.
+ Fake success, but don't do anything. */
+ printk("sddr09: avoid writing to pba 1\n");
+- return USB_STOR_TRANSPORT_GOOD;
++ return 0;
+ }
+
+ pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+@@ -864,7 +858,7 @@ sddr09_write_lba(struct us_data *us, uns
+ address = (pba << (info->pageshift + info->blockshift));
+ result = sddr09_read22(us, address>>1, info->blocksize,
+ info->pageshift, blockbuffer, 0);
+- if (result != USB_STOR_TRANSPORT_GOOD)
++ if (result)
+ return result;
+
+ /* check old contents and fill lba */
+@@ -911,7 +905,7 @@ sddr09_write_lba(struct us_data *us, uns
+ {
+ unsigned char status = 0;
+ int result2 = sddr09_read_status(us, &status);
+- if (result2 != USB_STOR_TRANSPORT_GOOD)
++ if (result2)
+ US_DEBUGP("sddr09_write_inplace: cannot read status\n");
+ else if (status != 0xc0)
+ US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
+@@ -952,7 +946,7 @@ sddr09_write_data(struct us_data *us,
+ blockbuffer = kmalloc(blocklen, GFP_NOIO);
+ if (!blockbuffer) {
+ printk("sddr09_write_data: Out of memory\n");
+- return USB_STOR_TRANSPORT_ERROR;
++ return -ENOMEM;
+ }
+
+ // Since we don't write the user data directly to the device,
+@@ -964,14 +958,14 @@ sddr09_write_data(struct us_data *us,
+ if (buffer == NULL) {
+ printk("sddr09_write_data: Out of memory\n");
+ kfree(blockbuffer);
+- return USB_STOR_TRANSPORT_ERROR;
++ return -ENOMEM;
+ }
+
+ // Figure out the initial LBA and page
+ lba = address >> info->blockshift;
+ page = (address & info->blockmask);
+
+- result = USB_STOR_TRANSPORT_GOOD;
++ result = 0;
+ index = offset = 0;
+
+ while (sectors > 0) {
+@@ -987,7 +981,7 @@ sddr09_write_data(struct us_data *us,
+
+ result = sddr09_write_lba(us, lba, page, pages,
+ buffer, blockbuffer);
+- if (result != USB_STOR_TRANSPORT_GOOD)
++ if (result)
+ break;
+
+ page = 0;
+@@ -1036,7 +1030,7 @@ sddr09_read_deviceID(struct us_data *us,
+ command[1] = LUNBITS;
+
+ result = sddr09_send_scsi_command(us, command, 12);
+- if (result != USB_STOR_TRANSPORT_GOOD)
++ if (result)
+ return result;
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+@@ -1045,8 +1039,7 @@ sddr09_read_deviceID(struct us_data *us,
+ for (i = 0; i < 4; i++)
+ deviceID[i] = content[i];
+
+- return (result == USB_STOR_XFER_GOOD ?
+- USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
++ return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
+ }
+
+ static int
+@@ -1055,7 +1048,7 @@ sddr09_get_wp(struct us_data *us, struct
+ unsigned char status;
+
+ result = sddr09_read_status(us, &status);
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("sddr09_get_wp: read_status fails\n");
+ return result;
+ }
+@@ -1071,7 +1064,7 @@ sddr09_get_wp(struct us_data *us, struct
+ if (status & 0x1)
+ US_DEBUGP(" Error");
+ US_DEBUGP("\n");
+- return USB_STOR_TRANSPORT_GOOD;
++ return 0;
+ }
+
+ #if 0
+@@ -1103,7 +1096,7 @@ sddr09_get_cardinfo(struct us_data *us,
+
+ result = sddr09_read_deviceID(us, deviceID);
+
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("Result of read_deviceID is %d\n", result);
+ printk("sddr09: could not read card info\n");
+ return NULL;
+@@ -1214,7 +1207,7 @@ sddr09_read_map(struct us_data *us) {
+ us, address>>1,
+ min(alloc_blocks, numblocks - i),
+ buffer, 0);
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ result = -1;
+ goto done;
+ }
+@@ -1402,7 +1395,7 @@ usb_stor_sddr09_dpcm_init(struct us_data
+ return result;
+
+ result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("sddr09_init: send_command fails\n");
+ return result;
+ }
+@@ -1411,7 +1404,7 @@ usb_stor_sddr09_dpcm_init(struct us_data
+ // get 07 02
+
+ result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("sddr09_init: 2nd send_command fails\n");
+ return result;
+ }
+@@ -1420,7 +1413,7 @@ usb_stor_sddr09_dpcm_init(struct us_data
+ // get 07 00
+
+ result = sddr09_request_sense(us, data, 18);
+- if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) {
++ if (result == 0 && data[2] != 0) {
+ int j;
+ for (j=0; j<18; j++)
+ printk(" %02X", data[j]);
+@@ -1567,7 +1560,9 @@ int sddr09_transport(struct scsi_cmnd *s
+ US_DEBUGP("READ_10: read page %d pagect %d\n",
+ page, pages);
+
+- return sddr09_read_data(us, page, pages);
++ result = sddr09_read_data(us, page, pages);
++ return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
++ USB_STOR_TRANSPORT_ERROR);
+ }
+
+ if (srb->cmnd[0] == WRITE_10) {
+@@ -1580,7 +1575,9 @@ int sddr09_transport(struct scsi_cmnd *s
+ US_DEBUGP("WRITE_10: write page %d pagect %d\n",
+ page, pages);
+
+- return sddr09_write_data(us, page, pages);
++ result = sddr09_write_data(us, page, pages);
++ return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
++ USB_STOR_TRANSPORT_ERROR);
+ }
+
+ /* catch-all for all other commands, except
+@@ -1606,10 +1603,10 @@ int sddr09_transport(struct scsi_cmnd *s
+ US_DEBUGP("SDDR09: Send control for command %s\n", ptr);
+
+ result = sddr09_send_scsi_command(us, srb->cmnd, 12);
+- if (result != USB_STOR_TRANSPORT_GOOD) {
++ if (result) {
+ US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
+ "returns %d\n", result);
+- return result;
++ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (srb->request_bufflen == 0)
diff --git a/usb/usb-storage-update-maintainers.patch b/usb/usb-storage-update-maintainers.patch
new file mode 100644
index 0000000000000..62102b7a90df5
--- /dev/null
+++ b/usb/usb-storage-update-maintainers.patch
@@ -0,0 +1,29 @@
+From mdharm@multivac.one-eyed-alien.net Sun Dec 4 22:07:14 2005
+Date: Sun, 4 Dec 2005 22:03:47 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB Storage: update MAINTAINERS
+Message-ID: <20051205060347.GF15047@one-eyed-alien.net>
+Content-Disposition: inline
+
+Someone recently pointed out to me that the MAINTAINERS entry for
+usb-storage was, perhaps, in need of changing.
+
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ MAINTAINERS | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/MAINTAINERS
++++ gregkh-2.6/MAINTAINERS
+@@ -2658,7 +2658,7 @@ USB MASS STORAGE DRIVER
+ P: Matthew Dharm
+ M: mdharm-usb@one-eyed-alien.net
+ L: linux-usb-users@lists.sourceforge.net
+-L: linux-usb-devel@lists.sourceforge.net
++L: usb-storage@lists.one-eyed-alien.net
+ S: Maintained
+ W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
+