diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2005-12-07 15:54:12 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-12-07 15:54:12 -0800 |
commit | 4bd956d2e2f9072faecd767e9b27da06b89481f0 (patch) | |
tree | fe9ce13110e1673e019ba876768a549a01f80f1f /usb | |
parent | dc4d53eedb18d77f3782c1c8109ebca0424cf976 (diff) | |
download | patches-4bd956d2e2f9072faecd767e9b27da06b89481f0.tar.gz |
w1 and usb patches
Diffstat (limited to 'usb')
-rw-r--r-- | usb/uhci-add-missing-memory-barriers.patch | 35 | ||||
-rw-r--r-- | usb/uhci-edit-some-comments.patch | 273 | ||||
-rw-r--r-- | usb/usb-driver-owner-removal.patch | 13 | ||||
-rw-r--r-- | usb/usb-let-usbmon-collect-less-garbage.patch | 47 | ||||
-rw-r--r-- | usb/usb-storage-add-alauda-support.patch | 1361 | ||||
-rw-r--r-- | usb/usb-storage-cleanups-of-sddr09.patch | 264 | ||||
-rw-r--r-- | usb/usb-storage-make-onetouch-pm-aware.patch | 131 | ||||
-rw-r--r-- | usb/usb-storage-more-sddr09-cleanups.patch | 101 | ||||
-rw-r--r-- | usb/usb-storage-sddr09-cleanups.patch | 395 | ||||
-rw-r--r-- | usb/usb-storage-update-maintainers.patch | 29 |
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/ + |