aboutsummaryrefslogtreecommitdiffstats
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2009-11-20 13:19:37 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2009-11-20 13:19:37 -0800
commit7206339a2d7c087c9286f715091433c7b4ebc64b (patch)
tree2e18e1c51359cae4501121e5aa8f5f290b7dd56b
parent09fee4a605baa586dbe2939dadbf6e7ee5c394ca (diff)
downloadpatches-7206339a2d7c087c9286f715091433c7b4ebc64b.tar.gz
lots o usb patches
and some sysfs ones as well.
-rw-r--r--driver-core/sysfs-rename-sysfs_d_iput-to-sysfs_dentry_iput.patch44
-rw-r--r--driver-core/sysfs-simplify-iattr-time-assignments.patch45
-rw-r--r--driver-core/sysfs-simplify-sysfs_chmod_file-semantics.patch51
-rw-r--r--driver-core/sysfs-update-sysfs_setxattr-so-it-updates-secdata-under-the-sysfs_mutex.patch92
-rw-r--r--driver-core/sysfs-use-dentry_ops-instead-of-directly-playing-with-the-dcache.patch140
-rw-r--r--series40
-rw-r--r--usb/usb-composite-usb_composite_unregister-no-longer-__exit.patch45
-rw-r--r--usb/usb-fix-possible-null-deref-in-init_usb_class.patch28
-rw-r--r--usb/usb-g_mass_storage-code-cleaned-up-and-comments-updated.patch1453
-rw-r--r--usb/usb-g_mass_storage-fsg_config-added-module-params-handlig-changed.patch493
-rw-r--r--usb/usb-g_mass_storage-lun_name_format-and-thread_name-added.patch110
-rw-r--r--usb/usb-g_mass_storage-mass-storage-function-created.patch1285
-rw-r--r--usb/usb-g_mass_storage-most-data-moved-to-fsg_common.patch2419
-rw-r--r--usb/usb-g_mass_storage-thread_exits-callback-added.patch151
-rw-r--r--usb/usb-g_multi-multifunction-composite-gadget-added.patch459
-rw-r--r--usb/usb-musb-add-notes-for-blackfin-anomalies.patch60
-rw-r--r--usb/usb-musb-add-work-around-for-blackfin-anomaly-05000456.patch45
-rw-r--r--usb/usb-musb-blackfin-code-needs-nop_usb_xceiv-too.patch38
-rw-r--r--usb/usb-musb-clear-the-blackfin-interrupt-pending-bits-early-in-the-isr.patch51
-rw-r--r--usb/usb-musb-error-out-when-anomaly-05000380-is-applicable.patch42
-rw-r--r--usb/usb-musb-fix-musb_platform_set_mode-definition.patch36
-rw-r--r--usb/usb-musb-fix-printf-warning-in-debug-code.patch37
-rw-r--r--usb/usb-musb-kill-compile-warning-for-blackfin-systems.patch42
-rw-r--r--usb/usb-musb-kill-some-useless-comments-in-blackfin-driver.patch34
-rw-r--r--usb/usb-musb-save-hardware-revision-at-init.patch73
-rw-r--r--usb/usb-musb-tweak-musb_read_fifo-to-avoid-unused-warnings.patch52
-rw-r--r--usb/usb-musb-update-blackfin-processor-dependency.patch36
-rw-r--r--usb/usb-musb_gadget-implement-set_wedge-method.patch104
-rw-r--r--usb/usb-musb_gadget-remove-pointless-loop.patch216
-rw-r--r--usb/usb-musb_gadget_ep0-fix-unhandled-endpoint-0-irqs-again.patch38
-rw-r--r--usb/usb-musb_gadget_ep0-stop-abusing-musb_gadget_set_halt.patch141
-rw-r--r--usb/usb-r8a66597-clean-up.-remove-unneeded-null-checks.patch45
-rw-r--r--usb/usb-remove-the-auto_pm-flag.patch188
-rw-r--r--usb/usb-twl4030-enable-usb-regulators-before-enabling-usb-charging.patch52
-rw-r--r--usb/usb-usbtmc-repeat-usb_bulk_msg-until-whole-message-is-transfered.patch49
-rw-r--r--usb/usb-xhci-add-tests-for-trb-address-translation.patch227
-rw-r--r--usb/usb-xhci-handle-errors-that-cause-endpoint-halts.patch150
-rw-r--r--usb/usb-xhci-return-eproto-on-a-split-transaction-error.patch30
-rw-r--r--usb/usb-xhci-return-success-for-vendor-specific-info-codes.patch40
-rw-r--r--usb/usb-xhci-set-transfer-descriptor-size-field-correctly.patch120
-rw-r--r--usb/usbtest-make-module-param-pattern-writeable.patch44
41 files changed, 8845 insertions, 0 deletions
diff --git a/driver-core/sysfs-rename-sysfs_d_iput-to-sysfs_dentry_iput.patch b/driver-core/sysfs-rename-sysfs_d_iput-to-sysfs_dentry_iput.patch
new file mode 100644
index 00000000000000..ff09ba7d33b986
--- /dev/null
+++ b/driver-core/sysfs-rename-sysfs_d_iput-to-sysfs_dentry_iput.patch
@@ -0,0 +1,44 @@
+From ebiederm@xmission.com Fri Nov 20 12:06:44 2009
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 7 Nov 2009 23:27:00 -0800
+Subject: sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Kay Sievers <kay.sievers@vrfy.org>, Greg KH <greg@kroah.com>, Tejun Heo <tj@kernel.org>, Cornelia Huck <cornelia.huck@de.ibm.com>, Eric Dumazet <eric.dumazet@gmail.com>, Benjamin LaHaise <bcrl@lhnet.ca>, Serge Hallyn <serue@us.ibm.com>, "Eric W. Biederman" <ebiederm@xmission.com>, "Eric W. Biederman" <ebiederm@aristanetworks.com>
+Message-ID: <1257665233-12468-2-git-send-email-ebiederm@xmission.com>
+
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+Using dentry instead of d in the function name is what
+several other filesystems are doing and it seems to be
+a more readable convention.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Acked-by: Serge Hallyn <serue@us.ibm.com>
+Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/sysfs/dir.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/sysfs/dir.c
++++ b/fs/sysfs/dir.c
+@@ -298,7 +298,7 @@ void release_sysfs_dirent(struct sysfs_d
+ goto repeat;
+ }
+
+-static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
++static void sysfs_dentry_iput(struct dentry * dentry, struct inode * inode)
+ {
+ struct sysfs_dirent * sd = dentry->d_fsdata;
+
+@@ -307,7 +307,7 @@ static void sysfs_d_iput(struct dentry *
+ }
+
+ static const struct dentry_operations sysfs_dentry_ops = {
+- .d_iput = sysfs_d_iput,
++ .d_iput = sysfs_dentry_iput,
+ };
+
+ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
diff --git a/driver-core/sysfs-simplify-iattr-time-assignments.patch b/driver-core/sysfs-simplify-iattr-time-assignments.patch
new file mode 100644
index 00000000000000..67907d2dc07d1a
--- /dev/null
+++ b/driver-core/sysfs-simplify-iattr-time-assignments.patch
@@ -0,0 +1,45 @@
+From ebiederm@xmission.com Fri Nov 20 12:10:29 2009
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 7 Nov 2009 23:27:03 -0800
+Subject: sysfs: Simplify iattr time assignments
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Kay Sievers <kay.sievers@vrfy.org>, Greg KH <greg@kroah.com>, Tejun Heo <tj@kernel.org>, Cornelia Huck <cornelia.huck@de.ibm.com>, Eric Dumazet <eric.dumazet@gmail.com>, Benjamin LaHaise <bcrl@lhnet.ca>, Serge Hallyn <serue@us.ibm.com>, "Eric W. Biederman" <ebiederm@xmission.com>, "Eric W. Biederman" <ebiederm@aristanetworks.com>
+Message-ID: <1257665233-12468-5-git-send-email-ebiederm@xmission.com>
+
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+The granularity of sysfs time when we keep it is 1 ns. Which
+when passed to timestamp_trunc results in a nop. So remove
+the unnecessary function call making sysfs_setattr slightly
+easier to read.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Acked-by: Serge Hallyn <serue@us.ibm.com>
+Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/sysfs/inode.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+--- a/fs/sysfs/inode.c
++++ b/fs/sysfs/inode.c
+@@ -104,14 +104,11 @@ int sysfs_setattr(struct dentry * dentry
+ if (ia_valid & ATTR_GID)
+ iattrs->ia_gid = iattr->ia_gid;
+ if (ia_valid & ATTR_ATIME)
+- iattrs->ia_atime = timespec_trunc(iattr->ia_atime,
+- inode->i_sb->s_time_gran);
++ iattrs->ia_atime = iattr->ia_atime;
+ if (ia_valid & ATTR_MTIME)
+- iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime,
+- inode->i_sb->s_time_gran);
++ iattrs->ia_mtime = iattr->ia_mtime;
+ if (ia_valid & ATTR_CTIME)
+- iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime,
+- inode->i_sb->s_time_gran);
++ iattrs->ia_ctime = iattr->ia_ctime;
+ if (ia_valid & ATTR_MODE) {
+ umode_t mode = iattr->ia_mode;
+
diff --git a/driver-core/sysfs-simplify-sysfs_chmod_file-semantics.patch b/driver-core/sysfs-simplify-sysfs_chmod_file-semantics.patch
new file mode 100644
index 00000000000000..cb975324022d6b
--- /dev/null
+++ b/driver-core/sysfs-simplify-sysfs_chmod_file-semantics.patch
@@ -0,0 +1,51 @@
+From ebiederm@xmission.com Fri Nov 20 12:10:03 2009
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 7 Nov 2009 23:27:02 -0800
+Subject: sysfs: Simplify sysfs_chmod_file semantics
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Kay Sievers <kay.sievers@vrfy.org>, Greg KH <greg@kroah.com>, Tejun Heo <tj@kernel.org>, Cornelia Huck <cornelia.huck@de.ibm.com>, Eric Dumazet <eric.dumazet@gmail.com>, Benjamin LaHaise <bcrl@lhnet.ca>, Serge Hallyn <serue@us.ibm.com>, "Eric W. Biederman" <ebiederm@xmission.com>, "Eric W. Biederman" <ebiederm@aristanetworks.com>
+Message-ID: <1257665233-12468-4-git-send-email-ebiederm@xmission.com>
+
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+Currently every caller of sysfs_chmod_file happens at either
+file creation time to set a non-default mode or in response
+to a specific user requested space change in policy. Making
+timestamps of when the chmod happens and notification of
+a file changing mode uninteresting.
+
+Remove the unnecessary time stamp and filesystem change
+notification, and removes the last of the explicit inotify
+and donitfy support from sysfs.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Acked-by: Serge Hallyn <serue@us.ibm.com>
+Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/sysfs/file.c | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+--- a/fs/sysfs/file.c
++++ b/fs/sysfs/file.c
+@@ -604,17 +604,9 @@ int sysfs_chmod_file(struct kobject *kob
+ mutex_lock(&inode->i_mutex);
+
+ newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
+- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+- newattrs.ia_ctime = current_fs_time(inode->i_sb);
++ newattrs.ia_valid = ATTR_MODE;
+ rc = sysfs_setattr(victim, &newattrs);
+
+- if (rc == 0) {
+- fsnotify_change(victim, newattrs.ia_valid);
+- mutex_lock(&sysfs_mutex);
+- victim_sd->s_mode = newattrs.ia_mode;
+- mutex_unlock(&sysfs_mutex);
+- }
+-
+ mutex_unlock(&inode->i_mutex);
+ out:
+ dput(victim);
diff --git a/driver-core/sysfs-update-sysfs_setxattr-so-it-updates-secdata-under-the-sysfs_mutex.patch b/driver-core/sysfs-update-sysfs_setxattr-so-it-updates-secdata-under-the-sysfs_mutex.patch
new file mode 100644
index 00000000000000..10d3bf42349f12
--- /dev/null
+++ b/driver-core/sysfs-update-sysfs_setxattr-so-it-updates-secdata-under-the-sysfs_mutex.patch
@@ -0,0 +1,92 @@
+From ebiederm@xmission.com Fri Nov 20 12:06:08 2009
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 7 Nov 2009 23:26:59 -0800
+Subject: sysfs: Update sysfs_setxattr so it updates secdata under the sysfs_mutex
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Kay Sievers <kay.sievers@vrfy.org>, Greg KH <greg@kroah.com>, Tejun Heo <tj@kernel.org>, Cornelia Huck <cornelia.huck@de.ibm.com>, Eric Dumazet <eric.dumazet@gmail.com>, Benjamin LaHaise <bcrl@lhnet.ca>, Serge Hallyn <serue@us.ibm.com>, "Eric W. Biederman" <ebiederm@maxwell.aristanetworks.com>, "Eric W. Biederman" <ebiederm@aristanetworks.com>
+Message-ID: <1257665233-12468-1-git-send-email-ebiederm@xmission.com>
+
+
+From: Eric W. Biederman <ebiederm@maxwell.aristanetworks.com>
+
+The sysfs_mutex is required to ensure updates are and will remain
+atomic with respect to other inode iattr updates, that do not happen
+through the filesystem.
+
+Acked-by: Serge Hallyn <serue@us.ibm.com>
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/sysfs/inode.c | 41 +++++++++++++++++++++++++++++------------
+ 1 file changed, 29 insertions(+), 12 deletions(-)
+
+--- a/fs/sysfs/inode.c
++++ b/fs/sysfs/inode.c
+@@ -123,23 +123,39 @@ int sysfs_setattr(struct dentry * dentry
+ return error;
+ }
+
++static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len)
++{
++ struct sysfs_inode_attrs *iattrs;
++ void *old_secdata;
++ size_t old_secdata_len;
++
++ iattrs = sd->s_iattr;
++ if (!iattrs)
++ iattrs = sysfs_init_inode_attrs(sd);
++ if (!iattrs)
++ return -ENOMEM;
++
++ old_secdata = iattrs->ia_secdata;
++ old_secdata_len = iattrs->ia_secdata_len;
++
++ iattrs->ia_secdata = *secdata;
++ iattrs->ia_secdata_len = *secdata_len;
++
++ *secdata = old_secdata;
++ *secdata_len = old_secdata_len;
++ return 0;
++}
++
+ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags)
+ {
+ struct sysfs_dirent *sd = dentry->d_fsdata;
+- struct sysfs_inode_attrs *iattrs;
+ void *secdata;
+ int error;
+ u32 secdata_len = 0;
+
+ if (!sd)
+ return -EINVAL;
+- if (!sd->s_iattr)
+- sd->s_iattr = sysfs_init_inode_attrs(sd);
+- if (!sd->s_iattr)
+- return -ENOMEM;
+-
+- iattrs = sd->s_iattr;
+
+ if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) {
+ const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
+@@ -151,12 +167,13 @@ int sysfs_setxattr(struct dentry *dentry
+ &secdata, &secdata_len);
+ if (error)
+ goto out;
+- if (iattrs->ia_secdata)
+- security_release_secctx(iattrs->ia_secdata,
+- iattrs->ia_secdata_len);
+- iattrs->ia_secdata = secdata;
+- iattrs->ia_secdata_len = secdata_len;
+
++ mutex_lock(&sysfs_mutex);
++ error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len);
++ mutex_unlock(&sysfs_mutex);
++
++ if (secdata)
++ security_release_secctx(secdata, secdata_len);
+ } else
+ return -EINVAL;
+ out:
diff --git a/driver-core/sysfs-use-dentry_ops-instead-of-directly-playing-with-the-dcache.patch b/driver-core/sysfs-use-dentry_ops-instead-of-directly-playing-with-the-dcache.patch
new file mode 100644
index 00000000000000..61c3e447baed63
--- /dev/null
+++ b/driver-core/sysfs-use-dentry_ops-instead-of-directly-playing-with-the-dcache.patch
@@ -0,0 +1,140 @@
+From ebiederm@xmission.com Fri Nov 20 12:07:21 2009
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 7 Nov 2009 23:27:01 -0800
+Subject: sysfs: Use dentry_ops instead of directly playing with the dcache
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Kay Sievers <kay.sievers@vrfy.org>, Greg KH <greg@kroah.com>, Tejun Heo <tj@kernel.org>, Cornelia Huck <cornelia.huck@de.ibm.com>, Eric Dumazet <eric.dumazet@gmail.com>, Benjamin LaHaise <bcrl@lhnet.ca>, Serge Hallyn <serue@us.ibm.com>, "Eric W. Biederman" <ebiederm@xmission.com>, "Eric W. Biederman" <ebiederm@aristanetworks.com>
+Message-ID: <1257665233-12468-3-git-send-email-ebiederm@xmission.com>
+
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+Calling d_drop unconditionally when a sysfs_dirent is deleted has
+the potential to leak mounts, so instead implement dentry delete
+and revalidate operations that cause sysfs dentries to be removed
+at the appropriate time.
+
+Acked-by: Tejun Heo <tj@kernel.org>
+Acked-by: Serge Hallyn <serue@us.ibm.com>
+Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/sysfs/dir.c | 73 +++++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 46 insertions(+), 27 deletions(-)
+
+--- a/fs/sysfs/dir.c
++++ b/fs/sysfs/dir.c
+@@ -298,6 +298,46 @@ void release_sysfs_dirent(struct sysfs_d
+ goto repeat;
+ }
+
++static int sysfs_dentry_delete(struct dentry *dentry)
++{
++ struct sysfs_dirent *sd = dentry->d_fsdata;
++ return !!(sd->s_flags & SYSFS_FLAG_REMOVED);
++}
++
++static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ struct sysfs_dirent *sd = dentry->d_fsdata;
++ int is_dir;
++
++ mutex_lock(&sysfs_mutex);
++
++ /* The sysfs dirent has been deleted */
++ if (sd->s_flags & SYSFS_FLAG_REMOVED)
++ goto out_bad;
++
++ mutex_unlock(&sysfs_mutex);
++out_valid:
++ return 1;
++out_bad:
++ /* Remove the dentry from the dcache hashes.
++ * If this is a deleted dentry we use d_drop instead of d_delete
++ * so sysfs doesn't need to cope with negative dentries.
++ */
++ is_dir = (sysfs_type(sd) == SYSFS_DIR);
++ mutex_unlock(&sysfs_mutex);
++ if (is_dir) {
++ /* If we have submounts we must allow the vfs caches
++ * to lie about the state of the filesystem to prevent
++ * leaks and other nasty things.
++ */
++ if (have_submounts(dentry))
++ goto out_valid;
++ shrink_dcache_parent(dentry);
++ }
++ d_drop(dentry);
++ return 0;
++}
++
+ static void sysfs_dentry_iput(struct dentry * dentry, struct inode * inode)
+ {
+ struct sysfs_dirent * sd = dentry->d_fsdata;
+@@ -307,6 +347,8 @@ static void sysfs_dentry_iput(struct den
+ }
+
+ static const struct dentry_operations sysfs_dentry_ops = {
++ .d_revalidate = sysfs_dentry_revalidate,
++ .d_delete = sysfs_dentry_delete,
+ .d_iput = sysfs_dentry_iput,
+ };
+
+@@ -527,44 +569,21 @@ void sysfs_remove_one(struct sysfs_addrm
+ }
+
+ /**
+- * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent
++ * sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent
+ * @sd: target sysfs_dirent
+ *
+- * Drop dentry for @sd. @sd must have been unlinked from its
++ * Decrement nlink for @sd. @sd must have been unlinked from its
+ * parent on entry to this function such that it can't be looked
+ * up anymore.
+ */
+-static void sysfs_drop_dentry(struct sysfs_dirent *sd)
++static void sysfs_dec_nlink(struct sysfs_dirent *sd)
+ {
+ struct inode *inode;
+- struct dentry *dentry;
+
+ inode = ilookup(sysfs_sb, sd->s_ino);
+ if (!inode)
+ return;
+
+- /* Drop any existing dentries associated with sd.
+- *
+- * For the dentry to be properly freed we need to grab a
+- * reference to the dentry under the dcache lock, unhash it,
+- * and then put it. The playing with the dentry count allows
+- * dput to immediately free the dentry if it is not in use.
+- */
+-repeat:
+- spin_lock(&dcache_lock);
+- list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+- if (d_unhashed(dentry))
+- continue;
+- dget_locked(dentry);
+- spin_lock(&dentry->d_lock);
+- __d_drop(dentry);
+- spin_unlock(&dentry->d_lock);
+- spin_unlock(&dcache_lock);
+- dput(dentry);
+- goto repeat;
+- }
+- spin_unlock(&dcache_lock);
+-
+ /* adjust nlink and update timestamp */
+ mutex_lock(&inode->i_mutex);
+
+@@ -611,7 +630,7 @@ void sysfs_addrm_finish(struct sysfs_add
+ acxt->removed = sd->s_sibling;
+ sd->s_sibling = NULL;
+
+- sysfs_drop_dentry(sd);
++ sysfs_dec_nlink(sd);
+ sysfs_deactivate(sd);
+ unmap_bin_file(sd);
+ sysfs_put(sd);
diff --git a/series b/series
index 63a9ec466f3d7c..edc68fc4179a38 100644
--- a/series
+++ b/series
@@ -54,6 +54,11 @@ driver-core/driver-core-devtmpfs-set-root-directory-mode-to-0755.patch
driver-core/firmware_class-make-request_firmware_nowait-more-useful.patch
driver-core/driver-core-don-t-remove-kobjects-in-device_shutdown.patch
driver-core/debugfs-fix-create-mutex-racy-fops-and-private-data.patch
+driver-core/sysfs-update-sysfs_setxattr-so-it-updates-secdata-under-the-sysfs_mutex.patch
+driver-core/sysfs-rename-sysfs_d_iput-to-sysfs_dentry_iput.patch
+driver-core/sysfs-use-dentry_ops-instead-of-directly-playing-with-the-dcache.patch
+driver-core/sysfs-simplify-sysfs_chmod_file-semantics.patch
+driver-core/sysfs-simplify-iattr-time-assignments.patch
#################################
@@ -153,6 +158,41 @@ usb/usb-ark3116-callbacks-for-interrupt-and-bulk-read.patch
usb/usb-ark3116-cleanup-of-now-unneeded-functions.patch
usb/usb-option.c-add-support-for-d-link-dwm-162-u5.patch
usb/usb-hcd.c-quiet-null-pointer-sparse-noise.patch
+usb/usb-remove-the-auto_pm-flag.patch
+usb/usb-r8a66597-clean-up.-remove-unneeded-null-checks.patch
+usb/usb-fix-possible-null-deref-in-init_usb_class.patch
+usb/usbtest-make-module-param-pattern-writeable.patch
+usb/usb-xhci-add-tests-for-trb-address-translation.patch
+usb/usb-g_mass_storage-mass-storage-function-created.patch
+usb/usb-g_mass_storage-fsg_config-added-module-params-handlig-changed.patch
+usb/usb-g_mass_storage-lun_name_format-and-thread_name-added.patch
+usb/usb-g_mass_storage-code-cleaned-up-and-comments-updated.patch
+usb/usb-g_mass_storage-most-data-moved-to-fsg_common.patch
+usb/usb-composite-usb_composite_unregister-no-longer-__exit.patch
+usb/usb-g_mass_storage-thread_exits-callback-added.patch
+usb/usb-g_multi-multifunction-composite-gadget-added.patch
+usb/usb-xhci-set-transfer-descriptor-size-field-correctly.patch
+usb/usb-xhci-return-eproto-on-a-split-transaction-error.patch
+usb/usb-xhci-return-success-for-vendor-specific-info-codes.patch
+usb/usb-xhci-handle-errors-that-cause-endpoint-halts.patch
+usb/usb-musb-tweak-musb_read_fifo-to-avoid-unused-warnings.patch
+usb/usb-musb-kill-compile-warning-for-blackfin-systems.patch
+usb/usb-musb-kill-some-useless-comments-in-blackfin-driver.patch
+usb/usb-musb-update-blackfin-processor-dependency.patch
+usb/usb-musb-add-notes-for-blackfin-anomalies.patch
+usb/usb-musb-add-work-around-for-blackfin-anomaly-05000456.patch
+usb/usb-musb-fix-musb_platform_set_mode-definition.patch
+usb/usb-musb-clear-the-blackfin-interrupt-pending-bits-early-in-the-isr.patch
+usb/usb-musb-error-out-when-anomaly-05000380-is-applicable.patch
+usb/usb-musb-blackfin-code-needs-nop_usb_xceiv-too.patch
+usb/usb-musb-fix-printf-warning-in-debug-code.patch
+usb/usb-musb-save-hardware-revision-at-init.patch
+usb/usb-musb_gadget_ep0-fix-unhandled-endpoint-0-irqs-again.patch
+usb/usb-musb_gadget-implement-set_wedge-method.patch
+usb/usb-musb_gadget_ep0-stop-abusing-musb_gadget_set_halt.patch
+usb/usb-musb_gadget-remove-pointless-loop.patch
+usb/usb-usbtmc-repeat-usb_bulk_msg-until-whole-message-is-transfered.patch
+usb/usb-twl4030-enable-usb-regulators-before-enabling-usb-charging.patch
#################################
diff --git a/usb/usb-composite-usb_composite_unregister-no-longer-__exit.patch b/usb/usb-composite-usb_composite_unregister-no-longer-__exit.patch
new file mode 100644
index 00000000000000..e7d75f861f9f6e
--- /dev/null
+++ b/usb/usb-composite-usb_composite_unregister-no-longer-__exit.patch
@@ -0,0 +1,45 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:28:47 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:25 +0100
+Subject: USB: composite: usb_composite_unregister() no longer __exit
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-7-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+Changed definition of usb_composite_unregister() function
+removing __exit declaration. This way, the function is
+included even if the whole code was not compiled as module.
+This is required if a compiled-in code would like to
+unregister a composite gadget.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/composite.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/gadget/composite.c
++++ b/drivers/usb/gadget/composite.c
+@@ -1092,7 +1092,8 @@ static struct usb_gadget_driver composit
+ .speed = USB_SPEED_HIGH,
+
+ .bind = composite_bind,
+- .unbind = __exit_p(composite_unbind),
++ /* .unbind = __exit_p(composite_unbind), */
++ .unbind = composite_unbind,
+
+ .setup = composite_setup,
+ .disconnect = composite_disconnect,
+@@ -1141,7 +1142,7 @@ int __init usb_composite_register(struct
+ * This function is used to unregister drivers using the composite
+ * driver framework.
+ */
+-void __exit usb_composite_unregister(struct usb_composite_driver *driver)
++void /* __exit */ usb_composite_unregister(struct usb_composite_driver *driver)
+ {
+ if (composite != driver)
+ return;
diff --git a/usb/usb-fix-possible-null-deref-in-init_usb_class.patch b/usb/usb-fix-possible-null-deref-in-init_usb_class.patch
new file mode 100644
index 00000000000000..e369251ae2bc8e
--- /dev/null
+++ b/usb/usb-fix-possible-null-deref-in-init_usb_class.patch
@@ -0,0 +1,28 @@
+From error27@gmail.com Fri Nov 20 11:55:00 2009
+From: Dan Carpenter <error27@gmail.com>
+Date: Tue, 10 Nov 2009 11:02:08 +0200 (SAST)
+Subject: USB: fix possible null deref in init_usb_class()
+Cc: gregkh@suse.de
+Message-ID: <alpine.DEB.2.00.0911071737130.19646@bicker>
+
+Add a missing goto. We dereference usb_class on the next line.
+
+Found by smatch static checker.
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/file.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/core/file.c
++++ b/drivers/usb/core/file.c
+@@ -99,6 +99,7 @@ static int init_usb_class(void)
+ printk(KERN_ERR "class_create failed for usb devices\n");
+ kfree(usb_class);
+ usb_class = NULL;
++ goto exit;
+ }
+ usb_class->class->devnode = usb_devnode;
+
diff --git a/usb/usb-g_mass_storage-code-cleaned-up-and-comments-updated.patch b/usb/usb-g_mass_storage-code-cleaned-up-and-comments-updated.patch
new file mode 100644
index 00000000000000..4b418039dad910
--- /dev/null
+++ b/usb/usb-g_mass_storage-code-cleaned-up-and-comments-updated.patch
@@ -0,0 +1,1453 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:28:24 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:23 +0100
+Subject: USB: g_mass_storage: code cleaned up and comments updated
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-5-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+Fixed most of the errors and warnings in f_mass_storage.c and
+storage_common.c reported by checkpatch.pl as well as updated
+comments.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_mass_storage.c | 575 ++++++++++++++++++++----------------
+ drivers/usb/gadget/mass_storage.c | 6
+ drivers/usb/gadget/storage_common.c | 108 +++---
+ 3 files changed, 391 insertions(+), 298 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -1,7 +1,9 @@
+ /*
+- * file_storage.c -- File-backed USB Storage Gadget, for USB development
++ * f_mass_storage.c -- Mass Storage USB Composite Function
+ *
+ * Copyright (C) 2003-2008 Alan Stern
++ * Copyright (C) 2009 Samsung Electronics
++ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+@@ -37,37 +39,112 @@
+
+
+ /*
+- * The File-backed Storage Gadget acts as a USB Mass Storage device,
+- * appearing to the host as a disk drive or as a CD-ROM drive. In addition
+- * to providing an example of a genuinely useful gadget driver for a USB
+- * device, it also illustrates a technique of double-buffering for increased
+- * throughput. Last but not least, it gives an easy way to probe the
+- * behavior of the Mass Storage drivers in a USB host.
+- *
+- * Backing storage is provided by a regular file or a block device, specified
+- * by the "file" module parameter. Access can be limited to read-only by
+- * setting the optional "ro" module parameter. (For CD-ROM emulation,
+- * access is always read-only.) The gadget will indicate that it has
+- * removable media if the optional "removable" module parameter is set.
+- *
+- * There is support for multiple logical units (LUNs), each of which has
+- * its own backing file. The number of LUNs can be set using the optional
+- * "luns" module parameter (anywhere from 1 to 8), and the corresponding
+- * files are specified using comma-separated lists for "file" and "ro".
+- * The default number of LUNs is taken from the number of "file" elements;
+- * it is 1 if "file" is not given. If "removable" is not set then a backing
+- * file must be specified for each LUN. If it is set, then an unspecified
+- * or empty backing filename means the LUN's medium is not loaded. Ideally
+- * each LUN would be settable independently as a disk drive or a CD-ROM
+- * drive, but currently all LUNs have to be the same type. The CD-ROM
+- * emulation includes a single data track and no audio tracks; hence there
+- * need be only one backing file per LUN. Note also that the CD-ROM block
+- * length is set to 512 rather than the more common value 2048.
++ * The Mass Storage Function acts as a USB Mass Storage device,
++ * appearing to the host as a disk drive or as a CD-ROM drive. In
++ * addition to providing an example of a genuinely useful composite
++ * function for a USB device, it also illustrates a technique of
++ * double-buffering for increased throughput.
++ *
++ * Function supports multiple logical units (LUNs). Backing storage
++ * for each LUN is provided by a regular file or a block device.
++ * Access for each LUN can be limited to read-only. Moreover, the
++ * function can indicate that LUN is removable and/or CD-ROM. (The
++ * later implies read-only access.)
++ *
++ * MSF is configured by specifying a fsg_config structure. It has the
++ * following fields:
++ *
++ * nluns Number of LUNs function have (anywhere from 1
++ * to FSG_MAX_LUNS which is 8).
++ * luns An array of LUN configuration values. This
++ * should be filled for each LUN that
++ * function will include (ie. for "nluns"
++ * LUNs). Each element of the array has
++ * the following fields:
++ * ->filename The path to the backing file for the LUN.
++ * Required if LUN is not marked as
++ * removable.
++ * ->ro Flag specifying access to the LUN shall be
++ * read-only. This is implied if CD-ROM
++ * emulation is enabled as well as when
++ * it was impossible to open "filename"
++ * in R/W mode.
++ * ->removable Flag specifying that LUN shall be indicated as
++ * being removable.
++ * ->cdrom Flag specifying that LUN shall be reported as
++ * being a CD-ROM.
++ *
++ * lun_name_format A printf-like format for names of the LUN
++ * devices. This determines how the
++ * directory in sysfs will be named.
++ * Unless you are using several MSFs in
++ * a single gadget (as opposed to single
++ * MSF in many configurations) you may
++ * leave it as NULL (in which case
++ * "lun%d" will be used). In the format
++ * you can use "%d" to index LUNs for
++ * MSF's with more than one LUN. (Beware
++ * that there is only one integer given
++ * as an argument for the format and
++ * specifying invalid format may cause
++ * unspecified behaviour.)
++ * thread_name Name of the kernel thread process used by the
++ * MSF. You can safely set it to NULL
++ * (in which case default "file-storage"
++ * will be used).
++ *
++ * vendor_name
++ * product_name
++ * release Information used as a reply to INQUIRY
++ * request. To use default set to NULL,
++ * NULL, 0xffff respectively. The first
++ * field should be 8 and the second 16
++ * characters or less.
++ *
++ * can_stall Set to permit function to halt bulk endpoints.
++ * Disabled on some USB devices known not
++ * to work correctly. You should set it
++ * to true.
++ *
++ * If "removable" is not set for a LUN then a backing file must be
++ * specified. If it is set, then NULL filename means the LUN's medium
++ * is not loaded (an empty string as "filename" in the fsg_config
++ * structure causes error). The CD-ROM emulation includes a single
++ * data track and no audio tracks; hence there need be only one
++ * backing file per LUN. Note also that the CD-ROM block length is
++ * set to 512 rather than the more common value 2048.
++ *
++ *
++ * MSF includes support for module parameters. If gadget using it
++ * decides to use it, the following module parameters will be
++ * available:
++ *
++ * file=filename[,filename...]
++ * Names of the files or block devices used for
++ * backing storage.
++ * ro=b[,b...] Default false, boolean for read-only access.
++ * removable=b[,b...]
++ * Default true, boolean for removable media.
++ * cdrom=b[,b...] Default false, boolean for whether to emulate
++ * a CD-ROM drive.
++ * luns=N Default N = number of filenames, number of
++ * LUNs to support.
++ * stall Default determined according to the type of
++ * USB device controller (usually true),
++ * boolean to permit the driver to halt
++ * bulk endpoints.
++ *
++ * The module parameters may be prefixed with some string. You need
++ * to consult gadget's documentation or source to verify whether it is
++ * using those module parameters and if it does what are the prefixes
++ * (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is
++ * the prefix).
++ *
+ *
+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
+- * needed (an interrupt-out endpoint is also needed for CBI). The memory
+- * requirement amounts to two 16K buffers, size configurable by a parameter.
+- * Support is included for both full-speed and high-speed operation.
++ * needed. The memory requirement amounts to two 16K buffers, size
++ * configurable by a parameter. Support is included for both
++ * full-speed and high-speed operation.
+ *
+ * Note that the driver is slightly non-portable in that it assumes a
+ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
+@@ -75,39 +152,28 @@
+ * issue, but there may be some with hardware restrictions that prevent
+ * a buffer from being used by more than one endpoint.
+ *
+- * Module options:
+ *
+- * file=filename[,filename...]
+- * Required if "removable" is not set, names of
+- * the files or block devices used for
+- * backing storage
+- * ro=b[,b...] Default false, booleans for read-only access
+- * removable Default false, boolean for removable media
+- * luns=N Default N = number of filenames, number of
+- * LUNs to support
+- * stall Default determined according to the type of
+- * USB device controller (usually true),
+- * boolean to permit the driver to halt
+- * bulk endpoints
+- * cdrom Default false, boolean for whether to emulate
+- * a CD-ROM drive
+- *
+- * The pathnames of the backing files and the ro settings are available in
+- * the attribute files "file" and "ro" in the lun<n> subdirectory of the
+- * gadget's sysfs directory. If the "removable" option is set, writing to
+- * these files will simulate ejecting/loading the medium (writing an empty
+- * line means eject) and adjusting a write-enable tab. Changes to the ro
+- * setting are not allowed when the medium is loaded or if CD-ROM emulation
+- * is being used.
+- *
+- * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
+- * The driver's SCSI command interface was based on the "Information
+- * technology - Small Computer System Interface - 2" document from
+- * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
+- * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
+- * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
+- * "Universal Serial Bus Mass Storage Class UFI Command Specification"
+- * document, Revision 1.0, December 14, 1998, available at
++ * The pathnames of the backing files and the ro settings are
++ * available in the attribute files "file" and "ro" in the lun<n> (or
++ * to be more precise in a directory which name comes from
++ * "lun_name_format" option!) subdirectory of the gadget's sysfs
++ * directory. If the "removable" option is set, writing to these
++ * files will simulate ejecting/loading the medium (writing an empty
++ * line means eject) and adjusting a write-enable tab. Changes to the
++ * ro setting are not allowed when the medium is loaded or if CD-ROM
++ * emulation is being used.
++ *
++ *
++ * This function is heavily based on "File-backed Storage Gadget" by
++ * Alan Stern which in turn is heavily based on "Gadget Zero" by David
++ * Brownell. The driver's SCSI command interface was based on the
++ * "Information technology - Small Computer System Interface - 2"
++ * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93,
++ * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.
++ * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which
++ * was based on the "Universal Serial Bus Mass Storage Class UFI
++ * Command Specification" document, Revision 1.0, December 14, 1998,
++ * available at
+ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
+ */
+
+@@ -115,7 +181,7 @@
+ /*
+ * Driver Design
+ *
+- * The FSG driver is fairly straightforward. There is a main kernel
++ * The MSF is fairly straightforward. There is a main kernel
+ * thread that handles most of the work. Interrupt routines field
+ * callbacks from the controller driver: bulk- and interrupt-request
+ * completion notifications, endpoint-0 events, and disconnect events.
+@@ -138,17 +204,11 @@
+ * an EXIT exception.
+ *
+ * In normal operation the main thread is started during the gadget's
+- * fsg_bind() callback and stopped during fsg_unbind(). But it can also
+- * exit when it receives a signal, and there's no point leaving the
+- * gadget running when the thread is dead. So just before the thread
+- * exits, it deregisters the gadget driver. This makes things a little
+- * tricky: The driver is deregistered at two places, and the exiting
+- * thread can indirectly call fsg_unbind() which in turn can tell the
+- * thread to exit. The first problem is resolved through the use of the
+- * REGISTERED atomic bitflag; the driver will only be deregistered once.
+- * The second problem is resolved by having fsg_unbind() check
+- * fsg->state; it won't try to stop the thread if the state is already
+- * FSG_STATE_TERMINATED.
++ * fsg_bind() callback and stopped during fsg_unbind(). But it can
++ * also exit when it receives a signal, and there's no point leaving
++ * the gadget running when the thread is dead. At of this moment, MSF
++ * provides no way to deregister the gadget when thread dies -- maybe
++ * a callback functions is needed.
+ *
+ * To provide maximum throughput, the driver uses a circular pipeline of
+ * buffer heads (struct fsg_buffhd). In principle the pipeline can be
+@@ -236,7 +296,7 @@
+ /*------------------------------------------------------------------------*/
+
+ #define FSG_DRIVER_DESC "Mass Storage Function"
+-#define FSG_DRIVER_VERSION "20 November 2008"
++#define FSG_DRIVER_VERSION "2009/09/11"
+
+ static const char fsg_string_interface[] = "Mass Storage";
+
+@@ -307,7 +367,7 @@ struct fsg_config {
+
+ struct fsg_dev {
+ struct usb_function function;
+- struct usb_composite_dev*cdev;
++ struct usb_composite_dev *cdev;
+ struct usb_gadget *gadget; /* Copy of cdev->gadget */
+ struct fsg_common *common;
+
+@@ -322,18 +382,18 @@ struct fsg_dev {
+ const char *ep0req_name;
+
+ unsigned int bulk_out_maxpacket;
+- enum fsg_state state; // For exception handling
++ enum fsg_state state; /* For exception handling */
+ unsigned int exception_req_tag;
+
+ u8 config, new_config;
+
+- unsigned int running : 1;
+- unsigned int bulk_in_enabled : 1;
+- unsigned int bulk_out_enabled : 1;
+- unsigned int phase_error : 1;
+- unsigned int short_packet_received : 1;
+- unsigned int bad_lun_okay : 1;
+- unsigned int can_stall : 1;
++ unsigned int running:1;
++ unsigned int bulk_in_enabled:1;
++ unsigned int bulk_out_enabled:1;
++ unsigned int phase_error:1;
++ unsigned int short_packet_received:1;
++ unsigned int bad_lun_okay:1;
++ unsigned int can_stall:1;
+
+ unsigned long atomic_bitflags;
+ #define REGISTERED 0
+@@ -461,7 +521,7 @@ static void bulk_in_complete(struct usb_
+ if (req->status || req->actual != req->length)
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual, req->length);
+- if (req->status == -ECONNRESET) // Request was cancelled
++ if (req->status == -ECONNRESET) /* Request was cancelled */
+ usb_ep_fifo_flush(ep);
+
+ /* Hold the lock while we update the request and buffer states */
+@@ -483,7 +543,7 @@ static void bulk_out_complete(struct usb
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual,
+ bh->bulk_out_intended_length);
+- if (req->status == -ECONNRESET) // Request was cancelled
++ if (req->status == -ECONNRESET) /* Request was cancelled */
+ usb_ep_fifo_flush(ep);
+
+ /* Hold the lock while we update the request and buffer states */
+@@ -643,7 +703,7 @@ static int do_read(struct fsg_dev *fsg)
+ /* Carry out the file reads */
+ amount_left = fsg->data_size_from_cmnd;
+ if (unlikely(amount_left == 0))
+- return -EIO; // No default reply
++ return -EIO; /* No default reply */
+
+ for (;;) {
+
+@@ -701,7 +761,7 @@ static int do_read(struct fsg_dev *fsg)
+ } else if (nread < amount) {
+ LDBG(curlun, "partial file read: %d/%u\n",
+ (int) nread, amount);
+- nread -= (nread & 511); // Round down to a block
++ nread -= (nread & 511); /* Round down to a block */
+ }
+ file_offset += nread;
+ amount_left -= nread;
+@@ -718,7 +778,7 @@ static int do_read(struct fsg_dev *fsg)
+ }
+
+ if (amount_left == 0)
+- break; // No more left to read
++ break; /* No more left to read */
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+@@ -727,7 +787,7 @@ static int do_read(struct fsg_dev *fsg)
+ fsg->common->next_buffhd_to_fill = bh->next;
+ }
+
+- return -EIO; // No default reply
++ return -EIO; /* No default reply */
+ }
+
+
+@@ -751,7 +811,7 @@ static int do_write(struct fsg_dev *fsg)
+ return -EINVAL;
+ }
+ spin_lock(&curlun->filp->f_lock);
+- curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
++ curlun->filp->f_flags &= ~O_SYNC; /* Default is not to wait */
+ spin_unlock(&curlun->filp->f_lock);
+
+ /* Get the starting Logical Block Address and check that it's
+@@ -769,7 +829,7 @@ static int do_write(struct fsg_dev *fsg)
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+- if (fsg->common->cmnd[1] & 0x08) { // FUA
++ if (fsg->common->cmnd[1] & 0x08) { /* FUA */
+ spin_lock(&curlun->filp->f_lock);
+ curlun->filp->f_flags |= O_SYNC;
+ spin_unlock(&curlun->filp->f_lock);
+@@ -834,8 +894,8 @@ static int do_write(struct fsg_dev *fsg)
+
+ /* amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size */
+- bh->outreq->length = bh->bulk_out_intended_length =
+- amount;
++ bh->outreq->length = amount;
++ bh->bulk_out_intended_length = amount;
+ bh->outreq->short_not_ok = 1;
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+@@ -846,7 +906,7 @@ static int do_write(struct fsg_dev *fsg)
+ /* Write the received data to the backing file */
+ bh = fsg->common->next_buffhd_to_drain;
+ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+- break; // We stopped early
++ break; /* We stopped early */
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+ fsg->common->next_buffhd_to_drain = bh->next;
+@@ -878,7 +938,7 @@ static int do_write(struct fsg_dev *fsg)
+ (unsigned long long) file_offset,
+ (int) nwritten);
+ if (signal_pending(current))
+- return -EINTR; // Interrupted!
++ return -EINTR; /* Interrupted! */
+
+ if (nwritten < 0) {
+ LDBG(curlun, "error in file write: %d\n",
+@@ -888,7 +948,7 @@ static int do_write(struct fsg_dev *fsg)
+ LDBG(curlun, "partial file write: %d/%u\n",
+ (int) nwritten, amount);
+ nwritten -= (nwritten & 511);
+- // Round down to a block
++ /* Round down to a block */
+ }
+ file_offset += nwritten;
+ amount_left_to_write -= nwritten;
+@@ -916,7 +976,7 @@ static int do_write(struct fsg_dev *fsg)
+ return rc;
+ }
+
+- return -EIO; // No default reply
++ return -EIO; /* No default reply */
+ }
+
+
+@@ -976,7 +1036,7 @@ static int do_verify(struct fsg_dev *fsg
+
+ verification_length = get_unaligned_be16(&fsg->common->cmnd[7]);
+ if (unlikely(verification_length == 0))
+- return -EIO; // No default reply
++ return -EIO; /* No default reply */
+
+ /* Prepare to carry out the file verify */
+ amount_left = verification_length << 9;
+@@ -1029,7 +1089,7 @@ static int do_verify(struct fsg_dev *fsg
+ } else if (nread < amount) {
+ LDBG(curlun, "partial file verify: %d/%u\n",
+ (int) nread, amount);
+- nread -= (nread & 511); // Round down to a sector
++ nread -= (nread & 511); /* Round down to a sector */
+ }
+ if (nread == 0) {
+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+@@ -1054,17 +1114,17 @@ static int do_inquiry(struct fsg_dev *fs
+ if (!curlun) { /* Unsupported LUNs are okay */
+ fsg->bad_lun_okay = 1;
+ memset(buf, 0, 36);
+- buf[0] = 0x7f; // Unsupported, no device-type
+- buf[4] = 31; // Additional length
++ buf[0] = 0x7f; /* Unsupported, no device-type */
++ buf[4] = 31; /* Additional length */
+ return 36;
+ }
+
+ buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
+ buf[1] = curlun->removable ? 0x80 : 0;
+- buf[2] = 2; // ANSI SCSI level 2
+- buf[3] = 2; // SCSI-2 INQUIRY data format
+- buf[4] = 31; // Additional length
+- buf[5] = 0; // No special options
++ buf[2] = 2; /* ANSI SCSI level 2 */
++ buf[3] = 2; /* SCSI-2 INQUIRY data format */
++ buf[4] = 31; /* Additional length */
++ buf[5] = 0; /* No special options */
+ buf[6] = 0;
+ buf[7] = 0;
+ memcpy(buf + 8, fsg->common->inquiry_string,
+@@ -1102,7 +1162,7 @@ static int do_request_sense(struct fsg_d
+ }
+ #endif
+
+- if (!curlun) { // Unsupported LUNs are okay
++ if (!curlun) { /* Unsupported LUNs are okay */
+ fsg->bad_lun_okay = 1;
+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+ sdinfo = 0;
+@@ -1117,10 +1177,10 @@ static int do_request_sense(struct fsg_d
+ }
+
+ memset(buf, 0, 18);
+- buf[0] = valid | 0x70; // Valid, current error
++ buf[0] = valid | 0x70; /* Valid, current error */
+ buf[2] = SK(sd);
+ put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
+- buf[7] = 18 - 8; // Additional sense length
++ buf[7] = 18 - 8; /* Additional sense length */
+ buf[12] = ASC(sd);
+ buf[13] = ASCQ(sd);
+ return 18;
+@@ -1209,7 +1269,7 @@ static int do_mode_sense(struct fsg_dev
+ int valid_page = 0;
+ int len, limit;
+
+- if ((fsg->common->cmnd[1] & ~0x08) != 0) { // Mask away DBD
++ if ((fsg->common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+@@ -1228,13 +1288,13 @@ static int do_mode_sense(struct fsg_dev
+ * the mode data length later. */
+ memset(buf, 0, 8);
+ if (mscmnd == SC_MODE_SENSE_6) {
+- buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
++ buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
+ buf += 4;
+ limit = 255;
+- } else { // SC_MODE_SENSE_10
+- buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
++ } else { /* SC_MODE_SENSE_10 */
++ buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
+ buf += 8;
+- limit = 65535; // Should really be FSG_BUFLEN
++ limit = 65535; /* Should really be FSG_BUFLEN */
+ }
+
+ /* No block descriptors */
+@@ -1243,14 +1303,14 @@ static int do_mode_sense(struct fsg_dev
+ * is the Caching page. */
+ if (page_code == 0x08 || all_pages) {
+ valid_page = 1;
+- buf[0] = 0x08; // Page code
+- buf[1] = 10; // Page length
+- memset(buf+2, 0, 10); // None of the fields are changeable
++ buf[0] = 0x08; /* Page code */
++ buf[1] = 10; /* Page length */
++ memset(buf+2, 0, 10); /* None of the fields are changeable */
+
+ if (!changeable_values) {
+- buf[2] = 0x04; // Write cache enable,
+- // Read cache not disabled
+- // No cache retention priorities
++ buf[2] = 0x04; /* Write cache enable, */
++ /* Read cache not disabled */
++ /* No cache retention priorities */
+ put_unaligned_be16(0xffff, &buf[4]);
+ /* Don't disable prefetch */
+ /* Minimum prefetch = 0 */
+@@ -1304,7 +1364,7 @@ static int do_prevent_allow(struct fsg_d
+ }
+
+ prevent = fsg->common->cmnd[4] & 0x01;
+- if ((fsg->common->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
++ if ((fsg->common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+@@ -1323,7 +1383,7 @@ static int do_read_format_capacities(str
+ u8 *buf = (u8 *) bh->buf;
+
+ buf[0] = buf[1] = buf[2] = 0;
+- buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
++ buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */
+ buf += 4;
+
+ put_unaligned_be32(curlun->num_sectors, &buf[0]);
+@@ -1398,7 +1458,7 @@ static int pad_with_zeros(struct fsg_dev
+ u32 nsend;
+ int rc;
+
+- bh->state = BUF_STATE_EMPTY; // For the first iteration
++ bh->state = BUF_STATE_EMPTY; /* For the first iteration */
+ fsg->usb_amount_left = nkeep + fsg->residue;
+ while (fsg->usb_amount_left > 0) {
+
+@@ -1454,8 +1514,8 @@ static int throw_away_data(struct fsg_de
+
+ /* amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size */
+- bh->outreq->length = bh->bulk_out_intended_length =
+- amount;
++ bh->outreq->length = amount;
++ bh->bulk_out_intended_length = amount;
+ bh->outreq->short_not_ok = 1;
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+@@ -1480,7 +1540,7 @@ static int finish_reply(struct fsg_dev *
+
+ switch (fsg->data_dir) {
+ case DATA_DIR_NONE:
+- break; // Nothing to send
++ break; /* Nothing to send */
+
+ /* If we don't know whether the host wants to read or write,
+ * this must be CB or CBI with an unknown command. We mustn't
+@@ -1522,14 +1582,13 @@ static int finish_reply(struct fsg_dev *
+ /* We have processed all we want from the data the host has sent.
+ * There may still be outstanding bulk-out requests. */
+ case DATA_DIR_FROM_HOST:
+- if (fsg->residue == 0)
+- ; // Nothing to receive
++ if (fsg->residue == 0) {
++ /* Nothing to receive */
+
+ /* Did the host stop sending unexpectedly early? */
+- else if (fsg->short_packet_received) {
++ } else if (fsg->short_packet_received) {
+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+- }
+
+ /* We haven't processed all the incoming data. Even though
+ * we may be allowed to stall, doing so would cause a race.
+@@ -1538,17 +1597,17 @@ static int finish_reply(struct fsg_dev *
+ * STALL. Not realizing the endpoint was halted, it wouldn't
+ * clear the halt -- leading to problems later on. */
+ #if 0
+- else if (fsg->can_stall) {
++ } else if (fsg->can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+- }
+ #endif
+
+ /* We can't stall. Read in the excess data and throw it
+ * all away. */
+- else
++ } else {
+ rc = throw_away_data(fsg);
++ }
+ break;
+ }
+ return rc;
+@@ -1593,7 +1652,7 @@ static int send_status(struct fsg_dev *f
+ }
+
+ /* Store and send the Bulk-only CSW */
+- csw = (void*)bh->buf;
++ csw = (void *)bh->buf;
+
+ csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+ csw->Tag = fsg->tag;
+@@ -1629,18 +1688,18 @@ static int check_command(struct fsg_dev
+ sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
+ fsg->data_size);
+ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
+- name, cmnd_size, dirletter[(int) data_dir],
+- fsg->data_size_from_cmnd, fsg->common->cmnd_size, hdlen);
++ name, cmnd_size, dirletter[(int) data_dir],
++ fsg->data_size_from_cmnd, fsg->common->cmnd_size, hdlen);
+
+ /* We can't reply at all until we know the correct data direction
+ * and size. */
+ if (fsg->data_size_from_cmnd == 0)
+ data_dir = DATA_DIR_NONE;
+- if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
++ if (fsg->data_dir == DATA_DIR_UNKNOWN) { /* CB or CBI */
+ fsg->data_dir = data_dir;
+ fsg->data_size = fsg->data_size_from_cmnd;
+
+- } else { // Bulk-only
++ } else { /* Bulk-only */
+ if (fsg->data_size < fsg->data_size_from_cmnd) {
+
+ /* Host data size < Device data size is a phase error.
+@@ -1691,7 +1750,8 @@ static int check_command(struct fsg_dev
+
+ /* Check the LUN */
+ if (fsg->common->lun >= 0 && fsg->common->lun < fsg->common->nluns) {
+- fsg->common->curlun = curlun = &fsg->common->luns[fsg->common->lun];
++ curlun = &fsg->common->luns[fsg->common->lun];
++ fsg->common->curlun = curlun;
+ if (fsg->common->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+@@ -1721,7 +1781,7 @@ static int check_command(struct fsg_dev
+ }
+
+ /* Check that only command bytes listed in the mask are non-zero */
+- fsg->common->cmnd[1] &= 0x1f; // Mask away the LUN
++ fsg->common->cmnd[1] &= 0x1f; /* Mask away the LUN */
+ for (i = 1; i < cmnd_size; ++i) {
+ if (fsg->common->cmnd[i] && !(mask & (1 << i))) {
+ if (curlun)
+@@ -1752,7 +1812,8 @@ static int do_scsi_command(struct fsg_de
+ dump_cdb(fsg->common);
+
+ /* Wait for the next buffer to become available for data or status */
+- bh = fsg->common->next_buffhd_to_drain = fsg->common->next_buffhd_to_fill;
++ bh = fsg->common->next_buffhd_to_fill;
++ fsg->common->next_buffhd_to_drain = bh;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+@@ -1761,141 +1822,163 @@ static int do_scsi_command(struct fsg_de
+ fsg->phase_error = 0;
+ fsg->short_packet_received = 0;
+
+- down_read(&fsg->common->filesem); // We're using the backing file
++ /* We're using the backing file */
++ down_read(&fsg->common->filesem);
+ switch (fsg->common->cmnd[0]) {
+
+ case SC_INQUIRY:
+ fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+- (1<<4), 0,
+- "INQUIRY")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<4), 0,
++ "INQUIRY");
++ if (reply == 0)
+ reply = do_inquiry(fsg, bh);
+ break;
+
+ case SC_MODE_SELECT_6:
+ fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
+- (1<<1) | (1<<4), 0,
+- "MODE SELECT(6)")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
++ (1<<1) | (1<<4), 0,
++ "MODE SELECT(6)");
++ if (reply == 0)
+ reply = do_mode_select(fsg, bh);
+ break;
+
+ case SC_MODE_SELECT_10:
+- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+- if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
+- (1<<1) | (3<<7), 0,
+- "MODE SELECT(10)")) == 0)
++ fsg->data_size_from_cmnd =
++ get_unaligned_be16(&fsg->common->cmnd[7]);
++ reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
++ (1<<1) | (3<<7), 0,
++ "MODE SELECT(10)");
++ if (reply == 0)
+ reply = do_mode_select(fsg, bh);
+ break;
+
+ case SC_MODE_SENSE_6:
+ fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+- (1<<1) | (1<<2) | (1<<4), 0,
+- "MODE SENSE(6)")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<1) | (1<<2) | (1<<4), 0,
++ "MODE SENSE(6)");
++ if (reply == 0)
+ reply = do_mode_sense(fsg, bh);
+ break;
+
+ case SC_MODE_SENSE_10:
+- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+- if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+- (1<<1) | (1<<2) | (3<<7), 0,
+- "MODE SENSE(10)")) == 0)
++ fsg->data_size_from_cmnd =
++ get_unaligned_be16(&fsg->common->cmnd[7]);
++ reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (1<<1) | (1<<2) | (3<<7), 0,
++ "MODE SENSE(10)");
++ if (reply == 0)
+ reply = do_mode_sense(fsg, bh);
+ break;
+
+ case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ fsg->data_size_from_cmnd = 0;
+- if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
+- (1<<4), 0,
+- "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_NONE,
++ (1<<4), 0,
++ "PREVENT-ALLOW MEDIUM REMOVAL");
++ if (reply == 0)
+ reply = do_prevent_allow(fsg);
+ break;
+
+ case SC_READ_6:
+ i = fsg->common->cmnd[4];
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+- if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+- (7<<1) | (1<<4), 1,
+- "READ(6)")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (7<<1) | (1<<4), 1,
++ "READ(6)");
++ if (reply == 0)
+ reply = do_read(fsg);
+ break;
+
+ case SC_READ_10:
+ fsg->data_size_from_cmnd =
+ get_unaligned_be16(&fsg->common->cmnd[7]) << 9;
+- if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+- (1<<1) | (0xf<<2) | (3<<7), 1,
+- "READ(10)")) == 0)
++ reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "READ(10)");
++ if (reply == 0)
+ reply = do_read(fsg);
+ break;
+
+ case SC_READ_12:
+ fsg->data_size_from_cmnd =
+ get_unaligned_be32(&fsg->common->cmnd[6]) << 9;
+- if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
+- (1<<1) | (0xf<<2) | (0xf<<6), 1,
+- "READ(12)")) == 0)
++ reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
++ (1<<1) | (0xf<<2) | (0xf<<6), 1,
++ "READ(12)");
++ if (reply == 0)
+ reply = do_read(fsg);
+ break;
+
+ case SC_READ_CAPACITY:
+ fsg->data_size_from_cmnd = 8;
+- if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+- (0xf<<2) | (1<<8), 1,
+- "READ CAPACITY")) == 0)
++ reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (0xf<<2) | (1<<8), 1,
++ "READ CAPACITY");
++ if (reply == 0)
+ reply = do_read_capacity(fsg, bh);
+ break;
+
+ case SC_READ_HEADER:
+ if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
+ goto unknown_cmnd;
+- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+- if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+- (3<<7) | (0x1f<<1), 1,
+- "READ HEADER")) == 0)
++ fsg->data_size_from_cmnd =
++ get_unaligned_be16(&fsg->common->cmnd[7]);
++ reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (3<<7) | (0x1f<<1), 1,
++ "READ HEADER");
++ if (reply == 0)
+ reply = do_read_header(fsg, bh);
+ break;
+
+ case SC_READ_TOC:
+ if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
+ goto unknown_cmnd;
+- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+- if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+- (7<<6) | (1<<1), 1,
+- "READ TOC")) == 0)
++ fsg->data_size_from_cmnd =
++ get_unaligned_be16(&fsg->common->cmnd[7]);
++ reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (7<<6) | (1<<1), 1,
++ "READ TOC");
++ if (reply == 0)
+ reply = do_read_toc(fsg, bh);
+ break;
+
+ case SC_READ_FORMAT_CAPACITIES:
+- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+- if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+- (3<<7), 1,
+- "READ FORMAT CAPACITIES")) == 0)
++ fsg->data_size_from_cmnd =
++ get_unaligned_be16(&fsg->common->cmnd[7]);
++ reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (3<<7), 1,
++ "READ FORMAT CAPACITIES");
++ if (reply == 0)
+ reply = do_read_format_capacities(fsg, bh);
+ break;
+
+ case SC_REQUEST_SENSE:
+ fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+- (1<<4), 0,
+- "REQUEST SENSE")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<4), 0,
++ "REQUEST SENSE");
++ if (reply == 0)
+ reply = do_request_sense(fsg, bh);
+ break;
+
+ case SC_START_STOP_UNIT:
+ fsg->data_size_from_cmnd = 0;
+- if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
+- (1<<1) | (1<<4), 0,
+- "START-STOP UNIT")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_NONE,
++ (1<<1) | (1<<4), 0,
++ "START-STOP UNIT");
++ if (reply == 0)
+ reply = do_start_stop(fsg);
+ break;
+
+ case SC_SYNCHRONIZE_CACHE:
+ fsg->data_size_from_cmnd = 0;
+- if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
+- (0xf<<2) | (3<<7), 1,
+- "SYNCHRONIZE CACHE")) == 0)
++ reply = check_command(fsg, 10, DATA_DIR_NONE,
++ (0xf<<2) | (3<<7), 1,
++ "SYNCHRONIZE CACHE");
++ if (reply == 0)
+ reply = do_synchronize_cache(fsg);
+ break;
+
+@@ -1910,36 +1993,40 @@ static int do_scsi_command(struct fsg_de
+ * support a minimal version: BytChk must be 0. */
+ case SC_VERIFY:
+ fsg->data_size_from_cmnd = 0;
+- if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
+- (1<<1) | (0xf<<2) | (3<<7), 1,
+- "VERIFY")) == 0)
++ reply = check_command(fsg, 10, DATA_DIR_NONE,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "VERIFY");
++ if (reply == 0)
+ reply = do_verify(fsg);
+ break;
+
+ case SC_WRITE_6:
+ i = fsg->common->cmnd[4];
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+- if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
+- (7<<1) | (1<<4), 1,
+- "WRITE(6)")) == 0)
++ reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
++ (7<<1) | (1<<4), 1,
++ "WRITE(6)");
++ if (reply == 0)
+ reply = do_write(fsg);
+ break;
+
+ case SC_WRITE_10:
+ fsg->data_size_from_cmnd =
+ get_unaligned_be16(&fsg->common->cmnd[7]) << 9;
+- if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
+- (1<<1) | (0xf<<2) | (3<<7), 1,
+- "WRITE(10)")) == 0)
++ reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "WRITE(10)");
++ if (reply == 0)
+ reply = do_write(fsg);
+ break;
+
+ case SC_WRITE_12:
+ fsg->data_size_from_cmnd =
+ get_unaligned_be32(&fsg->common->cmnd[6]) << 9;
+- if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
+- (1<<1) | (0xf<<2) | (0xf<<6), 1,
+- "WRITE(12)")) == 0)
++ reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
++ (1<<1) | (0xf<<2) | (0xf<<6), 1,
++ "WRITE(12)");
++ if (reply == 0)
+ reply = do_write(fsg);
+ break;
+
+@@ -1951,14 +2038,15 @@ static int do_scsi_command(struct fsg_de
+ case SC_RELEASE:
+ case SC_RESERVE:
+ case SC_SEND_DIAGNOSTIC:
+- // Fall through
++ /* Fall through */
+
+ default:
+- unknown_cmnd:
++unknown_cmnd:
+ fsg->data_size_from_cmnd = 0;
+ sprintf(unknown, "Unknown x%02x", fsg->common->cmnd[0]);
+- if ((reply = check_command(fsg, fsg->common->cmnd_size,
+- DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) {
++ reply = check_command(fsg, fsg->common->cmnd_size,
++ DATA_DIR_UNKNOWN, 0xff, 0, unknown);
++ if (reply == 0) {
+ fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
+ reply = -EINVAL;
+ }
+@@ -1971,13 +2059,13 @@ static int do_scsi_command(struct fsg_de
+
+ /* Set up the single reply buffer for finish_reply() */
+ if (reply == -EINVAL)
+- reply = 0; // Error reply length
++ reply = 0; /* Error reply length */
+ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
+ reply = min((u32) reply, fsg->data_size_from_cmnd);
+ bh->inreq->length = reply;
+ bh->state = BUF_STATE_FULL;
+ fsg->residue -= reply;
+- } // Otherwise it's already set
++ } /* Otherwise it's already set */
+
+ return 0;
+ }
+@@ -2157,13 +2245,15 @@ reset:
+ /* Enable the endpoints */
+ d = fsg_ep_desc(fsg->gadget,
+ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+- if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
++ rc = enable_endpoint(fsg, fsg->bulk_in, d);
++ if (rc != 0)
+ goto reset;
+ fsg->bulk_in_enabled = 1;
+
+ d = fsg_ep_desc(fsg->gadget,
+ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+- if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
++ rc = enable_endpoint(fsg, fsg->bulk_out, d);
++ if (rc != 0)
+ goto reset;
+ fsg->bulk_out_enabled = 1;
+ fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+@@ -2173,9 +2263,11 @@ reset:
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &fsg->common->buffhds[i];
+
+- if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
++ rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq);
++ if (rc != 0)
+ goto reset;
+- if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
++ rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq);
++ if (rc != 0)
+ goto reset;
+ bh->inreq->buf = bh->outreq->buf = bh->buf;
+ bh->inreq->context = bh->outreq->context = bh;
+@@ -2302,9 +2394,8 @@ static void handle_exception(struct fsg_
+ bh = &fsg->common->buffhds[i];
+ bh->state = BUF_STATE_EMPTY;
+ }
+- fsg->common->next_buffhd_to_fill = fsg->common->next_buffhd_to_drain =
+- &fsg->common->buffhds[0];
+-
++ fsg->common->next_buffhd_to_fill = &fsg->common->buffhds[0];
++ fsg->common->next_buffhd_to_drain = &fsg->common->buffhds[0];
+ exception_req_tag = fsg->exception_req_tag;
+ new_config = fsg->new_config;
+ old_state = fsg->state;
+@@ -2315,8 +2406,8 @@ static void handle_exception(struct fsg_
+ for (i = 0; i < fsg->common->nluns; ++i) {
+ curlun = &fsg->common->luns[i];
+ curlun->prevent_medium_removal = 0;
+- curlun->sense_data = curlun->unit_attention_data =
+- SS_NO_SENSE;
++ curlun->sense_data = SS_NO_SENSE;
++ curlun->unit_attention_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+@@ -2342,30 +2433,31 @@ static void handle_exception(struct fsg_
+ usb_ep_clear_halt(fsg->bulk_in);
+
+ if (fsg->ep0_req_tag == exception_req_tag)
+- ep0_queue(fsg); // Complete the status stage
++ ep0_queue(fsg); /* Complete the status stage */
+
+ /* Technically this should go here, but it would only be
+ * a waste of time. Ditto for the INTERFACE_CHANGE and
+ * CONFIG_CHANGE cases. */
+- // for (i = 0; i < fsg->common->nluns; ++i)
+- // fsg->common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
++ /* for (i = 0; i < fsg->common->nluns; ++i) */
++ /* fsg->common->luns[i].unit_attention_data = */
++ /* SS_RESET_OCCURRED; */
+ break;
+
+ case FSG_STATE_CONFIG_CHANGE:
+ rc = do_set_config(fsg, new_config);
+ if (fsg->ep0_req_tag != exception_req_tag)
+ break;
+- if (rc != 0) // STALL on errors
++ if (rc != 0) /* STALL on errors */
+ fsg_set_halt(fsg, fsg->ep0);
+- else // Complete the status stage
++ else /* Complete the status stage */
+ ep0_queue(fsg);
+ break;
+
+ case FSG_STATE_EXIT:
+ case FSG_STATE_TERMINATED:
+- do_set_config(fsg, 0); // Free resources
++ do_set_config(fsg, 0); /* Free resources */
+ spin_lock_irq(&fsg->lock);
+- fsg->state = FSG_STATE_TERMINATED; // Stop the thread
++ fsg->state = FSG_STATE_TERMINATED; /* Stop the thread */
+ spin_unlock_irq(&fsg->lock);
+ break;
+
+@@ -2645,7 +2737,8 @@ static struct fsg_common *fsg_common_ini
+ error_luns:
+ common->nluns = i + 1;
+ error_release:
+- /* Call fsg_common_release() directly, ref is not initialised */
++ /* Call fsg_common_release() directly, ref might be not
++ * initialised */
+ fsg_common_release(&common->ref);
+ return ERR_PTR(rc);
+ }
+@@ -2721,13 +2814,13 @@ static int fsg_bind(struct usb_configura
+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+- ep->driver_data = fsg; // claim the endpoint
++ ep->driver_data = fsg; /* claim the endpoint */
+ fsg->bulk_in = ep;
+
+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
+ if (!ep)
+ goto autoconf_fail;
+- ep->driver_data = fsg; // claim the endpoint
++ ep->driver_data = fsg; /* claim the endpoint */
+ fsg->bulk_out = ep;
+
+ if (gadget_is_dualspeed(gadget)) {
+@@ -2770,7 +2863,7 @@ autoconf_fail:
+ rc = -ENOTSUPP;
+
+ out:
+- fsg->state = FSG_STATE_TERMINATED; // The thread is dead
++ fsg->state = FSG_STATE_TERMINATED; /* The thread is dead */
+ fsg_unbind(c, f);
+ complete(&fsg->thread_notifier);
+ return rc;
+@@ -2874,18 +2967,16 @@ fsg_config_from_params(struct fsg_config
+ const struct fsg_module_parameters *params)
+ {
+ struct fsg_lun_config *lun;
+- unsigned i, nluns;
++ unsigned i;
+
+ /* Configure LUNs */
+- nluns = cfg->nluns = !params->luns
+- ? params->file_count ? params->file_count : 1
+- : params->luns;
+- for (i = 0, lun = cfg->luns;
+- i < FSG_MAX_LUNS && i < nluns;
+- ++i, ++lun) {
++ cfg->nluns =
++ min(params->luns ?: (params->file_count ?: 1u),
++ (unsigned)FSG_MAX_LUNS);
++ for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
+ lun->ro = !!params->ro[i];
+ lun->cdrom = !!params->cdrom[i];
+- lun->removable =
++ lun->removable = /* Removable by default */
+ params->removable_count <= i || params->removable[i];
+ lun->filename =
+ params->file_count > i && params->file[i][0]
+@@ -2893,7 +2984,7 @@ fsg_config_from_params(struct fsg_config
+ : 0;
+ }
+
+- /* Let FSG use defaults */
++ /* Let MSF use defaults */
+ cfg->lun_name_format = 0;
+ cfg->thread_name = 0;
+ cfg->vendor_name = 0;
+--- a/drivers/usb/gadget/mass_storage.c
++++ b/drivers/usb/gadget/mass_storage.c
+@@ -1,10 +1,10 @@
+ /*
+- * mass_storage.c -- File-backed USB Storage Gadget, for USB development
++ * mass_storage.c -- Mass Storage USB Gadget
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+- *
+ * Copyright (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
++ * All rights reserved.
+ *
+ * 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
+@@ -45,7 +45,7 @@
+ /*-------------------------------------------------------------------------*/
+
+ #define DRIVER_DESC "Mass Storage Gadget"
+-#define DRIVER_VERSION "2009/07/21"
++#define DRIVER_VERSION "2009/09/11"
+
+ /*-------------------------------------------------------------------------*/
+
+--- a/drivers/usb/gadget/storage_common.c
++++ b/drivers/usb/gadget/storage_common.c
+@@ -61,8 +61,8 @@
+ *
+ * DO NOT REUSE THESE IDs with any other driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures. */
+-#define FSG_VENDOR_ID 0x0525 // NetChip
+-#define FSG_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget
++#define FSG_VENDOR_ID 0x0525 /* NetChip */
++#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
+
+
+ /*-------------------------------------------------------------------------*/
+@@ -103,7 +103,7 @@
+ #ifdef DUMP_MSGS
+
+ # define dump_msg(fsg, /* const char * */ label, \
+- /* const u8 * */ buf, /* unsigned */ length) do { \
++ /* const u8 * */ buf, /* unsigned */ length) do { \
+ if (length < 512) { \
+ DBG(fsg, "%s, length %u:\n", label, length); \
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
+@@ -116,11 +116,11 @@
+ #else
+
+ # define dump_msg(fsg, /* const char * */ label, \
+- /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
++ /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
+
+ # ifdef VERBOSE_DEBUG
+
+-#define dump_cdb(fsg) \
++# define dump_cdb(fsg) \
+ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \
+ 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \
+
+@@ -143,45 +143,45 @@
+ #define TYPE_CDROM 0x05
+
+ /* USB protocol value = the transport method */
+-#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt
+-#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt
+-#define USB_PR_BULK 0x50 // Bulk-only
++#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
++#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
++#define USB_PR_BULK 0x50 /* Bulk-only */
+
+ /* USB subclass value = the protocol encapsulation */
+-#define USB_SC_RBC 0x01 // Reduced Block Commands (flash)
+-#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM)
+-#define USB_SC_QIC 0x03 // QIC-157 (tape)
+-#define USB_SC_UFI 0x04 // UFI (floppy)
+-#define USB_SC_8070 0x05 // SFF-8070i (removable)
+-#define USB_SC_SCSI 0x06 // Transparent SCSI
++#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
++#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
++#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
++#define USB_SC_UFI 0x04 /* UFI (floppy) */
++#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
++#define USB_SC_SCSI 0x06 /* Transparent SCSI */
+
+ /* Bulk-only data structures */
+
+ /* Command Block Wrapper */
+ struct fsg_bulk_cb_wrap {
+- __le32 Signature; // Contains 'USBC'
+- u32 Tag; // Unique per command id
+- __le32 DataTransferLength; // Size of the data
+- u8 Flags; // Direction in bit 7
+- u8 Lun; // LUN (normally 0)
+- u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE
+- u8 CDB[16]; // Command Data Block
++ __le32 Signature; /* Contains 'USBC' */
++ u32 Tag; /* Unique per command id */
++ __le32 DataTransferLength; /* Size of the data */
++ u8 Flags; /* Direction in bit 7 */
++ u8 Lun; /* LUN (normally 0) */
++ u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
++ u8 CDB[16]; /* Command Data Block */
+ };
+
+ #define USB_BULK_CB_WRAP_LEN 31
+-#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC
++#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
+ #define USB_BULK_IN_FLAG 0x80
+
+ /* Command Status Wrapper */
+ struct bulk_cs_wrap {
+- __le32 Signature; // Should = 'USBS'
+- u32 Tag; // Same as original command
+- __le32 Residue; // Amount not transferred
+- u8 Status; // See below
++ __le32 Signature; /* Should = 'USBS' */
++ u32 Tag; /* Same as original command */
++ __le32 Residue; /* Amount not transferred */
++ u8 Status; /* See below */
+ };
+
+ #define USB_BULK_CS_WRAP_LEN 13
+-#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS'
++#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
+ #define USB_STATUS_PASS 0
+ #define USB_STATUS_FAIL 1
+ #define USB_STATUS_PHASE_ERROR 2
+@@ -203,7 +203,8 @@ struct interrupt_data {
+ #define USB_CBI_ADSC_REQUEST 0x00
+
+
+-#define MAX_COMMAND_SIZE 16 // Length of a SCSI Command Data Block
++/* Length of a SCSI Command Data Block */
++#define MAX_COMMAND_SIZE 16
+
+ /* SCSI commands that we recognize */
+ #define SC_FORMAT_UNIT 0x04
+@@ -248,7 +249,7 @@ struct interrupt_data {
+ #define SS_WRITE_ERROR 0x030c02
+ #define SS_WRITE_PROTECTED 0x072700
+
+-#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc.
++#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
+ #define ASC(x) ((u8) ((x) >> 8))
+ #define ASCQ(x) ((u8) (x))
+
+@@ -261,13 +262,13 @@ struct fsg_lun {
+ loff_t file_length;
+ loff_t num_sectors;
+
+- unsigned int initially_ro : 1;
+- unsigned int ro : 1;
+- unsigned int removable : 1;
+- unsigned int cdrom : 1;
+- unsigned int prevent_medium_removal : 1;
+- unsigned int registered : 1;
+- unsigned int info_valid : 1;
++ unsigned int initially_ro:1;
++ unsigned int ro:1;
++ unsigned int removable:1;
++ unsigned int cdrom:1;
++ unsigned int prevent_medium_removal:1;
++ unsigned int registered:1;
++ unsigned int info_valid:1;
+
+ u32 sense_data;
+ u32 sense_data_info;
+@@ -286,7 +287,7 @@ static struct fsg_lun *fsg_lun_from_dev(
+
+ /* Big enough to hold our biggest descriptor */
+ #define EP0_BUFSIZE 256
+-#define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value
++#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
+
+ /* Number of buffers we will use. 2 is enough for double-buffering */
+ #define FSG_NUM_BUFFERS 2
+@@ -324,7 +325,8 @@ struct fsg_buffhd {
+ };
+
+ enum fsg_state {
+- FSG_STATE_COMMAND_PHASE = -10, // This one isn't used anywhere
++ /* This one isn't used anywhere */
++ FSG_STATE_COMMAND_PHASE = -10,
+ FSG_STATE_DATA_PHASE,
+ FSG_STATE_STATUS_PHASE,
+
+@@ -386,10 +388,10 @@ fsg_intf_desc = {
+ .bLength = sizeof fsg_intf_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+- .bNumEndpoints = 2, // Adjusted during fsg_bind()
++ .bNumEndpoints = 2, /* Adjusted during fsg_bind() */
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+- .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind()
+- .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind()
++ .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
++ .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
+ .iInterface = FSG_STRING_INTERFACE,
+ };
+
+@@ -426,7 +428,7 @@ fsg_fs_intr_in_desc = {
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(2),
+- .bInterval = 32, // frames -> 32 ms
++ .bInterval = 32, /* frames -> 32 ms */
+ };
+
+ #ifndef FSG_NO_OTG
+@@ -477,7 +479,7 @@ fsg_hs_bulk_out_desc = {
+ /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+- .bInterval = 1, // NAK every 1 uframe
++ .bInterval = 1, /* NAK every 1 uframe */
+ };
+
+ #ifndef FSG_NO_INTR_EP
+@@ -490,7 +492,7 @@ fsg_hs_intr_in_desc = {
+ /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(2),
+- .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms
++ .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
+ };
+
+ #ifndef FSG_NO_OTG
+@@ -538,7 +540,7 @@ static struct usb_string fsg_strings[]
+ };
+
+ static struct usb_gadget_strings fsg_stringtab = {
+- .language = 0x0409, // en-us
++ .language = 0x0409, /* en-us */
+ .strings = fsg_strings,
+ };
+
+@@ -600,11 +602,11 @@ static int fsg_lun_open(struct fsg_lun *
+ rc = (int) size;
+ goto out;
+ }
+- num_sectors = size >> 9; // File size in 512-byte blocks
++ num_sectors = size >> 9; /* File size in 512-byte blocks */
+ min_sectors = 1;
+ if (curlun->cdrom) {
+- num_sectors &= ~3; // Reduce to a multiple of 2048
+- min_sectors = 300*4; // Smallest track is 300 frames
++ num_sectors &= ~3; /* Reduce to a multiple of 2048 */
++ min_sectors = 300*4; /* Smallest track is 300 frames */
+ if (num_sectors >= 256*60*75*4) {
+ num_sectors = (256*60*75 - 1) * 4;
+ LINFO(curlun, "file too big: %s\n", filename);
+@@ -696,17 +698,17 @@ static ssize_t fsg_show_file(struct devi
+ ssize_t rc;
+
+ down_read(filesem);
+- if (fsg_lun_is_open(curlun)) { // Get the complete pathname
++ if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */
+ p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
+ if (IS_ERR(p))
+ rc = PTR_ERR(p);
+ else {
+ rc = strlen(p);
+ memmove(buf, p, rc);
+- buf[rc] = '\n'; // Add a newline
++ buf[rc] = '\n'; /* Add a newline */
+ buf[++rc] = 0;
+ }
+- } else { // No file, return 0 bytes
++ } else { /* No file, return 0 bytes */
+ *buf = 0;
+ rc = 0;
+ }
+@@ -750,12 +752,12 @@ static ssize_t fsg_store_file(struct dev
+
+ if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
+ LDBG(curlun, "eject attempt prevented\n");
+- return -EBUSY; // "Door is locked"
++ return -EBUSY; /* "Door is locked" */
+ }
+
+ /* Remove a trailing newline */
+ if (count > 0 && buf[count-1] == '\n')
+- ((char *) buf)[count-1] = 0; // Ugh!
++ ((char *) buf)[count-1] = 0; /* Ugh! */
+
+ /* Eject current medium */
+ down_write(filesem);
diff --git a/usb/usb-g_mass_storage-fsg_config-added-module-params-handlig-changed.patch b/usb/usb-g_mass_storage-fsg_config-added-module-params-handlig-changed.patch
new file mode 100644
index 00000000000000..3f5657f2399cdb
--- /dev/null
+++ b/usb/usb-g_mass_storage-fsg_config-added-module-params-handlig-changed.patch
@@ -0,0 +1,493 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:26:16 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:21 +0100
+Subject: USB: g_mass_storage: fsg_config added & module params handlig changed
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-3-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+Removed all references to mod_data in f_mass_storage.c and
+instead created fsg_config structure fsg_common_init() takes
+as an argument -- it stores all configuration options that
+were previously taken from mod_data.
+
+Moreover, The fsg_config structure allows per-LUN
+configuration of removable and CD-ROM emulation.
+
+Module parameters are handled by defining an object of
+fsg_module_parameters structure and then declaring module
+parameters via FSG_MODULE_PARAMETERS() macro. It adds proper
+declarations to the code making specified object be populated
+from module parameters.
+
+To use values stored there one may use either
+fsg_config_from_params() which will will a fsg_config structure
+with values taken from fsg_module_parameters structure or
+fsg_common_from_params() which will initialise fsg_common
+structure directly.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_mass_storage.c | 267 +++++++++++++++++++++++-------------
+ drivers/usb/gadget/mass_storage.c | 7
+ 2 files changed, 178 insertions(+), 96 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -253,51 +253,6 @@ static const char fsg_string_interface[]
+ /*-------------------------------------------------------------------------*/
+
+
+-/* Encapsulate the module parameter settings */
+-
+-static struct {
+- char *file[FSG_MAX_LUNS];
+- int ro[FSG_MAX_LUNS];
+- unsigned int num_filenames;
+- unsigned int num_ros;
+- unsigned int nluns;
+-
+- int removable;
+- int can_stall;
+- int cdrom;
+-
+- unsigned short release;
+-} mod_data = { // Default values
+- .removable = 0,
+- .can_stall = 1,
+- .cdrom = 0,
+- .release = 0xffff,
+- };
+-
+-
+-module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
+- S_IRUGO);
+-MODULE_PARM_DESC(file, "names of backing files or devices");
+-
+-module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
+-MODULE_PARM_DESC(ro, "true to force read-only");
+-
+-module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
+-MODULE_PARM_DESC(luns, "number of LUNs");
+-
+-module_param_named(removable, mod_data.removable, bool, S_IRUGO);
+-MODULE_PARM_DESC(removable, "true to simulate removable media");
+-
+-module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
+-MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+-
+-module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
+-MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-
+ /* Data shared by all the FSG instances. */
+ struct fsg_common {
+ struct usb_gadget *gadget;
+@@ -317,12 +272,34 @@ struct fsg_common {
+ struct fsg_lun *luns;
+ struct fsg_lun *curlun;
+
++ unsigned int can_stall:1;
+ unsigned int free_storage_on_release:1;
+
++ /* Vendor (8 chars), product (16 chars), release (4
++ * hexadecimal digits) and NUL byte */
++ char inquiry_string[8 + 16 + 4 + 1];
++
+ struct kref ref;
+ };
+
+
++struct fsg_config {
++ unsigned nluns;
++ struct fsg_lun_config {
++ const char *filename;
++ char ro;
++ char removable;
++ char cdrom;
++ } luns[FSG_MAX_LUNS];
++
++ const char *vendor_name; /* 8 characters or less */
++ const char *product_name; /* 16 characters or less */
++ u16 release;
++
++ char can_stall;
++};
++
++
+ struct fsg_dev {
+ struct usb_function function;
+ struct usb_composite_dev*cdev;
+@@ -351,6 +328,7 @@ struct fsg_dev {
+ unsigned int phase_error : 1;
+ unsigned int short_packet_received : 1;
+ unsigned int bad_lun_okay : 1;
++ unsigned int can_stall : 1;
+
+ unsigned long atomic_bitflags;
+ #define REGISTERED 0
+@@ -1065,13 +1043,10 @@ static int do_verify(struct fsg_dev *fsg
+
+ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+ {
++ struct fsg_lun *curlun = fsg->common->curlun;
+ u8 *buf = (u8 *) bh->buf;
+
+- static char vendor_id[] = "Linux ";
+- static char product_disk_id[] = "File-Stor Gadget";
+- static char product_cdrom_id[] = "File-CD Gadget ";
+-
+- if (!fsg->common->curlun) { // Unsupported LUNs are okay
++ if (!curlun) { /* Unsupported LUNs are okay */
+ fsg->bad_lun_okay = 1;
+ memset(buf, 0, 36);
+ buf[0] = 0x7f; // Unsupported, no device-type
+@@ -1079,18 +1054,16 @@ static int do_inquiry(struct fsg_dev *fs
+ return 36;
+ }
+
+- memset(buf, 0, 8);
+- buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
+- if (mod_data.removable)
+- buf[1] = 0x80;
++ buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
++ buf[1] = curlun->removable ? 0x80 : 0;
+ buf[2] = 2; // ANSI SCSI level 2
+ buf[3] = 2; // SCSI-2 INQUIRY data format
+ buf[4] = 31; // Additional length
+- // No special options
+- sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
+- (mod_data.cdrom ? product_cdrom_id :
+- product_disk_id),
+- mod_data.release);
++ buf[5] = 0; // No special options
++ buf[6] = 0;
++ buf[7] = 0;
++ memcpy(buf + 8, fsg->common->inquiry_string,
++ sizeof fsg->common->inquiry_string);
+ return 36;
+ }
+
+@@ -1303,7 +1276,9 @@ static int do_mode_sense(struct fsg_dev
+
+ static int do_start_stop(struct fsg_dev *fsg)
+ {
+- if (!mod_data.removable) {
++ if (!fsg->common->curlun) {
++ return -EINVAL;
++ } else if (!fsg->common->curlun->removable) {
+ fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+@@ -1316,8 +1291,10 @@ static int do_prevent_allow(struct fsg_d
+ struct fsg_lun *curlun = fsg->common->curlun;
+ int prevent;
+
+- if (!mod_data.removable) {
+- curlun->sense_data = SS_INVALID_COMMAND;
++ if (!fsg->common->curlun) {
++ return -EINVAL;
++ } else if (!fsg->common->curlun->removable) {
++ fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+
+@@ -1505,7 +1482,7 @@ static int finish_reply(struct fsg_dev *
+ * try to send or receive any data. So stall both bulk pipes
+ * if we can and wait for a reset. */
+ case DATA_DIR_UNKNOWN:
+- if (mod_data.can_stall) {
++ if (fsg->can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ rc = halt_bulk_in_endpoint(fsg);
+ }
+@@ -1526,7 +1503,7 @@ static int finish_reply(struct fsg_dev *
+ /* For Bulk-only, if we're allowed to stall then send the
+ * short packet and halt the bulk-in endpoint. If we can't
+ * stall, pad out the remaining data with 0's. */
+- } else if (mod_data.can_stall) {
++ } else if (fsg->can_stall) {
+ bh->inreq->zero = 1;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+@@ -1556,7 +1533,7 @@ static int finish_reply(struct fsg_dev *
+ * STALL. Not realizing the endpoint was halted, it wouldn't
+ * clear the halt -- leading to problems later on. */
+ #if 0
+- else if (mod_data.can_stall) {
++ else if (fsg->can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+@@ -1866,7 +1843,7 @@ static int do_scsi_command(struct fsg_de
+ break;
+
+ case SC_READ_HEADER:
+- if (!mod_data.cdrom)
++ if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
+ goto unknown_cmnd;
+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+@@ -1876,7 +1853,7 @@ static int do_scsi_command(struct fsg_de
+ break;
+
+ case SC_READ_TOC:
+- if (!mod_data.cdrom)
++ if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
+ goto unknown_cmnd;
+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+@@ -2043,7 +2020,7 @@ static int received_cbw(struct fsg_dev *
+
+ /* We can do anything we want here, so let's stall the
+ * bulk pipes if we are allowed to. */
+- if (mod_data.can_stall) {
++ if (fsg->can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ halt_bulk_in_endpoint(fsg);
+ }
+@@ -2499,18 +2476,18 @@ static inline void fsg_common_put(struct
+
+
+ static struct fsg_common *fsg_common_init(struct fsg_common *common,
+- struct usb_composite_dev *cdev)
++ struct usb_composite_dev *cdev,
++ struct fsg_config *cfg)
+ {
+ struct usb_gadget *gadget = cdev->gadget;
+ struct fsg_buffhd *bh;
+ struct fsg_lun *curlun;
++ struct fsg_lun_config *lcfg;
+ int nluns, i, rc;
+ char *pathbuf;
+
+ /* Find out how many LUNs there should be */
+- nluns = mod_data.nluns;
+- if (nluns == 0)
+- nluns = max(mod_data.num_filenames, 1u);
++ nluns = cfg->nluns;
+ if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+ dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
+ return ERR_PTR(-EINVAL);
+@@ -2539,10 +2516,10 @@ static struct fsg_common *fsg_common_ini
+
+ init_rwsem(&common->filesem);
+
+- for (i = 0; i < nluns; ++i, ++curlun) {
+- curlun->cdrom = !!mod_data.cdrom;
+- curlun->ro = mod_data.cdrom || mod_data.ro[i];
+- curlun->removable = mod_data.removable;
++ for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
++ curlun->cdrom = !!lcfg->cdrom;
++ curlun->ro = lcfg->cdrom || lcfg->ro;
++ curlun->removable = lcfg->removable;
+ curlun->dev.release = fsg_lun_release;
+ curlun->dev.parent = &gadget->dev;
+ /* curlun->dev.driver = &fsg_driver.driver; XXX */
+@@ -2564,11 +2541,11 @@ static struct fsg_common *fsg_common_ini
+ if (rc)
+ goto error_luns;
+
+- if (mod_data.file[i] && *mod_data.file[i]) {
+- rc = fsg_lun_open(curlun, mod_data.file[i]);
++ if (lcfg->filename) {
++ rc = fsg_lun_open(curlun, lcfg->filename);
+ if (rc)
+ goto error_luns;
+- } else if (!mod_data.removable) {
++ } else if (!curlun->removable) {
+ ERROR(common, "no file given for LUN%d\n", i);
+ rc = -EINVAL;
+ goto error_luns;
+@@ -2588,33 +2565,40 @@ static struct fsg_common *fsg_common_ini
+ bh->next = common->buffhds;
+
+
+- /* Release */
+- if (mod_data.release == 0xffff) { // Parameter wasn't set
+- int gcnum;
+-
++ /* Prepare inquiryString */
++ if (cfg->release != 0xffff) {
++ i = cfg->release;
++ } else {
+ /* The sa1100 controller is not supported */
+- if (gadget_is_sa1100(gadget))
+- gcnum = -1;
+- else
+- gcnum = usb_gadget_controller_number(gadget);
+- if (gcnum >= 0)
+- mod_data.release = 0x0300 + gcnum;
+- else {
+- WARNING(common, "controller '%s' not recognized\n",
+- gadget->name);
++ i = gadget_is_sa1100(gadget)
++ ? -1
++ : usb_gadget_controller_number(gadget);
++ if (i >= 0) {
++ i = 0x0300 + i;
++ } else {
+ WARNING(common, "controller '%s' not recognized\n",
+ gadget->name);
+- mod_data.release = 0x0399;
++ i = 0x0399;
+ }
+ }
++#define OR(x, y) ((x) ? (x) : (y))
++ snprintf(common->inquiry_string, sizeof common->inquiry_string,
++ "%-8s%-16s%04x",
++ OR(cfg->vendor_name, "Linux "),
++ /* Assume product name dependent on the first LUN */
++ OR(cfg->product_name, common->luns->cdrom
++ ? "File-Stor Gadget"
++ : "File-CD Gadget "),
++ i);
++#undef OR
+
+
+ /* Some peripheral controllers are known not to be able to
+ * halt bulk endpoints correctly. If one of them is present,
+ * disable stalls.
+ */
+- if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
+- mod_data.can_stall = 0;
++ common->can_stall = cfg->can_stall &&
++ !(gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget));
+
+
+ kref_init(&common->ref);
+@@ -2820,6 +2804,7 @@ static int fsg_add(struct usb_composite_
+ * from this function. So instead of incrementing counter now
+ * and decrement in error recovery we increment it only when
+ * call to usb_add_function() was successful. */
++ fsg->can_stall = common->can_stall;
+
+ rc = usb_add_function(c, &fsg->function);
+
+@@ -2830,3 +2815,95 @@ static int fsg_add(struct usb_composite_
+
+ return rc;
+ }
++
++
++
++/************************* Module parameters *************************/
++
++
++struct fsg_module_parameters {
++ char *file[FSG_MAX_LUNS];
++ int ro[FSG_MAX_LUNS];
++ int removable[FSG_MAX_LUNS];
++ int cdrom[FSG_MAX_LUNS];
++
++ unsigned int file_count, ro_count, removable_count, cdrom_count;
++ unsigned int luns; /* nluns */
++ int stall; /* can_stall */
++};
++
++
++#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
++ module_param_array_named(prefix ## name, params.name, type, \
++ &prefix ## params.name ## _count, \
++ S_IRUGO); \
++ MODULE_PARM_DESC(prefix ## name, desc)
++
++#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \
++ module_param_named(prefix ## name, params.name, type, \
++ S_IRUGO); \
++ MODULE_PARM_DESC(prefix ## name, desc)
++
++#define FSG_MODULE_PARAMETERS(prefix, params) \
++ _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \
++ "names of backing files or devices"); \
++ _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \
++ "true to force read-only"); \
++ _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \
++ "true to simulate removable media"); \
++ _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \
++ "true to simulate CD-ROM instead of disk"); \
++ _FSG_MODULE_PARAM(prefix, params, luns, uint, \
++ "number of LUNs"); \
++ _FSG_MODULE_PARAM(prefix, params, stall, bool, \
++ "false to prevent bulk stalls")
++
++
++static void
++fsg_config_from_params(struct fsg_config *cfg,
++ const struct fsg_module_parameters *params)
++{
++ struct fsg_lun_config *lun;
++ unsigned i, nluns;
++
++ /* Configure LUNs */
++ nluns = cfg->nluns = !params->luns
++ ? params->file_count ? params->file_count : 1
++ : params->luns;
++ for (i = 0, lun = cfg->luns;
++ i < FSG_MAX_LUNS && i < nluns;
++ ++i, ++lun) {
++ lun->ro = !!params->ro[i];
++ lun->cdrom = !!params->cdrom[i];
++ lun->removable =
++ params->removable_count <= i || params->removable[i];
++ lun->filename =
++ params->file_count > i && params->file[i][0]
++ ? params->file[i]
++ : 0;
++ }
++
++ /* Let FSG use defaults */
++ cfg->vendor_name = 0;
++ cfg->product_name = 0;
++ cfg->release = 0xffff;
++
++ /* Finalise */
++ cfg->can_stall = params->stall;
++}
++
++static inline struct fsg_common *
++fsg_common_from_params(struct fsg_common *common,
++ struct usb_composite_dev *cdev,
++ const struct fsg_module_parameters *params)
++ __attribute__((unused));
++static inline struct fsg_common *
++fsg_common_from_params(struct fsg_common *common,
++ struct usb_composite_dev *cdev,
++ const struct fsg_module_parameters *params)
++{
++ struct fsg_config cfg;
++ fsg_config_from_params(&cfg, params);
++ return fsg_common_init(common, cdev, &cfg);
++}
++
+--- a/drivers/usb/gadget/mass_storage.c
++++ b/drivers/usb/gadget/mass_storage.c
+@@ -127,6 +127,11 @@ static struct usb_gadget_strings *dev_st
+
+ /****************************** Configurations ******************************/
+
++static struct fsg_module_parameters mod_data = {
++ .stall = 1
++};
++FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
++
+ static int __init msg_do_config(struct usb_configuration *c)
+ {
+ struct fsg_common *common;
+@@ -137,7 +142,7 @@ static int __init msg_do_config(struct u
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+- common = fsg_common_init(0, c->cdev);
++ common = fsg_common_from_params(0, c->cdev, &mod_data);
+ if (IS_ERR(common))
+ return PTR_ERR(common);
+
diff --git a/usb/usb-g_mass_storage-lun_name_format-and-thread_name-added.patch b/usb/usb-g_mass_storage-lun_name_format-and-thread_name-added.patch
new file mode 100644
index 00000000000000..1b1467dbd75b6c
--- /dev/null
+++ b/usb/usb-g_mass_storage-lun_name_format-and-thread_name-added.patch
@@ -0,0 +1,110 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:28:11 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:22 +0100
+Subject: USB: g_mass_storage: lun_name_format and thread_name added
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-4-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+A two fsg_config fields were added:
+* lun_name_format which lets one specify format of a name
+ used when registering LUN devices. It is useful if there
+ would be ever need for two MSFs to be used in a single
+ composite gadget (as opposed to single MSF in two
+ configuration); and
+* thread_name which lets one specify the name of a kernel
+ thread used by MSF. This is not required since two or more
+ threads can have the same name but nevertheless it's here
+ for consistency.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_mass_storage.c | 22 +++++++++++++++++-----
+ 1 file changed, 17 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -233,7 +233,7 @@
+
+
+
+-/*-------------------------------------------------------------------------*/
++/*------------------------------------------------------------------------*/
+
+ #define FSG_DRIVER_DESC "Mass Storage Function"
+ #define FSG_DRIVER_VERSION "20 November 2008"
+@@ -275,6 +275,8 @@ struct fsg_common {
+ unsigned int can_stall:1;
+ unsigned int free_storage_on_release:1;
+
++ const char *thread_name;
++
+ /* Vendor (8 chars), product (16 chars), release (4
+ * hexadecimal digits) and NUL byte */
+ char inquiry_string[8 + 16 + 4 + 1];
+@@ -292,6 +294,9 @@ struct fsg_config {
+ char cdrom;
+ } luns[FSG_MAX_LUNS];
+
++ const char *lun_name_format;
++ const char *thread_name;
++
+ const char *vendor_name; /* 8 characters or less */
+ const char *product_name; /* 16 characters or less */
+ u16 release;
+@@ -2524,8 +2529,11 @@ static struct fsg_common *fsg_common_ini
+ curlun->dev.parent = &gadget->dev;
+ /* curlun->dev.driver = &fsg_driver.driver; XXX */
+ dev_set_drvdata(&curlun->dev, &common->filesem);
+- dev_set_name(&curlun->dev,"%s-lun%d",
+- dev_name(&gadget->dev), i);
++ dev_set_name(&curlun->dev,
++ cfg->lun_name_format
++ ? cfg->lun_name_format
++ : "lun%d",
++ i);
+
+ rc = device_register(&curlun->dev);
+ if (rc) {
+@@ -2590,7 +2598,6 @@ static struct fsg_common *fsg_common_ini
+ ? "File-Stor Gadget"
+ : "File-CD Gadget "),
+ i);
+-#undef OR
+
+
+ /* Some peripheral controllers are known not to be able to
+@@ -2601,7 +2608,10 @@ static struct fsg_common *fsg_common_ini
+ !(gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget));
+
+
++ common->thread_name = OR(cfg->thread_name, "file-storage");
+ kref_init(&common->ref);
++#undef OR
++
+
+ /* Information */
+ INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+@@ -2741,7 +2751,7 @@ static int fsg_bind(struct usb_configura
+
+
+ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+- "file-storage-gadget");
++ fsg->common->thread_name);
+ if (IS_ERR(fsg->thread_task)) {
+ rc = PTR_ERR(fsg->thread_task);
+ goto out;
+@@ -2884,6 +2894,8 @@ fsg_config_from_params(struct fsg_config
+ }
+
+ /* Let FSG use defaults */
++ cfg->lun_name_format = 0;
++ cfg->thread_name = 0;
+ cfg->vendor_name = 0;
+ cfg->product_name = 0;
+ cfg->release = 0xffff;
diff --git a/usb/usb-g_mass_storage-mass-storage-function-created.patch b/usb/usb-g_mass_storage-mass-storage-function-created.patch
new file mode 100644
index 00000000000000..0b278fc81362f8
--- /dev/null
+++ b/usb/usb-g_mass_storage-mass-storage-function-created.patch
@@ -0,0 +1,1285 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:14:22 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:20 +0100
+Subject: USB: g_mass_storage: Mass Storage Function created
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-2-git-send-email-m.nazarewicz@samsung.com>
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+The f_mass_storage.c has been changed into a composite function.
+mass_storage.c file has been introduced which defines a
+g_mass_storage gadget based on composite framework.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/Kconfig | 18 +
+ drivers/usb/gadget/Makefile | 2
+ drivers/usb/gadget/f_mass_storage.c | 644 ++++++++----------------------------
+ drivers/usb/gadget/file_storage.c | 7
+ drivers/usb/gadget/mass_storage.c | 233 +++++++++++++
+ drivers/usb/gadget/storage_common.c | 22 -
+ 6 files changed, 426 insertions(+), 500 deletions(-)
+
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -594,10 +594,9 @@ static int populate_config_buf(struct us
+
+ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
+ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
+- if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
+- function = fsg_hs_function;
+- else
+- function = fsg_fs_function;
++ function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
++ ? (const struct usb_descriptor_header **)fsg_hs_function
++ : (const struct usb_descriptor_header **)fsg_fs_function;
+
+ /* for now, don't advertise srp-only devices */
+ if (!gadget_is_otg(gadget))
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -233,47 +233,23 @@
+
+
+
+-/*
+- * Kbuild is not very cooperative with respect to linking separately
+- * compiled library objects into one module. So for now we won't use
+- * separate compilation ... ensuring init/exit sections work to shrink
+- * the runtime footprint, and giving us at least some parts of what
+- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+- */
+-#include "usbstring.c"
+-#include "config.c"
+-#include "epautoconf.c"
+-
+ /*-------------------------------------------------------------------------*/
+
+-#define DRIVER_DESC "File-backed Storage Gadget"
+-#define DRIVER_NAME "g_file_storage"
+-#define DRIVER_VERSION "20 November 2008"
++#define FSG_DRIVER_DESC "Mass Storage Function"
++#define FSG_DRIVER_VERSION "20 November 2008"
+
+-static char fsg_string_manufacturer[64];
+-static const char fsg_string_product[] = DRIVER_DESC;
+-static char fsg_string_serial[13];
+-static const char fsg_string_config[] = "Self-powered";
+ static const char fsg_string_interface[] = "Mass Storage";
+
+
+ #define FSG_NO_INTR_EP 1
+ #define FSG_BUFFHD_STATIC_BUFFER 1
++#define FSG_NO_DEVICE_STRINGS 1
++#define FSG_NO_OTG 1
++#define FSG_NO_INTR_EP 1
+
+ #include "storage_common.c"
+
+
+-MODULE_DESCRIPTION(DRIVER_DESC);
+-MODULE_AUTHOR("Alan Stern");
+-MODULE_LICENSE("Dual BSD/GPL");
+-
+-/*
+- * This driver assumes self-powered hardware and has no way for users to
+- * trigger remote wakeup. It uses autoconfiguration to select endpoints
+- * and endpoint addresses.
+- */
+-
+-
+ /*-------------------------------------------------------------------------*/
+
+
+@@ -295,6 +271,7 @@ static struct {
+ .removable = 0,
+ .can_stall = 1,
+ .cdrom = 0,
++ .release = 0xffff,
+ };
+
+
+@@ -347,14 +324,18 @@ struct fsg_common {
+
+
+ struct fsg_dev {
++ struct usb_function function;
++ struct usb_composite_dev*cdev;
++ struct usb_gadget *gadget; /* Copy of cdev->gadget */
+ struct fsg_common *common;
+
++ u16 interface_number;
++
+ /* lock protects: state, all the req_busy's */
+ spinlock_t lock;
+- struct usb_gadget *gadget;
+
+- struct usb_ep *ep0; // Handy copy of gadget->ep0
+- struct usb_request *ep0req; // For control responses
++ struct usb_ep *ep0; /* Copy of gadget->ep0 */
++ struct usb_request *ep0req; /* Copy of cdev->req */
+ unsigned int ep0_req_tag;
+ const char *ep0req_name;
+
+@@ -390,6 +371,13 @@ struct fsg_dev {
+ u32 usb_amount_left;
+ };
+
++
++static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
++{
++ return container_of(f, struct fsg_dev, function);
++}
++
++
+ typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+ static int exception_in_progress(struct fsg_dev *fsg)
+@@ -410,10 +398,6 @@ static void set_bulk_out_req_length(stru
+ bh->outreq->length = length;
+ }
+
+-static struct fsg_dev *the_fsg;
+-static struct usb_gadget_driver fsg_driver;
+-
+-
+ /*-------------------------------------------------------------------------*/
+
+ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
+@@ -433,95 +417,6 @@ static int fsg_set_halt(struct fsg_dev *
+
+ /*-------------------------------------------------------------------------*/
+
+-/*
+- * DESCRIPTORS ... most are static, but strings and (full) configuration
+- * descriptors are built on demand. Also the (static) config and interface
+- * descriptors are adjusted during fsg_bind().
+- */
+-
+-/* There is only one configuration. */
+-#define CONFIG_VALUE 1
+-
+-static struct usb_device_descriptor
+-device_desc = {
+- .bLength = sizeof device_desc,
+- .bDescriptorType = USB_DT_DEVICE,
+-
+- .bcdUSB = cpu_to_le16(0x0200),
+- .bDeviceClass = USB_CLASS_PER_INTERFACE,
+-
+- /* The next three values can be overridden by module parameters */
+- .idVendor = cpu_to_le16(FSG_VENDOR_ID),
+- .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
+- .bcdDevice = cpu_to_le16(0xffff),
+-
+- .iManufacturer = FSG_STRING_MANUFACTURER,
+- .iProduct = FSG_STRING_PRODUCT,
+- .iSerialNumber = FSG_STRING_SERIAL,
+- .bNumConfigurations = 1,
+-};
+-
+-static struct usb_config_descriptor
+-config_desc = {
+- .bLength = sizeof config_desc,
+- .bDescriptorType = USB_DT_CONFIG,
+-
+- /* wTotalLength computed by usb_gadget_config_buf() */
+- .bNumInterfaces = 1,
+- .bConfigurationValue = CONFIG_VALUE,
+- .iConfiguration = FSG_STRING_CONFIG,
+- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+- .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
+-};
+-
+-
+-static struct usb_qualifier_descriptor
+-dev_qualifier = {
+- .bLength = sizeof dev_qualifier,
+- .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+-
+- .bcdUSB = cpu_to_le16(0x0200),
+- .bDeviceClass = USB_CLASS_PER_INTERFACE,
+-
+- .bNumConfigurations = 1,
+-};
+-
+-
+-
+-/*
+- * Config descriptors must agree with the code that sets configurations
+- * and with code managing interfaces and their altsettings. They must
+- * also handle different speeds and other-speed requests.
+- */
+-static int populate_config_buf(struct usb_gadget *gadget,
+- u8 *buf, u8 type, unsigned index)
+-{
+- enum usb_device_speed speed = gadget->speed;
+- int len;
+- const struct usb_descriptor_header **function;
+-
+- if (index > 0)
+- return -EINVAL;
+-
+- if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
+- speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
+- if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
+- function = fsg_hs_function;
+- else
+- function = fsg_fs_function;
+-
+- /* for now, don't advertise srp-only devices */
+- if (!gadget_is_otg(gadget))
+- function++;
+-
+- len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
+- ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+- return len;
+-}
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+ /* These routines may be called in process context or in_irq */
+
+ /* Caller must hold fsg->lock */
+@@ -555,25 +450,12 @@ static void raise_exception(struct fsg_d
+
+ /*-------------------------------------------------------------------------*/
+
+-/* The disconnect callback and ep0 routines. These always run in_irq,
+- * except that ep0_queue() is called in the main thread to acknowledge
+- * completion of various requests: set config, set interface, and
+- * Bulk-only device reset. */
+-
+-static void fsg_disconnect(struct usb_gadget *gadget)
+-{
+- struct fsg_dev *fsg = get_gadget_data(gadget);
+-
+- DBG(fsg, "disconnect or port reset\n");
+- raise_exception(fsg, FSG_STATE_DISCONNECT);
+-}
+-
+-
+ static int ep0_queue(struct fsg_dev *fsg)
+ {
+ int rc;
+
+ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
++ fsg->ep0->driver_data = fsg;
+ if (rc != 0 && rc != -ESHUTDOWN) {
+
+ /* We can't do much more than wait for a reset */
+@@ -583,23 +465,6 @@ static int ep0_queue(struct fsg_dev *fsg
+ return rc;
+ }
+
+-static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+- struct fsg_dev *fsg = ep->driver_data;
+-
+- if (req->actual > 0)
+- dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
+- if (req->status || req->actual != req->length)
+- DBG(fsg, "%s --> %d, %u/%u\n", __func__,
+- req->status, req->actual, req->length);
+- if (req->status == -ECONNRESET) // Request was cancelled
+- usb_ep_fifo_flush(ep);
+-
+- if (req->status == 0 && req->context)
+- ((fsg_routine_t) (req->context))(fsg);
+-}
+-
+-
+ /*-------------------------------------------------------------------------*/
+
+ /* Bulk and interrupt endpoint completion handlers.
+@@ -652,9 +517,10 @@ static void bulk_out_complete(struct usb
+
+ /* Ep0 class-specific handlers. These always run in_irq. */
+
+-static int class_setup_req(struct fsg_dev *fsg,
++static int fsg_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+ {
++ struct fsg_dev *fsg = fsg_from_func(f);
+ struct usb_request *req = fsg->ep0req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+@@ -669,7 +535,7 @@ static int class_setup_req(struct fsg_de
+ if (ctrl->bRequestType !=
+ (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+ break;
+- if (w_index != 0 || w_value != 0)
++ if (w_index != fsg->interface_number || w_value != 0)
+ return -EDOM;
+
+ /* Raise an exception to stop the current operation
+@@ -682,7 +548,7 @@ static int class_setup_req(struct fsg_de
+ if (ctrl->bRequestType !=
+ (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+ break;
+- if (w_index != 0 || w_value != 0)
++ if (w_index != fsg->interface_number || w_value != 0)
+ return -EDOM;
+ VDBG(fsg, "get max LUN\n");
+ *(u8 *) req->buf = fsg->common->nluns - 1;
+@@ -700,160 +566,6 @@ static int class_setup_req(struct fsg_de
+
+ /*-------------------------------------------------------------------------*/
+
+-/* Ep0 standard request handlers. These always run in_irq. */
+-
+-static int standard_setup_req(struct fsg_dev *fsg,
+- const struct usb_ctrlrequest *ctrl)
+-{
+- struct usb_request *req = fsg->ep0req;
+- int value = -EOPNOTSUPP;
+- u16 w_index = le16_to_cpu(ctrl->wIndex);
+- u16 w_value = le16_to_cpu(ctrl->wValue);
+-
+- /* Usually this just stores reply data in the pre-allocated ep0 buffer,
+- * but config change events will also reconfigure hardware. */
+- switch (ctrl->bRequest) {
+-
+- case USB_REQ_GET_DESCRIPTOR:
+- if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+- USB_RECIP_DEVICE))
+- break;
+- switch (w_value >> 8) {
+-
+- case USB_DT_DEVICE:
+- VDBG(fsg, "get device descriptor\n");
+- value = sizeof device_desc;
+- memcpy(req->buf, &device_desc, value);
+- break;
+- case USB_DT_DEVICE_QUALIFIER:
+- VDBG(fsg, "get device qualifier\n");
+- if (!gadget_is_dualspeed(fsg->gadget))
+- break;
+- value = sizeof dev_qualifier;
+- memcpy(req->buf, &dev_qualifier, value);
+- break;
+-
+- case USB_DT_OTHER_SPEED_CONFIG:
+- VDBG(fsg, "get other-speed config descriptor\n");
+- if (!gadget_is_dualspeed(fsg->gadget))
+- break;
+- goto get_config;
+- case USB_DT_CONFIG:
+- VDBG(fsg, "get configuration descriptor\n");
+-get_config:
+- value = populate_config_buf(fsg->gadget,
+- req->buf,
+- w_value >> 8,
+- w_value & 0xff);
+- break;
+-
+- case USB_DT_STRING:
+- VDBG(fsg, "get string descriptor\n");
+-
+- /* wIndex == language code */
+- value = usb_gadget_get_string(&fsg_stringtab,
+- w_value & 0xff, req->buf);
+- break;
+- }
+- break;
+-
+- /* One config, two speeds */
+- case USB_REQ_SET_CONFIGURATION:
+- if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+- USB_RECIP_DEVICE))
+- break;
+- VDBG(fsg, "set configuration\n");
+- if (w_value == CONFIG_VALUE || w_value == 0) {
+- fsg->new_config = w_value;
+-
+- /* Raise an exception to wipe out previous transaction
+- * state (queued bufs, etc) and set the new config. */
+- raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
+- value = DELAYED_STATUS;
+- }
+- break;
+- case USB_REQ_GET_CONFIGURATION:
+- if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+- USB_RECIP_DEVICE))
+- break;
+- VDBG(fsg, "get configuration\n");
+- *(u8 *) req->buf = fsg->config;
+- value = 1;
+- break;
+-
+- case USB_REQ_SET_INTERFACE:
+- if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
+- USB_RECIP_INTERFACE))
+- break;
+- if (fsg->config && w_index == 0) {
+-
+- /* Raise an exception to wipe out previous transaction
+- * state (queued bufs, etc) and install the new
+- * interface altsetting. */
+- raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
+- value = DELAYED_STATUS;
+- }
+- break;
+- case USB_REQ_GET_INTERFACE:
+- if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+- USB_RECIP_INTERFACE))
+- break;
+- if (!fsg->config)
+- break;
+- if (w_index != 0) {
+- value = -EDOM;
+- break;
+- }
+- VDBG(fsg, "get interface\n");
+- *(u8 *) req->buf = 0;
+- value = 1;
+- break;
+-
+- default:
+- VDBG(fsg,
+- "unknown control req %02x.%02x v%04x i%04x l%u\n",
+- ctrl->bRequestType, ctrl->bRequest,
+- w_value, w_index, le16_to_cpu(ctrl->wLength));
+- }
+-
+- return value;
+-}
+-
+-
+-static int fsg_setup(struct usb_gadget *gadget,
+- const struct usb_ctrlrequest *ctrl)
+-{
+- struct fsg_dev *fsg = get_gadget_data(gadget);
+- int rc;
+- int w_length = le16_to_cpu(ctrl->wLength);
+-
+- ++fsg->ep0_req_tag; // Record arrival of a new request
+- fsg->ep0req->context = NULL;
+- fsg->ep0req->length = 0;
+- dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
+-
+- if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
+- rc = class_setup_req(fsg, ctrl);
+- else
+- rc = standard_setup_req(fsg, ctrl);
+-
+- /* Respond with data/status or defer until later? */
+- if (rc >= 0 && rc != DELAYED_STATUS) {
+- rc = min(rc, w_length);
+- fsg->ep0req->length = rc;
+- fsg->ep0req->zero = rc < w_length;
+- fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
+- "ep0-in" : "ep0-out");
+- rc = ep0_queue(fsg);
+- }
+-
+- /* Device either stalls (rc < 0) or reports success */
+- return rc;
+-}
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+ /* All the following routines run in process context */
+
+
+@@ -2518,24 +2230,33 @@ static int do_set_config(struct fsg_dev
+ /* Enable the interface */
+ if (new_config != 0) {
+ fsg->config = new_config;
+- if ((rc = do_set_interface(fsg, 0)) != 0)
+- fsg->config = 0; // Reset on errors
+- else {
+- char *speed;
+-
+- switch (fsg->gadget->speed) {
+- case USB_SPEED_LOW: speed = "low"; break;
+- case USB_SPEED_FULL: speed = "full"; break;
+- case USB_SPEED_HIGH: speed = "high"; break;
+- default: speed = "?"; break;
+- }
+- INFO(fsg, "%s speed config #%d\n", speed, fsg->config);
+- }
++ rc = do_set_interface(fsg, 0);
++ if (rc != 0)
++ fsg->config = 0; /* Reset on errors */
+ }
+ return rc;
+ }
+
+
++/****************************** ALT CONFIGS ******************************/
++
++
++static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++ struct fsg_dev *fsg = fsg_from_func(f);
++ fsg->new_config = 1;
++ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++ return 0;
++}
++
++static void fsg_disable(struct usb_function *f)
++{
++ struct fsg_dev *fsg = fsg_from_func(f);
++ fsg->new_config = 0;
++ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++}
++
++
+ /*-------------------------------------------------------------------------*/
+
+ static void handle_exception(struct fsg_dev *fsg)
+@@ -2623,9 +2344,6 @@ static void handle_exception(struct fsg_
+
+ /* Carry out any extra actions required for the exception */
+ switch (old_state) {
+- default:
+- break;
+-
+ case FSG_STATE_ABORT_BULK_OUT:
+ send_status(fsg);
+ spin_lock_irq(&fsg->lock);
+@@ -2651,16 +2369,6 @@ static void handle_exception(struct fsg_
+ // fsg->common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+ break;
+
+- case FSG_STATE_INTERFACE_CHANGE:
+- rc = do_set_interface(fsg, 0);
+- if (fsg->ep0_req_tag != exception_req_tag)
+- break;
+- if (rc != 0) // STALL on errors
+- fsg_set_halt(fsg, fsg->ep0);
+- else // Complete the status stage
+- ep0_queue(fsg);
+- break;
+-
+ case FSG_STATE_CONFIG_CHANGE:
+ rc = do_set_config(fsg, new_config);
+ if (fsg->ep0_req_tag != exception_req_tag)
+@@ -2671,12 +2379,6 @@ static void handle_exception(struct fsg_
+ ep0_queue(fsg);
+ break;
+
+- case FSG_STATE_DISCONNECT:
+- for (i = 0; i < fsg->common->nluns; ++i)
+- fsg_lun_fsync_sub(&fsg->common->luns[i]);
+- do_set_config(fsg, 0); // Unconfigured state
+- break;
+-
+ case FSG_STATE_EXIT:
+ case FSG_STATE_TERMINATED:
+ do_set_config(fsg, 0); // Free resources
+@@ -2684,6 +2386,14 @@ static void handle_exception(struct fsg_
+ fsg->state = FSG_STATE_TERMINATED; // Stop the thread
+ spin_unlock_irq(&fsg->lock);
+ break;
++
++ case FSG_STATE_INTERFACE_CHANGE:
++ case FSG_STATE_DISCONNECT:
++ case FSG_STATE_COMMAND_PHASE:
++ case FSG_STATE_DATA_PHASE:
++ case FSG_STATE_STATUS_PHASE:
++ case FSG_STATE_IDLE:
++ break;
+ }
+ }
+
+@@ -2744,16 +2454,17 @@ static int fsg_main_thread(void *fsg_)
+ if (!exception_in_progress(fsg))
+ fsg->state = FSG_STATE_IDLE;
+ spin_unlock_irq(&fsg->lock);
+- }
++ }
+
+ spin_lock_irq(&fsg->lock);
+ fsg->thread_task = NULL;
+ spin_unlock_irq(&fsg->lock);
+
++ /* XXX */
+ /* If we are exiting because of a signal, unregister the
+ * gadget driver. */
+- if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
+- usb_gadget_unregister_driver(&fsg_driver);
++ /* if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) */
++ /* usb_gadget_unregister_driver(&fsg_driver); */
+
+ /* Let the unbind and cleanup routines know the thread has exited */
+ complete_and_exit(&fsg->thread_notifier, 0);
+@@ -2762,10 +2473,9 @@ static int fsg_main_thread(void *fsg_)
+
+ /*************************** DEVICE ATTRIBUTES ***************************/
+
+-
+-/* The write permissions and store_xxx pointers are set in fsg_bind() */
+-static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
+-static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
++/* Write permission is checked per LUN in store_*() functions. */
++static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
++static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+
+
+ /****************************** FSG COMMON ******************************/
+@@ -2789,11 +2499,13 @@ static inline void fsg_common_put(struct
+
+
+ static struct fsg_common *fsg_common_init(struct fsg_common *common,
+- struct usb_gadget *gadget)
++ struct usb_composite_dev *cdev)
+ {
++ struct usb_gadget *gadget = cdev->gadget;
+ struct fsg_buffhd *bh;
+ struct fsg_lun *curlun;
+ int nluns, i, rc;
++ char *pathbuf;
+
+ /* Find out how many LUNs there should be */
+ nluns = mod_data.nluns;
+@@ -2833,7 +2545,7 @@ static struct fsg_common *fsg_common_ini
+ curlun->removable = mod_data.removable;
+ curlun->dev.release = fsg_lun_release;
+ curlun->dev.parent = &gadget->dev;
+- curlun->dev.driver = &fsg_driver.driver;
++ /* curlun->dev.driver = &fsg_driver.driver; XXX */
+ dev_set_drvdata(&curlun->dev, &common->filesem);
+ dev_set_name(&curlun->dev,"%s-lun%d",
+ dev_name(&gadget->dev), i);
+@@ -2906,6 +2618,33 @@ static struct fsg_common *fsg_common_ini
+
+
+ kref_init(&common->ref);
++
++ /* Information */
++ INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
++ INFO(common, "Number of LUNs=%d\n", common->nluns);
++
++ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
++ for (i = 0, nluns = common->nluns, curlun = common->luns;
++ i < nluns;
++ ++curlun, ++i) {
++ char *p = "(no medium)";
++ if (fsg_lun_is_open(curlun)) {
++ p = "(error)";
++ if (pathbuf) {
++ p = d_path(&curlun->filp->f_path,
++ pathbuf, PATH_MAX);
++ if (IS_ERR(p))
++ p = "(error)";
++ }
++ }
++ LINFO(curlun, "LUN: %s%s%sfile: %s\n",
++ curlun->removable ? "removable " : "",
++ curlun->ro ? "read only " : "",
++ curlun->cdrom ? "CD-ROM " : "",
++ p);
++ }
++ kfree(pathbuf);
++
+ return common;
+
+
+@@ -2944,10 +2683,9 @@ static void fsg_common_release(struct kr
+ /*-------------------------------------------------------------------------*/
+
+
+-static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
++static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+ {
+- struct fsg_dev *fsg = get_gadget_data(gadget);
+- struct usb_request *req = fsg->ep0req;
++ struct fsg_dev *fsg = fsg_from_func(f);
+
+ DBG(fsg, "unbind\n");
+ clear_bit(REGISTERED, &fsg->atomic_bitflags);
+@@ -2961,59 +2699,31 @@ static void /* __init_or_exit */ fsg_unb
+ complete(&fsg->thread_notifier);
+ }
+
+- /* Free the request and buffer for endpoint 0 */
+- if (req) {
+- kfree(req->buf);
+- usb_ep_free_request(fsg->ep0, req);
+- }
+-
+ fsg_common_put(fsg->common);
+ kfree(fsg);
+- set_gadget_data(gadget, NULL);
+ }
+
+
+-static int __init fsg_bind(struct usb_gadget *gadget)
++static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
+ {
+- struct fsg_dev *fsg;
++ struct fsg_dev *fsg = fsg_from_func(f);
++ struct usb_gadget *gadget = c->cdev->gadget;
+ int rc;
+ int i;
+- struct fsg_lun *curlun;
+ struct usb_ep *ep;
+- struct usb_request *req;
+- char *pathbuf, *p;
+-
+- /* Allocate */
+- fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+- if (!fsg)
+- return -ENOMEM;
+
+- /* Initialise common */
+- fsg->common = fsg_common_init(0, gadget);
+- if (IS_ERR(fsg->common))
+- return PTR_ERR(fsg->common);
+-
+- /* Basic parameters */
+ fsg->gadget = gadget;
+- set_gadget_data(gadget, fsg);
+ fsg->ep0 = gadget->ep0;
+- fsg->ep0->driver_data = fsg;
++ fsg->ep0req = c->cdev->req;
+
+- spin_lock_init(&fsg->lock);
+- init_completion(&fsg->thread_notifier);
+-
+- /* Enable the store_xxx attributes */
+- if (mod_data.removable) {
+- dev_attr_file.attr.mode = 0644;
+- dev_attr_file.store = fsg_store_file;
+- if (!mod_data.cdrom) {
+- dev_attr_ro.attr.mode = 0644;
+- dev_attr_ro.store = fsg_store_ro;
+- }
+- }
++ /* New interface */
++ i = usb_interface_id(c, f);
++ if (i < 0)
++ return i;
++ fsg_intf_desc.bInterfaceNumber = i;
++ fsg->interface_number = i;
+
+ /* Find all the endpoints we will use */
+- usb_ep_autoconfig_reset(gadget);
+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+@@ -3026,53 +2736,26 @@ static int __init fsg_bind(struct usb_ga
+ ep->driver_data = fsg; // claim the endpoint
+ fsg->bulk_out = ep;
+
+- /* Fix up the descriptors */
+- device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
+- device_desc.bcdDevice = cpu_to_le16(mod_data.release);
+-
+ if (gadget_is_dualspeed(gadget)) {
+- /* Assume ep0 uses the same maxpacket value for both speeds */
+- dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+-
+ /* Assume endpoint addresses are the same for both speeds */
+ fsg_hs_bulk_in_desc.bEndpointAddress =
+ fsg_fs_bulk_in_desc.bEndpointAddress;
+ fsg_hs_bulk_out_desc.bEndpointAddress =
+ fsg_fs_bulk_out_desc.bEndpointAddress;
++ f->hs_descriptors = fsg_hs_function;
+ }
+
+- if (gadget_is_otg(gadget))
+- fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
+-
+- rc = -ENOMEM;
+
+- /* Allocate the request and buffer for endpoint 0 */
+- fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
+- if (!req)
+- goto out;
+- req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
+- if (!req->buf)
+- goto out;
+- req->complete = ep0_complete;
+-
+- /* This should reflect the actual gadget power source */
+- usb_gadget_set_selfpowered(gadget);
+-
+- snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
+- "%s %s with %s",
+- init_utsname()->sysname, init_utsname()->release,
+- gadget->name);
+-
+- /* On a real device, serial[] would be loaded from permanent
+- * storage. We just encode it from the driver version string. */
+- for (i = 0; i < sizeof fsg_string_serial - 2; i += 2) {
+- unsigned char c = DRIVER_VERSION[i / 2];
+-
+- if (!c)
+- break;
+- sprintf(&fsg_string_serial[i], "%02X", c);
++ /* maybe allocate device-global string IDs, and patch descriptors */
++ if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
++ i = usb_string_id(c->cdev);
++ if (i < 0)
++ return i;
++ fsg_strings[FSG_STRING_INTERFACE].id = i;
++ fsg_intf_desc.iInterface = i;
+ }
+
++
+ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+ "file-storage-gadget");
+ if (IS_ERR(fsg->thread_task)) {
+@@ -3080,37 +2763,12 @@ static int __init fsg_bind(struct usb_ga
+ goto out;
+ }
+
+- INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+- INFO(fsg, "Number of LUNs=%d\n", fsg->common->nluns);
+-
+- pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+- for (i = 0; i < fsg->common->nluns; ++i) {
+- curlun = &fsg->common->luns[i];
+- if (fsg_lun_is_open(curlun)) {
+- p = NULL;
+- if (pathbuf) {
+- p = d_path(&curlun->filp->f_path,
+- pathbuf, PATH_MAX);
+- if (IS_ERR(p))
+- p = NULL;
+- }
+- LINFO(curlun, "ro=%d, file: %s\n",
+- curlun->ro, (p ? p : "(error)"));
+- }
+- }
+- kfree(pathbuf);
+-
+- DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
+- mod_data.removable, mod_data.can_stall,
+- mod_data.cdrom, FSG_BUFLEN);
+ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
+
+ set_bit(REGISTERED, &fsg->atomic_bitflags);
+
+ /* Tell the thread to start working */
+ wake_up_process(fsg->thread_task);
+-
+- the_fsg = fsg;
+ return 0;
+
+ autoconf_fail:
+@@ -3119,48 +2777,56 @@ autoconf_fail:
+
+ out:
+ fsg->state = FSG_STATE_TERMINATED; // The thread is dead
+- fsg_unbind(gadget);
++ fsg_unbind(c, f);
+ complete(&fsg->thread_notifier);
+ return rc;
+ }
+
+
+-/*-------------------------------------------------------------------------*/
++/****************************** ADD FUNCTION ******************************/
+
+-static struct usb_gadget_driver fsg_driver = {
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+- .speed = USB_SPEED_HIGH,
+-#else
+- .speed = USB_SPEED_FULL,
+-#endif
+- .function = (char *) fsg_string_product,
+- .bind = fsg_bind,
+- .unbind = fsg_unbind,
+- .disconnect = fsg_disconnect,
+- .setup = fsg_setup,
+-
+- .driver = {
+- .name = DRIVER_NAME,
+- .owner = THIS_MODULE,
+- // .release = ...
+- // .suspend = ...
+- // .resume = ...
+- },
++static struct usb_gadget_strings *fsg_strings_array[] = {
++ &fsg_stringtab,
++ NULL,
+ };
+
+-
+-static int __init fsg_init(void)
++static int fsg_add(struct usb_composite_dev *cdev,
++ struct usb_configuration *c,
++ struct fsg_common *common)
+ {
+- return usb_gadget_register_driver(&fsg_driver);
+-}
+-module_init(fsg_init);
++ struct fsg_dev *fsg;
++ int rc;
+
++ fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
++ if (unlikely(!fsg))
++ return -ENOMEM;
+
+-static void __exit fsg_cleanup(void)
+-{
+- /* Unregister the driver iff the thread hasn't already done so */
+- if (the_fsg &&
+- test_and_clear_bit(REGISTERED, &the_fsg->atomic_bitflags))
+- usb_gadget_unregister_driver(&fsg_driver);
++ spin_lock_init(&fsg->lock);
++ init_completion(&fsg->thread_notifier);
++
++ fsg->cdev = cdev;
++ fsg->function.name = FSG_DRIVER_DESC;
++ fsg->function.strings = fsg_strings_array;
++ fsg->function.descriptors = fsg_fs_function;
++ fsg->function.bind = fsg_bind;
++ fsg->function.unbind = fsg_unbind;
++ fsg->function.setup = fsg_setup;
++ fsg->function.set_alt = fsg_set_alt;
++ fsg->function.disable = fsg_disable;
++
++ fsg->common = common;
++ /* Our caller holds a reference to common structure so we
++ * don't have to be worry about it being freed until we return
++ * from this function. So instead of incrementing counter now
++ * and decrement in error recovery we increment it only when
++ * call to usb_add_function() was successful. */
++
++ rc = usb_add_function(c, &fsg->function);
++
++ if (likely(rc == 0))
++ fsg_common_get(fsg->common);
++ else
++ kfree(fsg);
++
++ return rc;
+ }
+-module_exit(fsg_cleanup);
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -732,6 +732,24 @@ config USB_FILE_STORAGE_TEST
+ behavior of USB Mass Storage hosts. Not needed for
+ normal operation.
+
++config USB_MASS_STORAGE
++ tristate "Mass Storage Gadget"
++ depends on BLOCK
++ help
++ The Mass Storage Gadget acts as a USB Mass Storage disk drive.
++ As its storage repository it can use a regular file or a block
++ device (in much the same way as the "loop" device driver),
++ specified as a module parameter or sysfs option.
++
++ This is heavily based on File-backed Storage Gadget and in most
++ cases you will want to use FSG instead. This gadget is mostly
++ here to test the functionality of the Mass Storage Function
++ which may be used with composite framework.
++
++ Say "y" to link the driver statically, or "m" to build
++ a dynamically linked module called "g_file_storage". If unsure,
++ consider File-backed Storage Gadget.
++
+ config USB_G_SERIAL
+ tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
+ help
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -39,6 +39,7 @@ g_serial-objs := serial.o
+ g_midi-objs := gmidi.o
+ gadgetfs-objs := inode.o
+ g_file_storage-objs := file_storage.o
++g_mass_storage-objs := mass_storage.o
+ g_printer-objs := printer.o
+ g_cdc-objs := cdc2.o
+
+@@ -47,6 +48,7 @@ obj-$(CONFIG_USB_AUDIO) += g_audio.o
+ obj-$(CONFIG_USB_ETH) += g_ether.o
+ obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
+ obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
++obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
+ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
+ obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
+--- /dev/null
++++ b/drivers/usb/gadget/mass_storage.c
+@@ -0,0 +1,233 @@
++/*
++ * mass_storage.c -- File-backed USB Storage Gadget, for USB development
++ *
++ * Copyright (C) 2003-2008 Alan Stern
++ *
++ * Copyright (C) 2009 Samsung Electronics
++ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
++ *
++ * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++
++/*
++ * The Mass Storage Gadget acts as a USB Mass Storage device,
++ * appearing to the host as a disk drive or as a CD-ROM drive. In
++ * addition to providing an example of a genuinely useful gadget
++ * driver for a USB device, it also illustrates a technique of
++ * double-buffering for increased throughput. Last but not least, it
++ * gives an easy way to probe the behavior of the Mass Storage drivers
++ * in a USB host.
++ *
++ * Since this file serves only administrative purposes and all the
++ * business logic is implemented in f_mass_storage.* file. Read
++ * comments in this file for more detailed description.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/usb/ch9.h>
++
++
++/*-------------------------------------------------------------------------*/
++
++#define DRIVER_DESC "Mass Storage Gadget"
++#define DRIVER_VERSION "2009/07/21"
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * kbuild is not very cooperative with respect to linking separately
++ * compiled library objects into one module. So for now we won't use
++ * separate compilation ... ensuring init/exit sections work to shrink
++ * the runtime footprint, and giving us at least some parts of what
++ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
++ */
++
++#include "composite.c"
++#include "usbstring.c"
++#include "config.c"
++#include "epautoconf.c"
++#include "f_mass_storage.c"
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_device_descriptor msg_device_desc = {
++ .bLength = sizeof msg_device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++
++ .bcdUSB = cpu_to_le16(0x0200),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++
++ /* Vendor and product id can be overridden by module parameters. */
++ .idVendor = cpu_to_le16(FSG_VENDOR_ID),
++ .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
++ /* .bcdDevice = f(hardware) */
++ /* .iManufacturer = DYNAMIC */
++ /* .iProduct = DYNAMIC */
++ /* NO SERIAL NUMBER */
++ .bNumConfigurations = 1,
++};
++
++static struct usb_otg_descriptor otg_descriptor = {
++ .bLength = sizeof otg_descriptor,
++ .bDescriptorType = USB_DT_OTG,
++
++ /* REVISIT SRP-only hardware is possible, although
++ * it would not be called "OTG" ...
++ */
++ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
++};
++
++static const struct usb_descriptor_header *otg_desc[] = {
++ (struct usb_descriptor_header *) &otg_descriptor,
++ NULL,
++};
++
++
++/* string IDs are assigned dynamically */
++
++#define STRING_MANUFACTURER_IDX 0
++#define STRING_PRODUCT_IDX 1
++#define STRING_CONFIGURATION_IDX 2
++
++static char manufacturer[50];
++
++static struct usb_string strings_dev[] = {
++ [STRING_MANUFACTURER_IDX].s = manufacturer,
++ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
++ [STRING_CONFIGURATION_IDX].s = "Self Powered",
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_dev = {
++ .language = 0x0409, /* en-us */
++ .strings = strings_dev,
++};
++
++static struct usb_gadget_strings *dev_strings[] = {
++ &stringtab_dev,
++ NULL,
++};
++
++
++
++/****************************** Configurations ******************************/
++
++static int __init msg_do_config(struct usb_configuration *c)
++{
++ struct fsg_common *common;
++ int ret;
++
++ if (gadget_is_otg(c->cdev->gadget)) {
++ c->descriptors = otg_desc;
++ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
++
++ common = fsg_common_init(0, c->cdev);
++ if (IS_ERR(common))
++ return PTR_ERR(common);
++
++ ret = fsg_add(c->cdev, c, common);
++ fsg_common_put(common);
++ return ret;
++}
++
++static struct usb_configuration msg_config_driver = {
++ .label = "Linux File-Backed Storage",
++ .bind = msg_do_config,
++ .bConfigurationValue = 1,
++ /* .iConfiguration = DYNAMIC */
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++};
++
++
++
++/****************************** Gadget Bind ******************************/
++
++
++static int __init msg_bind(struct usb_composite_dev *cdev)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ int status;
++
++ /* Allocate string descriptor numbers ... note that string
++ * contents can be overridden by the composite_dev glue.
++ */
++
++ /* device descriptor strings: manufacturer, product */
++ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
++ init_utsname()->sysname, init_utsname()->release,
++ gadget->name);
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ strings_dev[STRING_MANUFACTURER_IDX].id = status;
++ msg_device_desc.iManufacturer = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ strings_dev[STRING_PRODUCT_IDX].id = status;
++ msg_device_desc.iProduct = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ strings_dev[STRING_CONFIGURATION_IDX].id = status;
++ msg_config_driver.iConfiguration = status;
++
++ /* register our second configuration */
++ status = usb_add_config(cdev, &msg_config_driver);
++ if (status < 0)
++ return status;
++
++ dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
++ return 0;
++}
++
++static int __exit msg_unbind(struct usb_composite_dev *cdev)
++{
++ return 0;
++}
++
++
++/****************************** Some noise ******************************/
++
++
++static struct usb_composite_driver msg_driver = {
++ .name = "g_mass_storage",
++ .dev = &msg_device_desc,
++ .strings = dev_strings,
++ .bind = msg_bind,
++ .unbind = __exit_p(msg_unbind),
++};
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Michal Nazarewicz");
++MODULE_LICENSE("GPL");
++
++static int __init msg_init(void)
++{
++ return usb_composite_register(&msg_driver);
++}
++module_init(msg_init);
++
++static void __exit msg_cleanup(void)
++{
++ usb_composite_unregister(&msg_driver);
++}
++module_exit(msg_cleanup);
+--- a/drivers/usb/gadget/storage_common.c
++++ b/drivers/usb/gadget/storage_common.c
+@@ -84,11 +84,19 @@
+ #define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
+ #define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
+
+-#define DBG(d, fmt, args...) dev_dbg (&(d)->gadget->dev, fmt, ## args)
+-#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev, fmt, ## args)
+-#define ERROR(d, fmt, args...) dev_err (&(d)->gadget->dev, fmt, ## args)
+-#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev, fmt, ## args)
+-#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev, fmt, ## args)
++/* Keep those macros in sync with thos in
++ * include/linux/ubs/composite.h or else GCC will complain. If they
++ * are identical (the same names of arguments, white spaces in the
++ * same places) GCC will allow redefinition otherwise (even if some
++ * white space is removed or added) warning will be issued. No
++ * checking if those symbols is defined is performed because warning
++ * is desired when those macros were defined by someone else to mean
++ * something else. */
++#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
++#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
++#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
++#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
++#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args)
+
+
+
+@@ -429,7 +437,7 @@ fsg_fs_intr_in_desc = {
+
+ #endif
+
+-static const struct usb_descriptor_header *fsg_fs_function[] = {
++static struct usb_descriptor_header *fsg_fs_function[] = {
+ #ifndef FSG_NO_OTG
+ (struct usb_descriptor_header *) &fsg_otg_desc,
+ #endif
+@@ -493,7 +501,7 @@ fsg_hs_intr_in_desc = {
+
+ #endif
+
+-static const struct usb_descriptor_header *fsg_hs_function[] = {
++static struct usb_descriptor_header *fsg_hs_function[] = {
+ #ifndef FSG_NO_OTG
+ (struct usb_descriptor_header *) &fsg_otg_desc,
+ #endif
diff --git a/usb/usb-g_mass_storage-most-data-moved-to-fsg_common.patch b/usb/usb-g_mass_storage-most-data-moved-to-fsg_common.patch
new file mode 100644
index 00000000000000..a6a4f0efadc344
--- /dev/null
+++ b/usb/usb-g_mass_storage-most-data-moved-to-fsg_common.patch
@@ -0,0 +1,2419 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:28:37 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:24 +0100
+Subject: USB: g_mass_storage: most data moved to fsg_common
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-6-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+Most of the data from fsg_dev have been moved to fsg_common
+structure. The fsg_dev structure holds only endpoint dependent
+data. The fsg_common structure has a fsg pointer which points
+to active fsg_dev structure -- endpoints are referenced via this
+pointer.
+
+This fixes the problem of several threads created when a single
+instance of MSF is used in several USB configurations.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/gadget/f_mass_storage.c | 1230 ++++++++++++++++++------------------
+ 1 file changed, 648 insertions(+), 582 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -312,14 +312,26 @@ static const char fsg_string_interface[]
+
+ /*-------------------------------------------------------------------------*/
+
++struct fsg_dev;
++
+
+ /* Data shared by all the FSG instances. */
+ struct fsg_common {
+ struct usb_gadget *gadget;
++ struct fsg_dev *fsg;
++ struct fsg_dev *prev_fsg;
+
+ /* filesem protects: backing files in use */
+ struct rw_semaphore filesem;
+
++ /* lock protects: state, all the req_busy's */
++ spinlock_t lock;
++
++ struct usb_ep *ep0; /* Copy of gadget->ep0 */
++ struct usb_request *ep0req; /* Copy of cdev->req */
++ unsigned int ep0_req_tag;
++ const char *ep0req_name;
++
+ struct fsg_buffhd *next_buffhd_to_fill;
+ struct fsg_buffhd *next_buffhd_to_drain;
+ struct fsg_buffhd buffhds[FSG_NUM_BUFFERS];
+@@ -332,10 +344,28 @@ struct fsg_common {
+ struct fsg_lun *luns;
+ struct fsg_lun *curlun;
+
++ unsigned int bulk_out_maxpacket;
++ enum fsg_state state; /* For exception handling */
++ unsigned int exception_req_tag;
++
++ u8 config, new_config;
++ enum data_direction data_dir;
++ u32 data_size;
++ u32 data_size_from_cmnd;
++ u32 tag;
++ u32 residue;
++ u32 usb_amount_left;
++
+ unsigned int can_stall:1;
+ unsigned int free_storage_on_release:1;
++ unsigned int phase_error:1;
++ unsigned int short_packet_received:1;
++ unsigned int bad_lun_okay:1;
++ unsigned int running:1;
+
+- const char *thread_name;
++ int thread_wakeup_needed;
++ struct completion thread_notifier;
++ struct task_struct *thread_task;
+
+ /* Vendor (8 chars), product (16 chars), release (4
+ * hexadecimal digits) and NUL byte */
+@@ -367,52 +397,32 @@ struct fsg_config {
+
+ struct fsg_dev {
+ struct usb_function function;
+- struct usb_composite_dev *cdev;
+ struct usb_gadget *gadget; /* Copy of cdev->gadget */
+ struct fsg_common *common;
+
+ u16 interface_number;
+
+- /* lock protects: state, all the req_busy's */
+- spinlock_t lock;
+-
+- struct usb_ep *ep0; /* Copy of gadget->ep0 */
+- struct usb_request *ep0req; /* Copy of cdev->req */
+- unsigned int ep0_req_tag;
+- const char *ep0req_name;
+-
+- unsigned int bulk_out_maxpacket;
+- enum fsg_state state; /* For exception handling */
+- unsigned int exception_req_tag;
+-
+- u8 config, new_config;
+-
+- unsigned int running:1;
+ unsigned int bulk_in_enabled:1;
+ unsigned int bulk_out_enabled:1;
+- unsigned int phase_error:1;
+- unsigned int short_packet_received:1;
+- unsigned int bad_lun_okay:1;
+- unsigned int can_stall:1;
+
+ unsigned long atomic_bitflags;
+-#define REGISTERED 0
+-#define IGNORE_BULK_OUT 1
++#define IGNORE_BULK_OUT 0
+
+ struct usb_ep *bulk_in;
+ struct usb_ep *bulk_out;
++};
+
+- int thread_wakeup_needed;
+- struct completion thread_notifier;
+- struct task_struct *thread_task;
+
+- enum data_direction data_dir;
+- u32 data_size;
+- u32 data_size_from_cmnd;
+- u32 tag;
+- u32 residue;
+- u32 usb_amount_left;
+-};
++static inline int __fsg_is_set(struct fsg_common *common,
++ const char *func, unsigned line)
++{
++ if (common->fsg)
++ return 1;
++ ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
++ return 0;
++}
++
++#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
+
+
+ static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
+@@ -423,21 +433,21 @@ static inline struct fsg_dev *fsg_from_f
+
+ typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+-static int exception_in_progress(struct fsg_dev *fsg)
++static int exception_in_progress(struct fsg_common *common)
+ {
+- return (fsg->state > FSG_STATE_IDLE);
++ return common->state > FSG_STATE_IDLE;
+ }
+
+ /* Make bulk-out requests be divisible by the maxpacket size */
+-static void set_bulk_out_req_length(struct fsg_dev *fsg,
++static void set_bulk_out_req_length(struct fsg_common *common,
+ struct fsg_buffhd *bh, unsigned int length)
+ {
+ unsigned int rem;
+
+ bh->bulk_out_intended_length = length;
+- rem = length % fsg->bulk_out_maxpacket;
++ rem = length % common->bulk_out_maxpacket;
+ if (rem > 0)
+- length += fsg->bulk_out_maxpacket - rem;
++ length += common->bulk_out_maxpacket - rem;
+ bh->outreq->length = length;
+ }
+
+@@ -463,47 +473,46 @@ static int fsg_set_halt(struct fsg_dev *
+ /* These routines may be called in process context or in_irq */
+
+ /* Caller must hold fsg->lock */
+-static void wakeup_thread(struct fsg_dev *fsg)
++static void wakeup_thread(struct fsg_common *common)
+ {
+ /* Tell the main thread that something has happened */
+- fsg->thread_wakeup_needed = 1;
+- if (fsg->thread_task)
+- wake_up_process(fsg->thread_task);
++ common->thread_wakeup_needed = 1;
++ if (common->thread_task)
++ wake_up_process(common->thread_task);
+ }
+
+
+-static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
++static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
+ {
+ unsigned long flags;
+
+ /* Do nothing if a higher-priority exception is already in progress.
+ * If a lower-or-equal priority exception is in progress, preempt it
+ * and notify the main thread by sending it a signal. */
+- spin_lock_irqsave(&fsg->lock, flags);
+- if (fsg->state <= new_state) {
+- fsg->exception_req_tag = fsg->ep0_req_tag;
+- fsg->state = new_state;
+- if (fsg->thread_task)
++ spin_lock_irqsave(&common->lock, flags);
++ if (common->state <= new_state) {
++ common->exception_req_tag = common->ep0_req_tag;
++ common->state = new_state;
++ if (common->thread_task)
+ send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+- fsg->thread_task);
++ common->thread_task);
+ }
+- spin_unlock_irqrestore(&fsg->lock, flags);
++ spin_unlock_irqrestore(&common->lock, flags);
+ }
+
+
+ /*-------------------------------------------------------------------------*/
+
+-static int ep0_queue(struct fsg_dev *fsg)
++static int ep0_queue(struct fsg_common *common)
+ {
+ int rc;
+
+- rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
+- fsg->ep0->driver_data = fsg;
++ rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC);
++ common->ep0->driver_data = common;
+ if (rc != 0 && rc != -ESHUTDOWN) {
+-
+ /* We can't do much more than wait for a reset */
+- WARNING(fsg, "error in submission: %s --> %d\n",
+- fsg->ep0->name, rc);
++ WARNING(common, "error in submission: %s --> %d\n",
++ common->ep0->name, rc);
+ }
+ return rc;
+ }
+@@ -515,32 +524,32 @@ static int ep0_queue(struct fsg_dev *fsg
+
+ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
+ {
+- struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_common *common = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
+
+ if (req->status || req->actual != req->length)
+- DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ DBG(common, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual, req->length);
+ if (req->status == -ECONNRESET) /* Request was cancelled */
+ usb_ep_fifo_flush(ep);
+
+ /* Hold the lock while we update the request and buffer states */
+ smp_wmb();
+- spin_lock(&fsg->lock);
++ spin_lock(&common->lock);
+ bh->inreq_busy = 0;
+ bh->state = BUF_STATE_EMPTY;
+- wakeup_thread(fsg);
+- spin_unlock(&fsg->lock);
++ wakeup_thread(common);
++ spin_unlock(&common->lock);
+ }
+
+ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+ {
+- struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_common *common = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
+
+- dump_msg(fsg, "bulk-out", req->buf, req->actual);
++ dump_msg(common, "bulk-out", req->buf, req->actual);
+ if (req->status || req->actual != bh->bulk_out_intended_length)
+- DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ DBG(common, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual,
+ bh->bulk_out_intended_length);
+ if (req->status == -ECONNRESET) /* Request was cancelled */
+@@ -548,11 +557,11 @@ static void bulk_out_complete(struct usb
+
+ /* Hold the lock while we update the request and buffer states */
+ smp_wmb();
+- spin_lock(&fsg->lock);
++ spin_lock(&common->lock);
+ bh->outreq_busy = 0;
+ bh->state = BUF_STATE_FULL;
+- wakeup_thread(fsg);
+- spin_unlock(&fsg->lock);
++ wakeup_thread(common);
++ spin_unlock(&common->lock);
+ }
+
+
+@@ -564,12 +573,12 @@ static int fsg_setup(struct usb_function
+ const struct usb_ctrlrequest *ctrl)
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
+- struct usb_request *req = fsg->ep0req;
++ struct usb_request *req = fsg->common->ep0req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+- if (!fsg->config)
++ if (!fsg->common->config)
+ return -EOPNOTSUPP;
+
+ switch (ctrl->bRequest) {
+@@ -584,7 +593,7 @@ static int fsg_setup(struct usb_function
+ /* Raise an exception to stop the current operation
+ * and reinitialize our state. */
+ DBG(fsg, "bulk reset request\n");
+- raise_exception(fsg, FSG_STATE_RESET);
++ raise_exception(fsg->common, FSG_STATE_RESET);
+ return DELAYED_STATUS;
+
+ case USB_BULK_GET_MAX_LUN_REQUEST:
+@@ -622,10 +631,10 @@ static void start_transfer(struct fsg_de
+ if (ep == fsg->bulk_in)
+ dump_msg(fsg, "bulk-in", req->buf, req->length);
+
+- spin_lock_irq(&fsg->lock);
++ spin_lock_irq(&fsg->common->lock);
+ *pbusy = 1;
+ *state = BUF_STATE_BUSY;
+- spin_unlock_irq(&fsg->lock);
++ spin_unlock_irq(&fsg->common->lock);
+ rc = usb_ep_queue(ep, req, GFP_KERNEL);
+ if (rc != 0) {
+ *pbusy = 0;
+@@ -642,8 +651,18 @@ static void start_transfer(struct fsg_de
+ }
+ }
+
++#define START_TRANSFER_OR(common, ep_name, req, pbusy, state) \
++ if (fsg_is_set(common)) \
++ start_transfer((common)->fsg, (common)->fsg->ep_name, \
++ req, pbusy, state); \
++ else
++
++#define START_TRANSFER(common, ep_name, req, pbusy, state) \
++ START_TRANSFER_OR(common, ep_name, req, pbusy, state) (void)0
++
+
+-static int sleep_thread(struct fsg_dev *fsg)
++
++static int sleep_thread(struct fsg_common *common)
+ {
+ int rc = 0;
+
+@@ -655,21 +674,21 @@ static int sleep_thread(struct fsg_dev *
+ rc = -EINTR;
+ break;
+ }
+- if (fsg->thread_wakeup_needed)
++ if (common->thread_wakeup_needed)
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+- fsg->thread_wakeup_needed = 0;
++ common->thread_wakeup_needed = 0;
+ return rc;
+ }
+
+
+ /*-------------------------------------------------------------------------*/
+
+-static int do_read(struct fsg_dev *fsg)
++static int do_read(struct fsg_common *common)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ u32 lba;
+ struct fsg_buffhd *bh;
+ int rc;
+@@ -681,15 +700,15 @@ static int do_read(struct fsg_dev *fsg)
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+- if (fsg->common->cmnd[0] == SC_READ_6)
+- lba = get_unaligned_be24(&fsg->common->cmnd[1]);
++ if (common->cmnd[0] == SC_READ_6)
++ lba = get_unaligned_be24(&common->cmnd[1]);
+ else {
+- lba = get_unaligned_be32(&fsg->common->cmnd[2]);
++ lba = get_unaligned_be32(&common->cmnd[2]);
+
+ /* We allow DPO (Disable Page Out = don't save data in the
+ * cache) and FUA (Force Unit Access = don't read from the
+ * cache), but we don't implement them. */
+- if ((fsg->common->cmnd[1] & ~0x18) != 0) {
++ if ((common->cmnd[1] & ~0x18) != 0) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+@@ -701,7 +720,7 @@ static int do_read(struct fsg_dev *fsg)
+ file_offset = ((loff_t) lba) << 9;
+
+ /* Carry out the file reads */
+- amount_left = fsg->data_size_from_cmnd;
++ amount_left = common->data_size_from_cmnd;
+ if (unlikely(amount_left == 0))
+ return -EIO; /* No default reply */
+
+@@ -724,9 +743,9 @@ static int do_read(struct fsg_dev *fsg)
+ partial_page);
+
+ /* Wait for the next buffer to become available */
+- bh = fsg->common->next_buffhd_to_fill;
++ bh = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+@@ -765,7 +784,7 @@ static int do_read(struct fsg_dev *fsg)
+ }
+ file_offset += nread;
+ amount_left -= nread;
+- fsg->residue -= nread;
++ common->residue -= nread;
+ bh->inreq->length = nread;
+ bh->state = BUF_STATE_FULL;
+
+@@ -782,9 +801,12 @@ static int do_read(struct fsg_dev *fsg)
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+- start_transfer(fsg, fsg->bulk_in, bh->inreq,
+- &bh->inreq_busy, &bh->state);
+- fsg->common->next_buffhd_to_fill = bh->next;
++ START_TRANSFER_OR(common, bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state)
++ /* Don't know what to do if
++ * common->fsg is NULL */
++ return -EIO;
++ common->next_buffhd_to_fill = bh->next;
+ }
+
+ return -EIO; /* No default reply */
+@@ -793,9 +815,9 @@ static int do_read(struct fsg_dev *fsg)
+
+ /*-------------------------------------------------------------------------*/
+
+-static int do_write(struct fsg_dev *fsg)
++static int do_write(struct fsg_common *common)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ u32 lba;
+ struct fsg_buffhd *bh;
+ int get_some_more;
+@@ -816,20 +838,20 @@ static int do_write(struct fsg_dev *fsg)
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+- if (fsg->common->cmnd[0] == SC_WRITE_6)
+- lba = get_unaligned_be24(&fsg->common->cmnd[1]);
++ if (common->cmnd[0] == SC_WRITE_6)
++ lba = get_unaligned_be24(&common->cmnd[1]);
+ else {
+- lba = get_unaligned_be32(&fsg->common->cmnd[2]);
++ lba = get_unaligned_be32(&common->cmnd[2]);
+
+ /* We allow DPO (Disable Page Out = don't save data in the
+ * cache) and FUA (Force Unit Access = write directly to the
+ * medium). We don't implement DPO; we implement FUA by
+ * performing synchronous output. */
+- if ((fsg->common->cmnd[1] & ~0x18) != 0) {
++ if (common->cmnd[1] & ~0x18) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+- if (fsg->common->cmnd[1] & 0x08) { /* FUA */
++ if (common->cmnd[1] & 0x08) { /* FUA */
+ spin_lock(&curlun->filp->f_lock);
+ curlun->filp->f_flags |= O_SYNC;
+ spin_unlock(&curlun->filp->f_lock);
+@@ -843,12 +865,13 @@ static int do_write(struct fsg_dev *fsg)
+ /* Carry out the file writes */
+ get_some_more = 1;
+ file_offset = usb_offset = ((loff_t) lba) << 9;
+- amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
++ amount_left_to_req = common->data_size_from_cmnd;
++ amount_left_to_write = common->data_size_from_cmnd;
+
+ while (amount_left_to_write > 0) {
+
+ /* Queue a request for more data from the host */
+- bh = fsg->common->next_buffhd_to_fill;
++ bh = common->next_buffhd_to_fill;
+ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+ /* Figure out how much we want to get:
+@@ -887,7 +910,7 @@ static int do_write(struct fsg_dev *fsg)
+
+ /* Get the next buffer */
+ usb_offset += amount;
+- fsg->usb_amount_left -= amount;
++ common->usb_amount_left -= amount;
+ amount_left_to_req -= amount;
+ if (amount_left_to_req == 0)
+ get_some_more = 0;
+@@ -897,19 +920,22 @@ static int do_write(struct fsg_dev *fsg)
+ bh->outreq->length = amount;
+ bh->bulk_out_intended_length = amount;
+ bh->outreq->short_not_ok = 1;
+- start_transfer(fsg, fsg->bulk_out, bh->outreq,
+- &bh->outreq_busy, &bh->state);
+- fsg->common->next_buffhd_to_fill = bh->next;
++ START_TRANSFER_OR(common, bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state)
++ /* Don't know what to do if
++ * common->fsg is NULL */
++ return -EIO;
++ common->next_buffhd_to_fill = bh->next;
+ continue;
+ }
+
+ /* Write the received data to the backing file */
+- bh = fsg->common->next_buffhd_to_drain;
++ bh = common->next_buffhd_to_drain;
+ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+ break; /* We stopped early */
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+- fsg->common->next_buffhd_to_drain = bh->next;
++ common->next_buffhd_to_drain = bh->next;
+ bh->state = BUF_STATE_EMPTY;
+
+ /* Did something go wrong with the transfer? */
+@@ -952,7 +978,7 @@ static int do_write(struct fsg_dev *fsg)
+ }
+ file_offset += nwritten;
+ amount_left_to_write -= nwritten;
+- fsg->residue -= nwritten;
++ common->residue -= nwritten;
+
+ /* If an error occurred, report it and its position */
+ if (nwritten < amount) {
+@@ -964,14 +990,14 @@ static int do_write(struct fsg_dev *fsg)
+
+ /* Did the host decide to stop early? */
+ if (bh->outreq->actual != bh->outreq->length) {
+- fsg->short_packet_received = 1;
++ common->short_packet_received = 1;
+ break;
+ }
+ continue;
+ }
+
+ /* Wait for something to happen */
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+@@ -982,9 +1008,9 @@ static int do_write(struct fsg_dev *fsg)
+
+ /*-------------------------------------------------------------------------*/
+
+-static int do_synchronize_cache(struct fsg_dev *fsg)
++static int do_synchronize_cache(struct fsg_common *common)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ int rc;
+
+ /* We ignore the requested LBA and write out all file's
+@@ -1008,12 +1034,12 @@ static void invalidate_sub(struct fsg_lu
+ VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc);
+ }
+
+-static int do_verify(struct fsg_dev *fsg)
++static int do_verify(struct fsg_common *common)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ u32 lba;
+ u32 verification_length;
+- struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill;
++ struct fsg_buffhd *bh = common->next_buffhd_to_fill;
+ loff_t file_offset, file_offset_tmp;
+ u32 amount_left;
+ unsigned int amount;
+@@ -1021,7 +1047,7 @@ static int do_verify(struct fsg_dev *fsg
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+- lba = get_unaligned_be32(&fsg->common->cmnd[2]);
++ lba = get_unaligned_be32(&common->cmnd[2]);
+ if (lba >= curlun->num_sectors) {
+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ return -EINVAL;
+@@ -1029,12 +1055,12 @@ static int do_verify(struct fsg_dev *fsg
+
+ /* We allow DPO (Disable Page Out = don't save data in the
+ * cache) but we don't implement it. */
+- if ((fsg->common->cmnd[1] & ~0x10) != 0) {
++ if (common->cmnd[1] & ~0x10) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+
+- verification_length = get_unaligned_be16(&fsg->common->cmnd[7]);
++ verification_length = get_unaligned_be16(&common->cmnd[7]);
+ if (unlikely(verification_length == 0))
+ return -EIO; /* No default reply */
+
+@@ -1106,13 +1132,13 @@ static int do_verify(struct fsg_dev *fsg
+
+ /*-------------------------------------------------------------------------*/
+
+-static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ u8 *buf = (u8 *) bh->buf;
+
+ if (!curlun) { /* Unsupported LUNs are okay */
+- fsg->bad_lun_okay = 1;
++ common->bad_lun_okay = 1;
+ memset(buf, 0, 36);
+ buf[0] = 0x7f; /* Unsupported, no device-type */
+ buf[4] = 31; /* Additional length */
+@@ -1127,15 +1153,14 @@ static int do_inquiry(struct fsg_dev *fs
+ buf[5] = 0; /* No special options */
+ buf[6] = 0;
+ buf[7] = 0;
+- memcpy(buf + 8, fsg->common->inquiry_string,
+- sizeof fsg->common->inquiry_string);
++ memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
+ return 36;
+ }
+
+
+-static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ u8 *buf = (u8 *) bh->buf;
+ u32 sd, sdinfo;
+ int valid;
+@@ -1163,7 +1188,7 @@ static int do_request_sense(struct fsg_d
+ #endif
+
+ if (!curlun) { /* Unsupported LUNs are okay */
+- fsg->bad_lun_okay = 1;
++ common->bad_lun_okay = 1;
+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+ sdinfo = 0;
+ valid = 0;
+@@ -1187,11 +1212,11 @@ static int do_request_sense(struct fsg_d
+ }
+
+
+-static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
+- u32 lba = get_unaligned_be32(&fsg->common->cmnd[2]);
+- int pmi = fsg->common->cmnd[8];
++ struct fsg_lun *curlun = common->curlun;
++ u32 lba = get_unaligned_be32(&common->cmnd[2]);
++ int pmi = common->cmnd[8];
+ u8 *buf = (u8 *) bh->buf;
+
+ /* Check the PMI and LBA fields */
+@@ -1207,14 +1232,14 @@ static int do_read_capacity(struct fsg_d
+ }
+
+
+-static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
+- int msf = fsg->common->cmnd[1] & 0x02;
+- u32 lba = get_unaligned_be32(&fsg->common->cmnd[2]);
++ struct fsg_lun *curlun = common->curlun;
++ int msf = common->cmnd[1] & 0x02;
++ u32 lba = get_unaligned_be32(&common->cmnd[2]);
+ u8 *buf = (u8 *) bh->buf;
+
+- if ((fsg->common->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
++ if (common->cmnd[1] & ~0x02) { /* Mask away MSF */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+@@ -1230,14 +1255,14 @@ static int do_read_header(struct fsg_dev
+ }
+
+
+-static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
+- int msf = fsg->common->cmnd[1] & 0x02;
+- int start_track = fsg->common->cmnd[6];
++ struct fsg_lun *curlun = common->curlun;
++ int msf = common->cmnd[1] & 0x02;
++ int start_track = common->cmnd[6];
+ u8 *buf = (u8 *) bh->buf;
+
+- if ((fsg->common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
++ if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
+ start_track > 1) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+@@ -1258,10 +1283,10 @@ static int do_read_toc(struct fsg_dev *f
+ }
+
+
+-static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
+- int mscmnd = fsg->common->cmnd[0];
++ struct fsg_lun *curlun = common->curlun;
++ int mscmnd = common->cmnd[0];
+ u8 *buf = (u8 *) bh->buf;
+ u8 *buf0 = buf;
+ int pc, page_code;
+@@ -1269,12 +1294,12 @@ static int do_mode_sense(struct fsg_dev
+ int valid_page = 0;
+ int len, limit;
+
+- if ((fsg->common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */
++ if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+- pc = fsg->common->cmnd[2] >> 6;
+- page_code = fsg->common->cmnd[2] & 0x3f;
++ pc = common->cmnd[2] >> 6;
++ page_code = common->cmnd[2] & 0x3f;
+ if (pc == 3) {
+ curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
+ return -EINVAL;
+@@ -1339,32 +1364,32 @@ static int do_mode_sense(struct fsg_dev
+ }
+
+
+-static int do_start_stop(struct fsg_dev *fsg)
++static int do_start_stop(struct fsg_common *common)
+ {
+- if (!fsg->common->curlun) {
++ if (!common->curlun) {
+ return -EINVAL;
+- } else if (!fsg->common->curlun->removable) {
+- fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
++ } else if (!common->curlun->removable) {
++ common->curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+
+-static int do_prevent_allow(struct fsg_dev *fsg)
++static int do_prevent_allow(struct fsg_common *common)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ int prevent;
+
+- if (!fsg->common->curlun) {
++ if (!common->curlun) {
+ return -EINVAL;
+- } else if (!fsg->common->curlun->removable) {
+- fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
++ } else if (!common->curlun->removable) {
++ common->curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+
+- prevent = fsg->common->cmnd[4] & 0x01;
+- if ((fsg->common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */
++ prevent = common->cmnd[4] & 0x01;
++ if ((common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+@@ -1376,10 +1401,10 @@ static int do_prevent_allow(struct fsg_d
+ }
+
+
+-static int do_read_format_capacities(struct fsg_dev *fsg,
++static int do_read_format_capacities(struct fsg_common *common,
+ struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ u8 *buf = (u8 *) bh->buf;
+
+ buf[0] = buf[1] = buf[2] = 0;
+@@ -1394,12 +1419,13 @@ static int do_read_format_capacities(str
+ }
+
+
+-static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+
+ /* We don't support MODE SELECT */
+- curlun->sense_data = SS_INVALID_COMMAND;
++ if (curlun)
++ curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+
+@@ -1459,73 +1485,78 @@ static int pad_with_zeros(struct fsg_dev
+ int rc;
+
+ bh->state = BUF_STATE_EMPTY; /* For the first iteration */
+- fsg->usb_amount_left = nkeep + fsg->residue;
+- while (fsg->usb_amount_left > 0) {
++ fsg->common->usb_amount_left = nkeep + fsg->common->residue;
++ while (fsg->common->usb_amount_left > 0) {
+
+ /* Wait for the next buffer to be free */
+ while (bh->state != BUF_STATE_EMPTY) {
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(fsg->common);
+ if (rc)
+ return rc;
+ }
+
+- nsend = min(fsg->usb_amount_left, FSG_BUFLEN);
++ nsend = min(fsg->common->usb_amount_left, FSG_BUFLEN);
+ memset(bh->buf + nkeep, 0, nsend - nkeep);
+ bh->inreq->length = nsend;
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ bh = fsg->common->next_buffhd_to_fill = bh->next;
+- fsg->usb_amount_left -= nsend;
++ fsg->common->usb_amount_left -= nsend;
+ nkeep = 0;
+ }
+ return 0;
+ }
+
+-static int throw_away_data(struct fsg_dev *fsg)
++static int throw_away_data(struct fsg_common *common)
+ {
+ struct fsg_buffhd *bh;
+ u32 amount;
+ int rc;
+
+- for (bh = fsg->common->next_buffhd_to_drain;
+- bh->state != BUF_STATE_EMPTY || fsg->usb_amount_left > 0;
+- bh = fsg->common->next_buffhd_to_drain) {
++ for (bh = common->next_buffhd_to_drain;
++ bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0;
++ bh = common->next_buffhd_to_drain) {
+
+ /* Throw away the data in a filled buffer */
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+ bh->state = BUF_STATE_EMPTY;
+- fsg->common->next_buffhd_to_drain = bh->next;
++ common->next_buffhd_to_drain = bh->next;
+
+ /* A short packet or an error ends everything */
+ if (bh->outreq->actual != bh->outreq->length ||
+ bh->outreq->status != 0) {
+- raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ raise_exception(common,
++ FSG_STATE_ABORT_BULK_OUT);
+ return -EINTR;
+ }
+ continue;
+ }
+
+ /* Try to submit another request if we need one */
+- bh = fsg->common->next_buffhd_to_fill;
+- if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
+- amount = min(fsg->usb_amount_left, FSG_BUFLEN);
++ bh = common->next_buffhd_to_fill;
++ if (bh->state == BUF_STATE_EMPTY
++ && common->usb_amount_left > 0) {
++ amount = min(common->usb_amount_left, FSG_BUFLEN);
+
+ /* amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size */
+ bh->outreq->length = amount;
+ bh->bulk_out_intended_length = amount;
+ bh->outreq->short_not_ok = 1;
+- start_transfer(fsg, fsg->bulk_out, bh->outreq,
+- &bh->outreq_busy, &bh->state);
+- fsg->common->next_buffhd_to_fill = bh->next;
+- fsg->usb_amount_left -= amount;
++ START_TRANSFER_OR(common, bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state)
++ /* Don't know what to do if
++ * common->fsg is NULL */
++ return -EIO;
++ common->next_buffhd_to_fill = bh->next;
++ common->usb_amount_left -= amount;
+ continue;
+ }
+
+ /* Otherwise wait for something to happen */
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+@@ -1533,12 +1564,12 @@ static int throw_away_data(struct fsg_de
+ }
+
+
+-static int finish_reply(struct fsg_dev *fsg)
++static int finish_reply(struct fsg_common *common)
+ {
+- struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill;
++ struct fsg_buffhd *bh = common->next_buffhd_to_fill;
+ int rc = 0;
+
+- switch (fsg->data_dir) {
++ switch (common->data_dir) {
+ case DATA_DIR_NONE:
+ break; /* Nothing to send */
+
+@@ -1547,47 +1578,60 @@ static int finish_reply(struct fsg_dev *
+ * try to send or receive any data. So stall both bulk pipes
+ * if we can and wait for a reset. */
+ case DATA_DIR_UNKNOWN:
+- if (fsg->can_stall) {
+- fsg_set_halt(fsg, fsg->bulk_out);
+- rc = halt_bulk_in_endpoint(fsg);
++ if (!common->can_stall) {
++ /* Nothing */
++ } else if (fsg_is_set(common)) {
++ fsg_set_halt(common->fsg, common->fsg->bulk_out);
++ rc = halt_bulk_in_endpoint(common->fsg);
++ } else {
++ /* Don't know what to do if common->fsg is NULL */
++ rc = -EIO;
+ }
+ break;
+
+ /* All but the last buffer of data must have already been sent */
+ case DATA_DIR_TO_HOST:
+- if (fsg->data_size == 0) {
++ if (common->data_size == 0) {
+ /* Nothing to send */
+
+ /* If there's no residue, simply send the last buffer */
+- } else if (fsg->residue == 0) {
++ } else if (common->residue == 0) {
+ bh->inreq->zero = 0;
+- start_transfer(fsg, fsg->bulk_in, bh->inreq,
+- &bh->inreq_busy, &bh->state);
+- fsg->common->next_buffhd_to_fill = bh->next;
++ START_TRANSFER_OR(common, bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state)
++ return -EIO;
++ common->next_buffhd_to_fill = bh->next;
+
+ /* For Bulk-only, if we're allowed to stall then send the
+ * short packet and halt the bulk-in endpoint. If we can't
+ * stall, pad out the remaining data with 0's. */
+- } else if (fsg->can_stall) {
++ } else if (common->can_stall) {
+ bh->inreq->zero = 1;
+- start_transfer(fsg, fsg->bulk_in, bh->inreq,
+- &bh->inreq_busy, &bh->state);
+- fsg->common->next_buffhd_to_fill = bh->next;
+- rc = halt_bulk_in_endpoint(fsg);
++ START_TRANSFER_OR(common, bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state)
++ /* Don't know what to do if
++ * common->fsg is NULL */
++ rc = -EIO;
++ common->next_buffhd_to_fill = bh->next;
++ if (common->fsg)
++ rc = halt_bulk_in_endpoint(common->fsg);
++ } else if (fsg_is_set(common)) {
++ rc = pad_with_zeros(common->fsg);
+ } else {
+- rc = pad_with_zeros(fsg);
++ /* Don't know what to do if common->fsg is NULL */
++ rc = -EIO;
+ }
+ break;
+
+ /* We have processed all we want from the data the host has sent.
+ * There may still be outstanding bulk-out requests. */
+ case DATA_DIR_FROM_HOST:
+- if (fsg->residue == 0) {
++ if (common->residue == 0) {
+ /* Nothing to receive */
+
+ /* Did the host stop sending unexpectedly early? */
+- } else if (fsg->short_packet_received) {
+- raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ } else if (common->short_packet_received) {
++ raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+
+ /* We haven't processed all the incoming data. Even though
+@@ -1597,16 +1641,18 @@ static int finish_reply(struct fsg_dev *
+ * STALL. Not realizing the endpoint was halted, it wouldn't
+ * clear the halt -- leading to problems later on. */
+ #if 0
+- } else if (fsg->can_stall) {
+- fsg_set_halt(fsg, fsg->bulk_out);
+- raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ } else if (common->can_stall) {
++ if (fsg_is_set(common))
++ fsg_set_halt(common->fsg,
++ common->fsg->bulk_out);
++ raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+ #endif
+
+ /* We can't stall. Read in the excess data and throw it
+ * all away. */
+ } else {
+- rc = throw_away_data(fsg);
++ rc = throw_away_data(common);
+ }
+ break;
+ }
+@@ -1614,9 +1660,9 @@ static int finish_reply(struct fsg_dev *
+ }
+
+
+-static int send_status(struct fsg_dev *fsg)
++static int send_status(struct fsg_common *common)
+ {
+- struct fsg_lun *curlun = fsg->common->curlun;
++ struct fsg_lun *curlun = common->curlun;
+ struct fsg_buffhd *bh;
+ struct bulk_cs_wrap *csw;
+ int rc;
+@@ -1624,9 +1670,9 @@ static int send_status(struct fsg_dev *f
+ u32 sd, sdinfo = 0;
+
+ /* Wait for the next buffer to become available */
+- bh = fsg->common->next_buffhd_to_fill;
++ bh = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+@@ -1634,19 +1680,19 @@ static int send_status(struct fsg_dev *f
+ if (curlun) {
+ sd = curlun->sense_data;
+ sdinfo = curlun->sense_data_info;
+- } else if (fsg->bad_lun_okay)
++ } else if (common->bad_lun_okay)
+ sd = SS_NO_SENSE;
+ else
+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+- if (fsg->phase_error) {
+- DBG(fsg, "sending phase-error status\n");
++ if (common->phase_error) {
++ DBG(common, "sending phase-error status\n");
+ status = USB_STATUS_PHASE_ERROR;
+ sd = SS_INVALID_COMMAND;
+ } else if (sd != SS_NO_SENSE) {
+- DBG(fsg, "sending command-failure status\n");
++ DBG(common, "sending command-failure status\n");
+ status = USB_STATUS_FAIL;
+- VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
++ VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+ " info x%x\n",
+ SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+ }
+@@ -1655,16 +1701,18 @@ static int send_status(struct fsg_dev *f
+ csw = (void *)bh->buf;
+
+ csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+- csw->Tag = fsg->tag;
+- csw->Residue = cpu_to_le32(fsg->residue);
++ csw->Tag = common->tag;
++ csw->Residue = cpu_to_le32(common->residue);
+ csw->Status = status;
+
+ bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+ bh->inreq->zero = 0;
+- start_transfer(fsg, fsg->bulk_in, bh->inreq,
+- &bh->inreq_busy, &bh->state);
++ START_TRANSFER_OR(common, bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state)
++ /* Don't know what to do if common->fsg is NULL */
++ return -EIO;
+
+- fsg->common->next_buffhd_to_fill = bh->next;
++ common->next_buffhd_to_fill = bh->next;
+ return 0;
+ }
+
+@@ -1673,52 +1721,47 @@ static int send_status(struct fsg_dev *f
+
+ /* Check whether the command is properly formed and whether its data size
+ * and direction agree with the values we already have. */
+-static int check_command(struct fsg_dev *fsg, int cmnd_size,
++static int check_command(struct fsg_common *common, int cmnd_size,
+ enum data_direction data_dir, unsigned int mask,
+ int needs_medium, const char *name)
+ {
+ int i;
+- int lun = fsg->common->cmnd[1] >> 5;
++ int lun = common->cmnd[1] >> 5;
+ static const char dirletter[4] = {'u', 'o', 'i', 'n'};
+ char hdlen[20];
+ struct fsg_lun *curlun;
+
+ hdlen[0] = 0;
+- if (fsg->data_dir != DATA_DIR_UNKNOWN)
+- sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
+- fsg->data_size);
+- VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
++ if (common->data_dir != DATA_DIR_UNKNOWN)
++ sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
++ common->data_size);
++ VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
+ name, cmnd_size, dirletter[(int) data_dir],
+- fsg->data_size_from_cmnd, fsg->common->cmnd_size, hdlen);
++ common->data_size_from_cmnd, common->cmnd_size, hdlen);
+
+ /* We can't reply at all until we know the correct data direction
+ * and size. */
+- if (fsg->data_size_from_cmnd == 0)
++ if (common->data_size_from_cmnd == 0)
+ data_dir = DATA_DIR_NONE;
+- if (fsg->data_dir == DATA_DIR_UNKNOWN) { /* CB or CBI */
+- fsg->data_dir = data_dir;
+- fsg->data_size = fsg->data_size_from_cmnd;
+-
+- } else { /* Bulk-only */
+- if (fsg->data_size < fsg->data_size_from_cmnd) {
+-
+- /* Host data size < Device data size is a phase error.
+- * Carry out the command, but only transfer as much
+- * as we are allowed. */
+- fsg->data_size_from_cmnd = fsg->data_size;
+- fsg->phase_error = 1;
+- }
++ if (common->data_size < common->data_size_from_cmnd) {
++ /* Host data size < Device data size is a phase error.
++ * Carry out the command, but only transfer as much as
++ * we are allowed. */
++ common->data_size_from_cmnd = common->data_size;
++ common->phase_error = 1;
+ }
+- fsg->residue = fsg->usb_amount_left = fsg->data_size;
++ common->residue = common->data_size;
++ common->usb_amount_left = common->data_size;
+
+ /* Conflicting data directions is a phase error */
+- if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
+- fsg->phase_error = 1;
++ if (common->data_dir != data_dir
++ && common->data_size_from_cmnd > 0) {
++ common->phase_error = 1;
+ return -EINVAL;
+ }
+
+ /* Verify the length of the command itself */
+- if (cmnd_size != fsg->common->cmnd_size) {
++ if (cmnd_size != common->cmnd_size) {
+
+ /* Special case workaround: There are plenty of buggy SCSI
+ * implementations. Many have issues with cbw->Length
+@@ -1732,40 +1775,41 @@ static int check_command(struct fsg_dev
+ * REQUEST SENSE with cbw->Length == 10 where it should
+ * be 6 as well.
+ */
+- if (cmnd_size <= fsg->common->cmnd_size) {
+- DBG(fsg, "%s is buggy! Expected length %d "
++ if (cmnd_size <= common->cmnd_size) {
++ DBG(common, "%s is buggy! Expected length %d "
+ "but we got %d\n", name,
+- cmnd_size, fsg->common->cmnd_size);
+- cmnd_size = fsg->common->cmnd_size;
++ cmnd_size, common->cmnd_size);
++ cmnd_size = common->cmnd_size;
+ } else {
+- fsg->phase_error = 1;
++ common->phase_error = 1;
+ return -EINVAL;
+ }
+ }
+
+ /* Check that the LUN values are consistent */
+- if (fsg->common->lun != lun)
+- DBG(fsg, "using LUN %d from CBW, not LUN %d from CDB\n",
+- fsg->common->lun, lun);
++ if (common->lun != lun)
++ DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
++ common->lun, lun);
+
+ /* Check the LUN */
+- if (fsg->common->lun >= 0 && fsg->common->lun < fsg->common->nluns) {
+- curlun = &fsg->common->luns[fsg->common->lun];
+- fsg->common->curlun = curlun;
+- if (fsg->common->cmnd[0] != SC_REQUEST_SENSE) {
++ if (common->lun >= 0 && common->lun < common->nluns) {
++ curlun = &common->luns[common->lun];
++ common->curlun = curlun;
++ if (common->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+ } else {
+- fsg->common->curlun = curlun = NULL;
+- fsg->bad_lun_okay = 0;
++ common->curlun = NULL;
++ curlun = NULL;
++ common->bad_lun_okay = 0;
+
+ /* INQUIRY and REQUEST SENSE commands are explicitly allowed
+ * to use unsupported LUNs; all others may not. */
+- if (fsg->common->cmnd[0] != SC_INQUIRY &&
+- fsg->common->cmnd[0] != SC_REQUEST_SENSE) {
+- DBG(fsg, "unsupported LUN %d\n", fsg->common->lun);
++ if (common->cmnd[0] != SC_INQUIRY &&
++ common->cmnd[0] != SC_REQUEST_SENSE) {
++ DBG(common, "unsupported LUN %d\n", common->lun);
+ return -EINVAL;
+ }
+ }
+@@ -1773,17 +1817,17 @@ static int check_command(struct fsg_dev
+ /* If a unit attention condition exists, only INQUIRY and
+ * REQUEST SENSE commands are allowed; anything else must fail. */
+ if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
+- fsg->common->cmnd[0] != SC_INQUIRY &&
+- fsg->common->cmnd[0] != SC_REQUEST_SENSE) {
++ common->cmnd[0] != SC_INQUIRY &&
++ common->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = curlun->unit_attention_data;
+ curlun->unit_attention_data = SS_NO_SENSE;
+ return -EINVAL;
+ }
+
+ /* Check that only command bytes listed in the mask are non-zero */
+- fsg->common->cmnd[1] &= 0x1f; /* Mask away the LUN */
++ common->cmnd[1] &= 0x1f; /* Mask away the LUN */
+ for (i = 1; i < cmnd_size; ++i) {
+- if (fsg->common->cmnd[i] && !(mask & (1 << i))) {
++ if (common->cmnd[i] && !(mask & (1 << i))) {
+ if (curlun)
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+@@ -1801,7 +1845,7 @@ static int check_command(struct fsg_dev
+ }
+
+
+-static int do_scsi_command(struct fsg_dev *fsg)
++static int do_scsi_command(struct fsg_common *common)
+ {
+ struct fsg_buffhd *bh;
+ int rc;
+@@ -1809,182 +1853,181 @@ static int do_scsi_command(struct fsg_de
+ int i;
+ static char unknown[16];
+
+- dump_cdb(fsg->common);
++ dump_cdb(common);
+
+ /* Wait for the next buffer to become available for data or status */
+- bh = fsg->common->next_buffhd_to_fill;
+- fsg->common->next_buffhd_to_drain = bh;
++ bh = common->next_buffhd_to_fill;
++ common->next_buffhd_to_drain = bh;
+ while (bh->state != BUF_STATE_EMPTY) {
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+- fsg->phase_error = 0;
+- fsg->short_packet_received = 0;
++ common->phase_error = 0;
++ common->short_packet_received = 0;
+
+- /* We're using the backing file */
+- down_read(&fsg->common->filesem);
+- switch (fsg->common->cmnd[0]) {
++ down_read(&common->filesem); /* We're using the backing file */
++ switch (common->cmnd[0]) {
+
+ case SC_INQUIRY:
+- fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd = common->cmnd[4];
++ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (1<<4), 0,
+ "INQUIRY");
+ if (reply == 0)
+- reply = do_inquiry(fsg, bh);
++ reply = do_inquiry(common, bh);
+ break;
+
+ case SC_MODE_SELECT_6:
+- fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
++ common->data_size_from_cmnd = common->cmnd[4];
++ reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+ (1<<1) | (1<<4), 0,
+ "MODE SELECT(6)");
+ if (reply == 0)
+- reply = do_mode_select(fsg, bh);
++ reply = do_mode_select(common, bh);
+ break;
+
+ case SC_MODE_SELECT_10:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]);
+- reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]);
++ reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+ (1<<1) | (3<<7), 0,
+ "MODE SELECT(10)");
+ if (reply == 0)
+- reply = do_mode_select(fsg, bh);
++ reply = do_mode_select(common, bh);
+ break;
+
+ case SC_MODE_SENSE_6:
+- fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd = common->cmnd[4];
++ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (1<<1) | (1<<2) | (1<<4), 0,
+ "MODE SENSE(6)");
+ if (reply == 0)
+- reply = do_mode_sense(fsg, bh);
++ reply = do_mode_sense(common, bh);
+ break;
+
+ case SC_MODE_SENSE_10:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]);
+- reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]);
++ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (1<<1) | (1<<2) | (3<<7), 0,
+ "MODE SENSE(10)");
+ if (reply == 0)
+- reply = do_mode_sense(fsg, bh);
++ reply = do_mode_sense(common, bh);
+ break;
+
+ case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
+- fsg->data_size_from_cmnd = 0;
+- reply = check_command(fsg, 6, DATA_DIR_NONE,
++ common->data_size_from_cmnd = 0;
++ reply = check_command(common, 6, DATA_DIR_NONE,
+ (1<<4), 0,
+ "PREVENT-ALLOW MEDIUM REMOVAL");
+ if (reply == 0)
+- reply = do_prevent_allow(fsg);
++ reply = do_prevent_allow(common);
+ break;
+
+ case SC_READ_6:
+- i = fsg->common->cmnd[4];
+- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+- reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ i = common->cmnd[4];
++ common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
++ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (7<<1) | (1<<4), 1,
+ "READ(6)");
+ if (reply == 0)
+- reply = do_read(fsg);
++ reply = do_read(common);
+ break;
+
+ case SC_READ_10:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]) << 9;
+- reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]) << 9;
++ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "READ(10)");
+ if (reply == 0)
+- reply = do_read(fsg);
++ reply = do_read(common);
+ break;
+
+ case SC_READ_12:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be32(&fsg->common->cmnd[6]) << 9;
+- reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be32(&common->cmnd[6]) << 9;
++ reply = check_command(common, 12, DATA_DIR_TO_HOST,
+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
+ "READ(12)");
+ if (reply == 0)
+- reply = do_read(fsg);
++ reply = do_read(common);
+ break;
+
+ case SC_READ_CAPACITY:
+- fsg->data_size_from_cmnd = 8;
+- reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd = 8;
++ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (0xf<<2) | (1<<8), 1,
+ "READ CAPACITY");
+ if (reply == 0)
+- reply = do_read_capacity(fsg, bh);
++ reply = do_read_capacity(common, bh);
+ break;
+
+ case SC_READ_HEADER:
+- if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
++ if (!common->curlun || !common->curlun->cdrom)
+ goto unknown_cmnd;
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]);
+- reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]);
++ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (3<<7) | (0x1f<<1), 1,
+ "READ HEADER");
+ if (reply == 0)
+- reply = do_read_header(fsg, bh);
++ reply = do_read_header(common, bh);
+ break;
+
+ case SC_READ_TOC:
+- if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
++ if (!common->curlun || !common->curlun->cdrom)
+ goto unknown_cmnd;
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]);
+- reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]);
++ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (7<<6) | (1<<1), 1,
+ "READ TOC");
+ if (reply == 0)
+- reply = do_read_toc(fsg, bh);
++ reply = do_read_toc(common, bh);
+ break;
+
+ case SC_READ_FORMAT_CAPACITIES:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]);
+- reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]);
++ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (3<<7), 1,
+ "READ FORMAT CAPACITIES");
+ if (reply == 0)
+- reply = do_read_format_capacities(fsg, bh);
++ reply = do_read_format_capacities(common, bh);
+ break;
+
+ case SC_REQUEST_SENSE:
+- fsg->data_size_from_cmnd = fsg->common->cmnd[4];
+- reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ common->data_size_from_cmnd = common->cmnd[4];
++ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (1<<4), 0,
+ "REQUEST SENSE");
+ if (reply == 0)
+- reply = do_request_sense(fsg, bh);
++ reply = do_request_sense(common, bh);
+ break;
+
+ case SC_START_STOP_UNIT:
+- fsg->data_size_from_cmnd = 0;
+- reply = check_command(fsg, 6, DATA_DIR_NONE,
++ common->data_size_from_cmnd = 0;
++ reply = check_command(common, 6, DATA_DIR_NONE,
+ (1<<1) | (1<<4), 0,
+ "START-STOP UNIT");
+ if (reply == 0)
+- reply = do_start_stop(fsg);
++ reply = do_start_stop(common);
+ break;
+
+ case SC_SYNCHRONIZE_CACHE:
+- fsg->data_size_from_cmnd = 0;
+- reply = check_command(fsg, 10, DATA_DIR_NONE,
++ common->data_size_from_cmnd = 0;
++ reply = check_command(common, 10, DATA_DIR_NONE,
+ (0xf<<2) | (3<<7), 1,
+ "SYNCHRONIZE CACHE");
+ if (reply == 0)
+- reply = do_synchronize_cache(fsg);
++ reply = do_synchronize_cache(common);
+ break;
+
+ case SC_TEST_UNIT_READY:
+- fsg->data_size_from_cmnd = 0;
+- reply = check_command(fsg, 6, DATA_DIR_NONE,
++ common->data_size_from_cmnd = 0;
++ reply = check_command(common, 6, DATA_DIR_NONE,
+ 0, 1,
+ "TEST UNIT READY");
+ break;
+@@ -1992,42 +2035,42 @@ static int do_scsi_command(struct fsg_de
+ /* Although optional, this command is used by MS-Windows. We
+ * support a minimal version: BytChk must be 0. */
+ case SC_VERIFY:
+- fsg->data_size_from_cmnd = 0;
+- reply = check_command(fsg, 10, DATA_DIR_NONE,
++ common->data_size_from_cmnd = 0;
++ reply = check_command(common, 10, DATA_DIR_NONE,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "VERIFY");
+ if (reply == 0)
+- reply = do_verify(fsg);
++ reply = do_verify(common);
+ break;
+
+ case SC_WRITE_6:
+- i = fsg->common->cmnd[4];
+- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+- reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
++ i = common->cmnd[4];
++ common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
++ reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+ (7<<1) | (1<<4), 1,
+ "WRITE(6)");
+ if (reply == 0)
+- reply = do_write(fsg);
++ reply = do_write(common);
+ break;
+
+ case SC_WRITE_10:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be16(&fsg->common->cmnd[7]) << 9;
+- reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be16(&common->cmnd[7]) << 9;
++ reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "WRITE(10)");
+ if (reply == 0)
+- reply = do_write(fsg);
++ reply = do_write(common);
+ break;
+
+ case SC_WRITE_12:
+- fsg->data_size_from_cmnd =
+- get_unaligned_be32(&fsg->common->cmnd[6]) << 9;
+- reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
++ common->data_size_from_cmnd =
++ get_unaligned_be32(&common->cmnd[6]) << 9;
++ reply = check_command(common, 12, DATA_DIR_FROM_HOST,
+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
+ "WRITE(12)");
+ if (reply == 0)
+- reply = do_write(fsg);
++ reply = do_write(common);
+ break;
+
+ /* Some mandatory commands that we recognize but don't implement.
+@@ -2042,17 +2085,17 @@ static int do_scsi_command(struct fsg_de
+
+ default:
+ unknown_cmnd:
+- fsg->data_size_from_cmnd = 0;
+- sprintf(unknown, "Unknown x%02x", fsg->common->cmnd[0]);
+- reply = check_command(fsg, fsg->common->cmnd_size,
++ common->data_size_from_cmnd = 0;
++ sprintf(unknown, "Unknown x%02x", common->cmnd[0]);
++ reply = check_command(common, common->cmnd_size,
+ DATA_DIR_UNKNOWN, 0xff, 0, unknown);
+ if (reply == 0) {
+- fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
++ common->curlun->sense_data = SS_INVALID_COMMAND;
+ reply = -EINVAL;
+ }
+ break;
+ }
+- up_read(&fsg->common->filesem);
++ up_read(&common->filesem);
+
+ if (reply == -EINTR || signal_pending(current))
+ return -EINTR;
+@@ -2060,11 +2103,11 @@ unknown_cmnd:
+ /* Set up the single reply buffer for finish_reply() */
+ if (reply == -EINVAL)
+ reply = 0; /* Error reply length */
+- if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
+- reply = min((u32) reply, fsg->data_size_from_cmnd);
++ if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
++ reply = min((u32) reply, common->data_size_from_cmnd);
+ bh->inreq->length = reply;
+ bh->state = BUF_STATE_FULL;
+- fsg->residue -= reply;
++ common->residue -= reply;
+ } /* Otherwise it's already set */
+
+ return 0;
+@@ -2075,8 +2118,9 @@ unknown_cmnd:
+
+ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+ {
+- struct usb_request *req = bh->outreq;
++ struct usb_request *req = bh->outreq;
+ struct fsg_bulk_cb_wrap *cbw = req->buf;
++ struct fsg_common *common = fsg->common;
+
+ /* Was this a real packet? Should it be ignored? */
+ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
+@@ -2113,7 +2157,7 @@ static int received_cbw(struct fsg_dev *
+
+ /* We can do anything we want here, so let's stall the
+ * bulk pipes if we are allowed to. */
+- if (fsg->can_stall) {
++ if (common->can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ halt_bulk_in_endpoint(fsg);
+ }
+@@ -2121,39 +2165,41 @@ static int received_cbw(struct fsg_dev *
+ }
+
+ /* Save the command for later */
+- fsg->common->cmnd_size = cbw->Length;
+- memcpy(fsg->common->cmnd, cbw->CDB, fsg->common->cmnd_size);
++ common->cmnd_size = cbw->Length;
++ memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
+ if (cbw->Flags & USB_BULK_IN_FLAG)
+- fsg->data_dir = DATA_DIR_TO_HOST;
++ common->data_dir = DATA_DIR_TO_HOST;
+ else
+- fsg->data_dir = DATA_DIR_FROM_HOST;
+- fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
+- if (fsg->data_size == 0)
+- fsg->data_dir = DATA_DIR_NONE;
+- fsg->common->lun = cbw->Lun;
+- fsg->tag = cbw->Tag;
++ common->data_dir = DATA_DIR_FROM_HOST;
++ common->data_size = le32_to_cpu(cbw->DataTransferLength);
++ if (common->data_size == 0)
++ common->data_dir = DATA_DIR_NONE;
++ common->lun = cbw->Lun;
++ common->tag = cbw->Tag;
+ return 0;
+ }
+
+
+-static int get_next_command(struct fsg_dev *fsg)
++static int get_next_command(struct fsg_common *common)
+ {
+ struct fsg_buffhd *bh;
+ int rc = 0;
+
+ /* Wait for the next buffer to become available */
+- bh = fsg->common->next_buffhd_to_fill;
++ bh = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+
+ /* Queue a request to read a Bulk-only CBW */
+- set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
++ set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
+ bh->outreq->short_not_ok = 1;
+- start_transfer(fsg, fsg->bulk_out, bh->outreq,
+- &bh->outreq_busy, &bh->state);
++ START_TRANSFER_OR(common, bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state)
++ /* Don't know what to do if common->fsg is NULL */
++ return -EIO;
+
+ /* We will drain the buffer in software, which means we
+ * can reuse it for the next filling. No need to advance
+@@ -2161,12 +2207,12 @@ static int get_next_command(struct fsg_d
+
+ /* Wait for the CBW to arrive */
+ while (bh->state != BUF_STATE_FULL) {
+- rc = sleep_thread(fsg);
++ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+ smp_rmb();
+- rc = received_cbw(fsg, bh);
++ rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+ bh->state = BUF_STATE_EMPTY;
+
+ return rc;
+@@ -2175,25 +2221,25 @@ static int get_next_command(struct fsg_d
+
+ /*-------------------------------------------------------------------------*/
+
+-static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
++static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *d)
+ {
+ int rc;
+
+- ep->driver_data = fsg;
++ ep->driver_data = common;
+ rc = usb_ep_enable(ep, d);
+ if (rc)
+- ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
++ ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
+ return rc;
+ }
+
+-static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
++static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
+ struct usb_request **preq)
+ {
+ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (*preq)
+ return 0;
+- ERROR(fsg, "can't allocate request for %s\n", ep->name);
++ ERROR(common, "can't allocate request for %s\n", ep->name);
+ return -ENOMEM;
+ }
+
+@@ -2202,83 +2248,96 @@ static int alloc_request(struct fsg_dev
+ * Call with altsetting < 0 to disable the interface. The only other
+ * available altsetting is 0, which enables the interface.
+ */
+-static int do_set_interface(struct fsg_dev *fsg, int altsetting)
++static int do_set_interface(struct fsg_common *common, int altsetting)
+ {
+ int rc = 0;
+ int i;
+ const struct usb_endpoint_descriptor *d;
+
+- if (fsg->running)
+- DBG(fsg, "reset interface\n");
++ if (common->running)
++ DBG(common, "reset interface\n");
+
+ reset:
+ /* Deallocate the requests */
+- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+- struct fsg_buffhd *bh = &fsg->common->buffhds[i];
++ if (common->prev_fsg) {
++ struct fsg_dev *fsg = common->prev_fsg;
++
++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
++ struct fsg_buffhd *bh = &common->buffhds[i];
+
+- if (bh->inreq) {
+- usb_ep_free_request(fsg->bulk_in, bh->inreq);
+- bh->inreq = NULL;
++ if (bh->inreq) {
++ usb_ep_free_request(fsg->bulk_in, bh->inreq);
++ bh->inreq = NULL;
++ }
++ if (bh->outreq) {
++ usb_ep_free_request(fsg->bulk_out, bh->outreq);
++ bh->outreq = NULL;
++ }
+ }
+- if (bh->outreq) {
+- usb_ep_free_request(fsg->bulk_out, bh->outreq);
+- bh->outreq = NULL;
++
++ /* Disable the endpoints */
++ if (fsg->bulk_in_enabled) {
++ usb_ep_disable(fsg->bulk_in);
++ fsg->bulk_in_enabled = 0;
++ }
++ if (fsg->bulk_out_enabled) {
++ usb_ep_disable(fsg->bulk_out);
++ fsg->bulk_out_enabled = 0;
+ }
+- }
+
+- /* Disable the endpoints */
+- if (fsg->bulk_in_enabled) {
+- usb_ep_disable(fsg->bulk_in);
+- fsg->bulk_in_enabled = 0;
+- }
+- if (fsg->bulk_out_enabled) {
+- usb_ep_disable(fsg->bulk_out);
+- fsg->bulk_out_enabled = 0;
++ common->prev_fsg = 0;
+ }
+
+- fsg->running = 0;
++ common->running = 0;
+ if (altsetting < 0 || rc != 0)
+ return rc;
+
+- DBG(fsg, "set interface %d\n", altsetting);
+-
+- /* Enable the endpoints */
+- d = fsg_ep_desc(fsg->gadget,
+- &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+- rc = enable_endpoint(fsg, fsg->bulk_in, d);
+- if (rc != 0)
+- goto reset;
+- fsg->bulk_in_enabled = 1;
+-
+- d = fsg_ep_desc(fsg->gadget,
+- &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+- rc = enable_endpoint(fsg, fsg->bulk_out, d);
+- if (rc != 0)
+- goto reset;
+- fsg->bulk_out_enabled = 1;
+- fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+- clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
++ DBG(common, "set interface %d\n", altsetting);
+
+- /* Allocate the requests */
+- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+- struct fsg_buffhd *bh = &fsg->common->buffhds[i];
+-
+- rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq);
+- if (rc != 0)
++ if (fsg_is_set(common)) {
++ struct fsg_dev *fsg = common->fsg;
++ common->prev_fsg = common->fsg;
++
++ /* Enable the endpoints */
++ d = fsg_ep_desc(common->gadget,
++ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
++ rc = enable_endpoint(common, fsg->bulk_in, d);
++ if (rc)
+ goto reset;
+- rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq);
+- if (rc != 0)
++ fsg->bulk_in_enabled = 1;
++
++ d = fsg_ep_desc(common->gadget,
++ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
++ rc = enable_endpoint(common, fsg->bulk_out, d);
++ if (rc)
+ goto reset;
+- bh->inreq->buf = bh->outreq->buf = bh->buf;
+- bh->inreq->context = bh->outreq->context = bh;
+- bh->inreq->complete = bulk_in_complete;
+- bh->outreq->complete = bulk_out_complete;
+- }
++ fsg->bulk_out_enabled = 1;
++ common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
++ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+
+- fsg->running = 1;
+- for (i = 0; i < fsg->common->nluns; ++i)
+- fsg->common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+- return rc;
++ /* Allocate the requests */
++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
++ struct fsg_buffhd *bh = &common->buffhds[i];
++
++ rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
++ if (rc)
++ goto reset;
++ rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
++ if (rc)
++ goto reset;
++ bh->inreq->buf = bh->outreq->buf = bh->buf;
++ bh->inreq->context = bh->outreq->context = bh;
++ bh->inreq->complete = bulk_in_complete;
++ bh->outreq->complete = bulk_out_complete;
++ }
++
++ common->running = 1;
++ for (i = 0; i < common->nluns; ++i)
++ common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
++ return rc;
++ } else {
++ return -EIO;
++ }
+ }
+
+
+@@ -2290,23 +2349,23 @@ reset:
+ * configurations might not work with our current power sources.
+ * For now we just assume the gadget is always self-powered.
+ */
+-static int do_set_config(struct fsg_dev *fsg, u8 new_config)
++static int do_set_config(struct fsg_common *common, u8 new_config)
+ {
+ int rc = 0;
+
+ /* Disable the single interface */
+- if (fsg->config != 0) {
+- DBG(fsg, "reset config\n");
+- fsg->config = 0;
+- rc = do_set_interface(fsg, -1);
++ if (common->config != 0) {
++ DBG(common, "reset config\n");
++ common->config = 0;
++ rc = do_set_interface(common, -1);
+ }
+
+ /* Enable the interface */
+ if (new_config != 0) {
+- fsg->config = new_config;
+- rc = do_set_interface(fsg, 0);
++ common->config = new_config;
++ rc = do_set_interface(common, 0);
+ if (rc != 0)
+- fsg->config = 0; /* Reset on errors */
++ common->config = 0; /* Reset on errors */
+ }
+ return rc;
+ }
+@@ -2318,22 +2377,26 @@ static int do_set_config(struct fsg_dev
+ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
+- fsg->new_config = 1;
+- raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++ fsg->common->prev_fsg = fsg->common->fsg;
++ fsg->common->fsg = fsg;
++ fsg->common->new_config = 1;
++ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+ return 0;
+ }
+
+ static void fsg_disable(struct usb_function *f)
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
+- fsg->new_config = 0;
+- raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++ fsg->common->prev_fsg = fsg->common->fsg;
++ fsg->common->fsg = fsg;
++ fsg->common->new_config = 0;
++ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+ }
+
+
+ /*-------------------------------------------------------------------------*/
+
+-static void handle_exception(struct fsg_dev *fsg)
++static void handle_exception(struct fsg_common *common)
+ {
+ siginfo_t info;
+ int sig;
+@@ -2352,113 +2415,121 @@ static void handle_exception(struct fsg_
+ if (!sig)
+ break;
+ if (sig != SIGUSR1) {
+- if (fsg->state < FSG_STATE_EXIT)
+- DBG(fsg, "Main thread exiting on signal\n");
+- raise_exception(fsg, FSG_STATE_EXIT);
++ if (common->state < FSG_STATE_EXIT)
++ DBG(common, "Main thread exiting on signal\n");
++ raise_exception(common, FSG_STATE_EXIT);
+ }
+ }
+
+ /* Cancel all the pending transfers */
+- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+- bh = &fsg->common->buffhds[i];
+- if (bh->inreq_busy)
+- usb_ep_dequeue(fsg->bulk_in, bh->inreq);
+- if (bh->outreq_busy)
+- usb_ep_dequeue(fsg->bulk_out, bh->outreq);
+- }
+-
+- /* Wait until everything is idle */
+- for (;;) {
+- int num_active = 0;
++ if (fsg_is_set(common)) {
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+- bh = &fsg->common->buffhds[i];
+- num_active += bh->inreq_busy + bh->outreq_busy;
++ bh = &common->buffhds[i];
++ if (bh->inreq_busy)
++ usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
++ if (bh->outreq_busy)
++ usb_ep_dequeue(common->fsg->bulk_out,
++ bh->outreq);
+ }
+- if (num_active == 0)
+- break;
+- if (sleep_thread(fsg))
+- return;
+- }
+
+- /* Clear out the controller's fifos */
+- if (fsg->bulk_in_enabled)
+- usb_ep_fifo_flush(fsg->bulk_in);
+- if (fsg->bulk_out_enabled)
+- usb_ep_fifo_flush(fsg->bulk_out);
++ /* Wait until everything is idle */
++ for (;;) {
++ int num_active = 0;
++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
++ bh = &common->buffhds[i];
++ num_active += bh->inreq_busy + bh->outreq_busy;
++ }
++ if (num_active == 0)
++ break;
++ if (sleep_thread(common))
++ return;
++ }
++
++ /* Clear out the controller's fifos */
++ if (common->fsg->bulk_in_enabled)
++ usb_ep_fifo_flush(common->fsg->bulk_in);
++ if (common->fsg->bulk_out_enabled)
++ usb_ep_fifo_flush(common->fsg->bulk_out);
++ }
+
+ /* Reset the I/O buffer states and pointers, the SCSI
+ * state, and the exception. Then invoke the handler. */
+- spin_lock_irq(&fsg->lock);
++ spin_lock_irq(&common->lock);
+
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+- bh = &fsg->common->buffhds[i];
++ bh = &common->buffhds[i];
+ bh->state = BUF_STATE_EMPTY;
+ }
+- fsg->common->next_buffhd_to_fill = &fsg->common->buffhds[0];
+- fsg->common->next_buffhd_to_drain = &fsg->common->buffhds[0];
+- exception_req_tag = fsg->exception_req_tag;
+- new_config = fsg->new_config;
+- old_state = fsg->state;
++ common->next_buffhd_to_fill = &common->buffhds[0];
++ common->next_buffhd_to_drain = &common->buffhds[0];
++ exception_req_tag = common->exception_req_tag;
++ new_config = common->new_config;
++ old_state = common->state;
+
+ if (old_state == FSG_STATE_ABORT_BULK_OUT)
+- fsg->state = FSG_STATE_STATUS_PHASE;
++ common->state = FSG_STATE_STATUS_PHASE;
+ else {
+- for (i = 0; i < fsg->common->nluns; ++i) {
+- curlun = &fsg->common->luns[i];
++ for (i = 0; i < common->nluns; ++i) {
++ curlun = &common->luns[i];
+ curlun->prevent_medium_removal = 0;
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->unit_attention_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+- fsg->state = FSG_STATE_IDLE;
++ common->state = FSG_STATE_IDLE;
+ }
+- spin_unlock_irq(&fsg->lock);
++ spin_unlock_irq(&common->lock);
+
+ /* Carry out any extra actions required for the exception */
+ switch (old_state) {
+ case FSG_STATE_ABORT_BULK_OUT:
+- send_status(fsg);
+- spin_lock_irq(&fsg->lock);
+- if (fsg->state == FSG_STATE_STATUS_PHASE)
+- fsg->state = FSG_STATE_IDLE;
+- spin_unlock_irq(&fsg->lock);
++ send_status(common);
++ spin_lock_irq(&common->lock);
++ if (common->state == FSG_STATE_STATUS_PHASE)
++ common->state = FSG_STATE_IDLE;
++ spin_unlock_irq(&common->lock);
+ break;
+
+ case FSG_STATE_RESET:
+ /* In case we were forced against our will to halt a
+ * bulk endpoint, clear the halt now. (The SuperH UDC
+ * requires this.) */
+- if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
+- usb_ep_clear_halt(fsg->bulk_in);
++ if (!fsg_is_set(common))
++ break;
++ if (test_and_clear_bit(IGNORE_BULK_OUT,
++ &common->fsg->atomic_bitflags))
++ usb_ep_clear_halt(common->fsg->bulk_in);
+
+- if (fsg->ep0_req_tag == exception_req_tag)
+- ep0_queue(fsg); /* Complete the status stage */
++ if (common->ep0_req_tag == exception_req_tag)
++ ep0_queue(common); /* Complete the status stage */
+
+ /* Technically this should go here, but it would only be
+ * a waste of time. Ditto for the INTERFACE_CHANGE and
+ * CONFIG_CHANGE cases. */
+- /* for (i = 0; i < fsg->common->nluns; ++i) */
+- /* fsg->common->luns[i].unit_attention_data = */
++ /* for (i = 0; i < common->nluns; ++i) */
++ /* common->luns[i].unit_attention_data = */
+ /* SS_RESET_OCCURRED; */
+ break;
+
+ case FSG_STATE_CONFIG_CHANGE:
+- rc = do_set_config(fsg, new_config);
+- if (fsg->ep0_req_tag != exception_req_tag)
++ rc = do_set_config(common, new_config);
++ if (common->ep0_req_tag != exception_req_tag)
+ break;
+- if (rc != 0) /* STALL on errors */
+- fsg_set_halt(fsg, fsg->ep0);
+- else /* Complete the status stage */
+- ep0_queue(fsg);
++ if (rc != 0) { /* STALL on errors */
++ DBG(common, "ep0 set halt\n");
++ usb_ep_set_halt(common->ep0);
++ } else { /* Complete the status stage */
++ ep0_queue(common);
++ }
+ break;
+
+ case FSG_STATE_EXIT:
+ case FSG_STATE_TERMINATED:
+- do_set_config(fsg, 0); /* Free resources */
+- spin_lock_irq(&fsg->lock);
+- fsg->state = FSG_STATE_TERMINATED; /* Stop the thread */
+- spin_unlock_irq(&fsg->lock);
++ do_set_config(common, 0); /* Free resources */
++ spin_lock_irq(&common->lock);
++ common->state = FSG_STATE_TERMINATED; /* Stop the thread */
++ spin_unlock_irq(&common->lock);
+ break;
+
+ case FSG_STATE_INTERFACE_CHANGE:
+@@ -2474,9 +2545,9 @@ static void handle_exception(struct fsg_
+
+ /*-------------------------------------------------------------------------*/
+
+-static int fsg_main_thread(void *fsg_)
++static int fsg_main_thread(void *common_)
+ {
+- struct fsg_dev *fsg = fsg_;
++ struct fsg_common *common = common_;
+
+ /* Allow the thread to be killed by a signal, but set the signal mask
+ * to block everything but INT, TERM, KILL, and USR1. */
+@@ -2494,45 +2565,45 @@ static int fsg_main_thread(void *fsg_)
+ set_fs(get_ds());
+
+ /* The main loop */
+- while (fsg->state != FSG_STATE_TERMINATED) {
+- if (exception_in_progress(fsg) || signal_pending(current)) {
+- handle_exception(fsg);
++ while (common->state != FSG_STATE_TERMINATED) {
++ if (exception_in_progress(common) || signal_pending(current)) {
++ handle_exception(common);
+ continue;
+ }
+
+- if (!fsg->running) {
+- sleep_thread(fsg);
++ if (!common->running) {
++ sleep_thread(common);
+ continue;
+ }
+
+- if (get_next_command(fsg))
++ if (get_next_command(common))
+ continue;
+
+- spin_lock_irq(&fsg->lock);
+- if (!exception_in_progress(fsg))
+- fsg->state = FSG_STATE_DATA_PHASE;
+- spin_unlock_irq(&fsg->lock);
++ spin_lock_irq(&common->lock);
++ if (!exception_in_progress(common))
++ common->state = FSG_STATE_DATA_PHASE;
++ spin_unlock_irq(&common->lock);
+
+- if (do_scsi_command(fsg) || finish_reply(fsg))
++ if (do_scsi_command(common) || finish_reply(common))
+ continue;
+
+- spin_lock_irq(&fsg->lock);
+- if (!exception_in_progress(fsg))
+- fsg->state = FSG_STATE_STATUS_PHASE;
+- spin_unlock_irq(&fsg->lock);
++ spin_lock_irq(&common->lock);
++ if (!exception_in_progress(common))
++ common->state = FSG_STATE_STATUS_PHASE;
++ spin_unlock_irq(&common->lock);
+
+- if (send_status(fsg))
++ if (send_status(common))
+ continue;
+
+- spin_lock_irq(&fsg->lock);
+- if (!exception_in_progress(fsg))
+- fsg->state = FSG_STATE_IDLE;
+- spin_unlock_irq(&fsg->lock);
++ spin_lock_irq(&common->lock);
++ if (!exception_in_progress(common))
++ common->state = FSG_STATE_IDLE;
++ spin_unlock_irq(&common->lock);
+ }
+
+- spin_lock_irq(&fsg->lock);
+- fsg->thread_task = NULL;
+- spin_unlock_irq(&fsg->lock);
++ spin_lock_irq(&common->lock);
++ common->thread_task = NULL;
++ spin_unlock_irq(&common->lock);
+
+ /* XXX */
+ /* If we are exiting because of a signal, unregister the
+@@ -2541,7 +2612,7 @@ static int fsg_main_thread(void *fsg_)
+ /* usb_gadget_unregister_driver(&fsg_driver); */
+
+ /* Let the unbind and cleanup routines know the thread has exited */
+- complete_and_exit(&fsg->thread_notifier, 0);
++ complete_and_exit(&common->thread_notifier, 0);
+ }
+
+
+@@ -2600,7 +2671,21 @@ static struct fsg_common *fsg_common_ini
+ memset(common, 0, sizeof common);
+ common->free_storage_on_release = 0;
+ }
++
+ common->gadget = gadget;
++ common->ep0 = gadget->ep0;
++ common->ep0req = cdev->req;
++
++ /* Maybe allocate device-global string IDs, and patch descriptors */
++ if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
++ rc = usb_string_id(cdev);
++ if (rc < 0) {
++ kfree(common);
++ return ERR_PTR(rc);
++ }
++ fsg_strings[FSG_STRING_INTERFACE].id = rc;
++ fsg_intf_desc.iInterface = rc;
++ }
+
+ /* Create the LUNs, open their backing files, and register the
+ * LUN devices in sysfs. */
+@@ -2697,11 +2782,23 @@ static struct fsg_common *fsg_common_ini
+ * disable stalls.
+ */
+ common->can_stall = cfg->can_stall &&
+- !(gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget));
++ !(gadget_is_sh(common->gadget) ||
++ gadget_is_at91(common->gadget));
+
+
+- common->thread_name = OR(cfg->thread_name, "file-storage");
++ spin_lock_init(&common->lock);
+ kref_init(&common->ref);
++
++
++ /* Tell the thread to start working */
++ common->thread_task =
++ kthread_create(fsg_main_thread, common,
++ OR(cfg->thread_name, "file-storage"));
++ if (IS_ERR(common->thread_task)) {
++ rc = PTR_ERR(common->thread_task);
++ goto error_release;
++ }
++ init_completion(&common->thread_notifier);
+ #undef OR
+
+
+@@ -2731,15 +2828,21 @@ static struct fsg_common *fsg_common_ini
+ }
+ kfree(pathbuf);
+
++ DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
++
++ wake_up_process(common->thread_task);
++
+ return common;
+
+
+ error_luns:
+ common->nluns = i + 1;
+ error_release:
++ common->state = FSG_STATE_TERMINATED; /* The thread is dead */
+ /* Call fsg_common_release() directly, ref might be not
+ * initialised */
+ fsg_common_release(&common->ref);
++ complete(&common->thread_notifier);
+ return ERR_PTR(rc);
+ }
+
+@@ -2751,6 +2854,15 @@ static void fsg_common_release(struct kr
+ unsigned i = common->nluns;
+ struct fsg_lun *lun = common->luns;
+
++ /* If the thread isn't already dead, tell it to exit now */
++ if (common->state != FSG_STATE_TERMINATED) {
++ raise_exception(common, FSG_STATE_EXIT);
++ wait_for_completion(&common->thread_notifier);
++
++ /* The cleanup routine waits for this completion also */
++ complete(&common->thread_notifier);
++ }
++
+ /* Beware tempting for -> do-while optimization: when in error
+ * recovery nluns may be zero. */
+
+@@ -2775,17 +2887,6 @@ static void fsg_unbind(struct usb_config
+ struct fsg_dev *fsg = fsg_from_func(f);
+
+ DBG(fsg, "unbind\n");
+- clear_bit(REGISTERED, &fsg->atomic_bitflags);
+-
+- /* If the thread isn't already dead, tell it to exit now */
+- if (fsg->state != FSG_STATE_TERMINATED) {
+- raise_exception(fsg, FSG_STATE_EXIT);
+- wait_for_completion(&fsg->thread_notifier);
+-
+- /* The cleanup routine waits for this completion also */
+- complete(&fsg->thread_notifier);
+- }
+-
+ fsg_common_put(fsg->common);
+ kfree(fsg);
+ }
+@@ -2800,8 +2901,6 @@ static int fsg_bind(struct usb_configura
+ struct usb_ep *ep;
+
+ fsg->gadget = gadget;
+- fsg->ep0 = gadget->ep0;
+- fsg->ep0req = c->cdev->req;
+
+ /* New interface */
+ i = usb_interface_id(c, f);
+@@ -2814,13 +2913,13 @@ static int fsg_bind(struct usb_configura
+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+- ep->driver_data = fsg; /* claim the endpoint */
++ ep->driver_data = fsg->common; /* claim the endpoint */
+ fsg->bulk_in = ep;
+
+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
+ if (!ep)
+ goto autoconf_fail;
+- ep->driver_data = fsg; /* claim the endpoint */
++ ep->driver_data = fsg->common; /* claim the endpoint */
+ fsg->bulk_out = ep;
+
+ if (gadget_is_dualspeed(gadget)) {
+@@ -2832,40 +2931,12 @@ static int fsg_bind(struct usb_configura
+ f->hs_descriptors = fsg_hs_function;
+ }
+
+-
+- /* maybe allocate device-global string IDs, and patch descriptors */
+- if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+- i = usb_string_id(c->cdev);
+- if (i < 0)
+- return i;
+- fsg_strings[FSG_STRING_INTERFACE].id = i;
+- fsg_intf_desc.iInterface = i;
+- }
+-
+-
+- fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+- fsg->common->thread_name);
+- if (IS_ERR(fsg->thread_task)) {
+- rc = PTR_ERR(fsg->thread_task);
+- goto out;
+- }
+-
+- DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
+-
+- set_bit(REGISTERED, &fsg->atomic_bitflags);
+-
+- /* Tell the thread to start working */
+- wake_up_process(fsg->thread_task);
+ return 0;
+
+ autoconf_fail:
+ ERROR(fsg, "unable to autoconfigure all endpoints\n");
+ rc = -ENOTSUPP;
+-
+-out:
+- fsg->state = FSG_STATE_TERMINATED; /* The thread is dead */
+ fsg_unbind(c, f);
+- complete(&fsg->thread_notifier);
+ return rc;
+ }
+
+@@ -2888,10 +2959,6 @@ static int fsg_add(struct usb_composite_
+ if (unlikely(!fsg))
+ return -ENOMEM;
+
+- spin_lock_init(&fsg->lock);
+- init_completion(&fsg->thread_notifier);
+-
+- fsg->cdev = cdev;
+ fsg->function.name = FSG_DRIVER_DESC;
+ fsg->function.strings = fsg_strings_array;
+ fsg->function.descriptors = fsg_fs_function;
+@@ -2907,7 +2974,6 @@ static int fsg_add(struct usb_composite_
+ * from this function. So instead of incrementing counter now
+ * and decrement in error recovery we increment it only when
+ * call to usb_add_function() was successful. */
+- fsg->can_stall = common->can_stall;
+
+ rc = usb_add_function(c, &fsg->function);
+
diff --git a/usb/usb-g_mass_storage-thread_exits-callback-added.patch b/usb/usb-g_mass_storage-thread_exits-callback-added.patch
new file mode 100644
index 00000000000000..8bd89724d5cd9c
--- /dev/null
+++ b/usb/usb-g_mass_storage-thread_exits-callback-added.patch
@@ -0,0 +1,151 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:29:06 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:26 +0100
+Subject: USB: g_mass_storage: thread_exits callback added
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-8-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+thread_exits callback has been added to fsg_common structure.
+This callback is called when MSF's thread exits (is terminated
+by a signal or function is unregistered). It's then gadget's
+responsibility to unregister the gadget.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_mass_storage.c | 23 ++++++++++++++++++-----
+ drivers/usb/gadget/mass_storage.c | 20 +++++++++++---------
+ 2 files changed, 29 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -367,6 +367,11 @@ struct fsg_common {
+ struct completion thread_notifier;
+ struct task_struct *thread_task;
+
++ /* Callback function to call when thread exits. */
++ void (*thread_exits)(struct fsg_common *common);
++ /* Gadget's private data. */
++ void *private_data;
++
+ /* Vendor (8 chars), product (16 chars), release (4
+ * hexadecimal digits) and NUL byte */
+ char inquiry_string[8 + 16 + 4 + 1];
+@@ -387,6 +392,11 @@ struct fsg_config {
+ const char *lun_name_format;
+ const char *thread_name;
+
++ /* Callback function to call when thread exits. */
++ void (*thread_exits)(struct fsg_common *common);
++ /* Gadget's private data. */
++ void *private_data;
++
+ const char *vendor_name; /* 8 characters or less */
+ const char *product_name; /* 16 characters or less */
+ u16 release;
+@@ -2605,11 +2615,8 @@ static int fsg_main_thread(void *common_
+ common->thread_task = NULL;
+ spin_unlock_irq(&common->lock);
+
+- /* XXX */
+- /* If we are exiting because of a signal, unregister the
+- * gadget driver. */
+- /* if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) */
+- /* usb_gadget_unregister_driver(&fsg_driver); */
++ if (common->thread_exits)
++ common->thread_exits(common);
+
+ /* Let the unbind and cleanup routines know the thread has exited */
+ complete_and_exit(&common->thread_notifier, 0);
+@@ -2672,6 +2679,8 @@ static struct fsg_common *fsg_common_ini
+ common->free_storage_on_release = 0;
+ }
+
++ common->private_data = cfg->private_data;
++
+ common->gadget = gadget;
+ common->ep0 = gadget->ep0;
+ common->ep0req = cdev->req;
+@@ -2791,6 +2800,7 @@ static struct fsg_common *fsg_common_ini
+
+
+ /* Tell the thread to start working */
++ common->thread_exits = cfg->thread_exits;
+ common->thread_task =
+ kthread_create(fsg_main_thread, common,
+ OR(cfg->thread_name, "file-storage"));
+@@ -3057,6 +3067,9 @@ fsg_config_from_params(struct fsg_config
+ cfg->product_name = 0;
+ cfg->release = 0xffff;
+
++ cfg->thread_exits = 0;
++ cfg->private_data = 0;
++
+ /* Finalise */
+ cfg->can_stall = params->stall;
+ }
+--- a/drivers/usb/gadget/mass_storage.c
++++ b/drivers/usb/gadget/mass_storage.c
+@@ -132,9 +132,13 @@ static struct fsg_module_parameters mod_
+ };
+ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
+
++static unsigned long msg_registered = 0;
++static void msg_cleanup(void);
++
+ static int __init msg_do_config(struct usb_configuration *c)
+ {
+ struct fsg_common *common;
++ struct fsg_config config;
+ int ret;
+
+ if (gadget_is_otg(c->cdev->gadget)) {
+@@ -142,7 +146,9 @@ static int __init msg_do_config(struct u
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+- common = fsg_common_from_params(0, c->cdev, &mod_data);
++ fsg_config_from_params(&config, &mod_data);
++ config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup;
++ common = fsg_common_init(0, c->cdev, &config);
+ if (IS_ERR(common))
+ return PTR_ERR(common);
+
+@@ -201,11 +207,7 @@ static int __init msg_bind(struct usb_co
+ return status;
+
+ dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+- return 0;
+-}
+-
+-static int __exit msg_unbind(struct usb_composite_dev *cdev)
+-{
++ set_bit(0, &msg_registered);
+ return 0;
+ }
+
+@@ -218,7 +220,6 @@ static struct usb_composite_driver msg_d
+ .dev = &msg_device_desc,
+ .strings = dev_strings,
+ .bind = msg_bind,
+- .unbind = __exit_p(msg_unbind),
+ };
+
+ MODULE_DESCRIPTION(DRIVER_DESC);
+@@ -231,8 +232,9 @@ static int __init msg_init(void)
+ }
+ module_init(msg_init);
+
+-static void __exit msg_cleanup(void)
++static void msg_cleanup(void)
+ {
+- usb_composite_unregister(&msg_driver);
++ if (test_and_clear_bit(0, &msg_registered))
++ usb_composite_unregister(&msg_driver);
+ }
+ module_exit(msg_cleanup);
diff --git a/usb/usb-g_multi-multifunction-composite-gadget-added.patch b/usb/usb-g_multi-multifunction-composite-gadget-added.patch
new file mode 100644
index 00000000000000..ba93a4d6dfb96f
--- /dev/null
+++ b/usb/usb-g_multi-multifunction-composite-gadget-added.patch
@@ -0,0 +1,459 @@
+From m.nazarewicz@samsung.com Fri Nov 20 12:31:31 2009
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Mon, 09 Nov 2009 14:15:27 +0100
+Subject: USB: g_multi: Multifunction Composite Gadget added
+To: Greg KH <greg@kroah.com>
+Cc: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Message-ID: <1257772527-870-9-git-send-email-m.nazarewicz@samsung.com>
+
+
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+
+The Multifunction Composite Gadget has two configurations
+consisting of Ethernet (RNDIS in first and CDC Ethernet in
+second configuration), CDC Serial and File-backed Storage
+functions.
+
+When connected to a Windows host, the first configuration
+is chosen thus gadget provides RNDIS Ethernet, serial and
+mass storage whereas when connected to Linux host, second
+configuration is chosen thus providing CDC Ethernet,
+serial and mass storage.
+
+Which configurations are built can be configured via
+KConfig options.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/gadget/Kconfig | 42 +++++
+ drivers/usb/gadget/Makefile | 2
+ drivers/usb/gadget/multi.c | 355 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 399 insertions(+)
+ create mode 100644 drivers/usb/gadget/multi.c
+
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -812,6 +812,48 @@ config USB_CDC_COMPOSITE
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module.
+
++config USB_G_MULTI
++ tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
++ help
++ The Multifunction Composite Gadget provides Ethernet (RNDIS
++ and/or CDC Ethernet), mass storage and ACM serial link
++ interfaces.
++
++ You will be asked too choose which of the two configurations are
++ to be available in the gadget. At least one configuration must
++ be choosen to make gadget usable. Selecting more then one
++ configuration will prevent Windows from automatically detecting
++ the gadget as a composite gadget an INF file will be needed to
++ use the gadget.
++
++ Say "y" to link the driver statically, or "m" to build a
++ dynamically linked module called "g_multi".
++
++config USB_G_MULTI_RNDIS
++ bool "RNDIS + CDC Serial + Storage configuration"
++ depends on USB_G_MULTI
++ default y
++ help
++ This option enables a configuration with RNDIS, CDC Serial and
++ Mass Storage functions available in the Multifunction Composite
++ Gadget. This is configuration dedicated for Windows since RNDIS
++ is Microsfot's protocol.
++
++ If unsure, say "y".
++
++config USB_G_MULTI_CDC
++ bool "CDC Ethernet + CDC Serial + Storage configuration"
++ depends on USB_G_MULTI
++ default n
++ help
++ This option enables a configuration with CDC Ethernet (ECM), CDC
++ Serial and Mass Storage functions available in the Multifunction
++ Composite Gadget. This is configuration dedicated for Windows
++ since RNDIS is Microsfot's protocol.
++
++ If unsure, say "y".
++
++
+ # put drivers that need isochronous transfer support (for audio
+ # or video class gadget drivers), or specific hardware, here.
+
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -42,6 +42,7 @@ g_file_storage-objs := file_storage.o
+ g_mass_storage-objs := mass_storage.o
+ g_printer-objs := printer.o
+ g_cdc-objs := cdc2.o
++g_multi-objs := multi.o
+
+ obj-$(CONFIG_USB_ZERO) += g_zero.o
+ obj-$(CONFIG_USB_AUDIO) += g_audio.o
+@@ -53,4 +54,5 @@ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
+ obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
+ obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
++obj-$(CONFIG_USB_G_MULTI) += g_multi.o
+
+--- /dev/null
++++ b/drivers/usb/gadget/multi.c
+@@ -0,0 +1,355 @@
++/*
++ * multi.c -- Multifunction Composite driver
++ *
++ * Copyright (C) 2008 David Brownell
++ * Copyright (C) 2008 Nokia Corporation
++ * Copyright (C) 2009 Samsung Electronics
++ * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
++ *
++ * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++
++
++#if defined CONFIG_USB_G_MULTI_RNDIS
++# define CONFIG_USB_ETH_RNDIS y
++#endif
++
++
++#define DRIVER_DESC "Multifunction Composite Gadget"
++#define DRIVER_VERSION "2009/07/21"
++
++/*-------------------------------------------------------------------------*/
++
++#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
++#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * kbuild is not very cooperative with respect to linking separately
++ * compiled library objects into one module. So for now we won't use
++ * separate compilation ... ensuring init/exit sections work to shrink
++ * the runtime footprint, and giving us at least some parts of what
++ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
++ */
++
++#include "composite.c"
++#include "usbstring.c"
++#include "config.c"
++#include "epautoconf.c"
++
++#include "u_serial.c"
++#include "f_acm.c"
++
++#include "f_ecm.c"
++#include "f_subset.c"
++#ifdef CONFIG_USB_ETH_RNDIS
++# include "f_rndis.c"
++# include "rndis.c"
++#endif
++#include "u_ether.c"
++
++#undef DBG /* u_ether.c has broken idea about macros */
++#undef VDBG /* so clean up after it */
++#undef ERROR
++#undef INFO
++#include "f_mass_storage.c"
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_device_descriptor device_desc = {
++ .bLength = sizeof device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++
++ .bcdUSB = cpu_to_le16(0x0200),
++
++ /* .bDeviceClass = USB_CLASS_COMM, */
++ /* .bDeviceSubClass = 0, */
++ /* .bDeviceProtocol = 0, */
++ .bDeviceClass = 0xEF,
++ .bDeviceSubClass = 2,
++ .bDeviceProtocol = 1,
++ /* .bMaxPacketSize0 = f(hardware) */
++
++ /* Vendor and product id can be overridden by module parameters. */
++ .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
++ .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
++ /* .bcdDevice = f(hardware) */
++ /* .iManufacturer = DYNAMIC */
++ /* .iProduct = DYNAMIC */
++ /* NO SERIAL NUMBER */
++ .bNumConfigurations = 1,
++};
++
++static struct usb_otg_descriptor otg_descriptor = {
++ .bLength = sizeof otg_descriptor,
++ .bDescriptorType = USB_DT_OTG,
++
++ /* REVISIT SRP-only hardware is possible, although
++ * it would not be called "OTG" ...
++ */
++ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
++};
++
++static const struct usb_descriptor_header *otg_desc[] = {
++ (struct usb_descriptor_header *) &otg_descriptor,
++ NULL,
++};
++
++
++/* string IDs are assigned dynamically */
++
++#define STRING_MANUFACTURER_IDX 0
++#define STRING_PRODUCT_IDX 1
++
++static char manufacturer[50];
++
++static struct usb_string strings_dev[] = {
++ [STRING_MANUFACTURER_IDX].s = manufacturer,
++ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_dev = {
++ .language = 0x0409, /* en-us */
++ .strings = strings_dev,
++};
++
++static struct usb_gadget_strings *dev_strings[] = {
++ &stringtab_dev,
++ NULL,
++};
++
++static u8 hostaddr[ETH_ALEN];
++
++
++
++/****************************** Configurations ******************************/
++
++static struct fsg_module_parameters mod_data = {
++ .stall = 1
++};
++FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
++
++static struct fsg_common *fsg_common;
++
++
++#ifdef CONFIG_USB_ETH_RNDIS
++
++static int __init rndis_do_config(struct usb_configuration *c)
++{
++ int ret;
++
++ if (gadget_is_otg(c->cdev->gadget)) {
++ c->descriptors = otg_desc;
++ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
++
++ ret = rndis_bind_config(c, hostaddr);
++ if (ret < 0)
++ return ret;
++
++ ret = acm_bind_config(c, 0);
++ if (ret < 0)
++ return ret;
++
++ ret = fsg_add(c->cdev, c, fsg_common);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static struct usb_configuration rndis_config_driver = {
++ .label = "Multifunction Composite (RNDIS + MS + ACM)",
++ .bind = rndis_do_config,
++ .bConfigurationValue = 2,
++ /* .iConfiguration = DYNAMIC */
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++};
++
++#endif
++
++#ifdef CONFIG_USB_G_MULTI_CDC
++
++static int __init cdc_do_config(struct usb_configuration *c)
++{
++ int ret;
++
++ if (gadget_is_otg(c->cdev->gadget)) {
++ c->descriptors = otg_desc;
++ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
++
++ ret = ecm_bind_config(c, hostaddr);
++ if (ret < 0)
++ return ret;
++
++ ret = acm_bind_config(c, 0);
++ if (ret < 0)
++ return ret;
++
++ ret = fsg_add(c->cdev, c, fsg_common);
++ if (ret < 0)
++ return ret;
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static struct usb_configuration cdc_config_driver = {
++ .label = "Multifunction Composite (CDC + MS + ACM)",
++ .bind = cdc_do_config,
++ .bConfigurationValue = 1,
++ /* .iConfiguration = DYNAMIC */
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++};
++
++#endif
++
++
++
++/****************************** Gadget Bind ******************************/
++
++
++static int __init multi_bind(struct usb_composite_dev *cdev)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ int status, gcnum;
++
++ if (!can_support_ecm(cdev->gadget)) {
++ dev_err(&gadget->dev, "controller '%s' not usable\n",
++ gadget->name);
++ return -EINVAL;
++ }
++
++ /* set up network link layer */
++ status = gether_setup(cdev->gadget, hostaddr);
++ if (status < 0)
++ return status;
++
++ /* set up serial link layer */
++ status = gserial_setup(cdev->gadget, 1);
++ if (status < 0)
++ goto fail0;
++
++ /* set up mass storage function */
++ fsg_common = fsg_common_from_params(0, cdev, &mod_data);
++ if (IS_ERR(fsg_common)) {
++ status = PTR_ERR(fsg_common);
++ goto fail1;
++ }
++
++
++ gcnum = usb_gadget_controller_number(gadget);
++ if (gcnum >= 0)
++ device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
++ else {
++ /* We assume that can_support_ecm() tells the truth;
++ * but if the controller isn't recognized at all then
++ * that assumption is a bit more likely to be wrong.
++ */
++ WARNING(cdev, "controller '%s' not recognized\n",
++ gadget->name);
++ device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
++ }
++
++
++ /* Allocate string descriptor numbers ... note that string
++ * contents can be overridden by the composite_dev glue.
++ */
++
++ /* device descriptor strings: manufacturer, product */
++ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
++ init_utsname()->sysname, init_utsname()->release,
++ gadget->name);
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail2;
++ strings_dev[STRING_MANUFACTURER_IDX].id = status;
++ device_desc.iManufacturer = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail2;
++ strings_dev[STRING_PRODUCT_IDX].id = status;
++ device_desc.iProduct = status;
++
++#ifdef CONFIG_USB_ETH_RNDIS
++ /* register our first configuration */
++ status = usb_add_config(cdev, &rndis_config_driver);
++ if (status < 0)
++ goto fail2;
++#endif
++
++#ifdef CONFIG_USB_G_MULTI_CDC
++ /* register our second configuration */
++ status = usb_add_config(cdev, &cdc_config_driver);
++ if (status < 0)
++ goto fail2;
++#endif
++
++ dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
++ fsg_common_put(fsg_common);
++ return 0;
++
++fail2:
++ fsg_common_put(fsg_common);
++fail1:
++ gserial_cleanup();
++fail0:
++ gether_cleanup();
++ return status;
++}
++
++static int __exit multi_unbind(struct usb_composite_dev *cdev)
++{
++ gserial_cleanup();
++ gether_cleanup();
++ return 0;
++}
++
++
++/****************************** Some noise ******************************/
++
++
++static struct usb_composite_driver multi_driver = {
++ .name = "g_multi",
++ .dev = &device_desc,
++ .strings = dev_strings,
++ .bind = multi_bind,
++ .unbind = __exit_p(multi_unbind),
++};
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Michal Nazarewicz");
++MODULE_LICENSE("GPL");
++
++static int __init g_multi_init(void)
++{
++ return usb_composite_register(&multi_driver);
++}
++module_init(g_multi_init);
++
++static void __exit g_multi_cleanup(void)
++{
++ usb_composite_unregister(&multi_driver);
++}
++module_exit(g_multi_cleanup);
diff --git a/usb/usb-musb-add-notes-for-blackfin-anomalies.patch b/usb/usb-musb-add-notes-for-blackfin-anomalies.patch
new file mode 100644
index 00000000000000..99fa72f8fa2095
--- /dev/null
+++ b/usb/usb-musb-add-notes-for-blackfin-anomalies.patch
@@ -0,0 +1,60 @@
+From gadiyar@ti.com Fri Nov 20 12:41:46 2009
+From: Sonic Zhang <sonic.zhang@analog.com>
+Date: Mon, 16 Nov 2009 19:13:08 +0530
+Subject: USB: musb: add notes for Blackfin anomalies
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Sonic Zhang <sonic.zhang@analog.com>, Cliff Cai <cliff.cai@analog.com>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258378988-20147-1-git-send-email-gadiyar@ti.com>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Add some helpful notes about how the driver works around different
+anomalies that exist in the on-chip host controller.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/blackfin.h | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/drivers/usb/musb/blackfin.h
++++ b/drivers/usb/musb/blackfin.h
+@@ -14,6 +14,33 @@
+ * Blackfin specific definitions
+ */
+
++/* Anomalies notes:
++ *
++ * 05000450 - USB DMA Mode 1 Short Packet Data Corruption:
++ * MUSB driver is designed to transfer buffer of N * maxpacket size
++ * in DMA mode 1 and leave the rest of the data to the next
++ * transfer in DMA mode 0, so we never transmit a short packet in
++ * DMA mode 1.
++ *
++ * 05000463 - This anomaly doesn't affect this driver since it
++ * never uses L1 or L2 memory as data destination.
++ *
++ * 05000464 - This anomaly doesn't affect this driver since it
++ * never uses L1 or L2 memory as data source.
++ *
++ * 05000465 - The anomaly can be seen when SCLK is over 100 MHz, and there is
++ * no way to workaround for bulk endpoints. Since the wMaxPackSize
++ * of bulk is less than or equal to 512, while the fifo size of
++ * endpoint 5, 6, 7 is 1024, the double buffer mode is enabled
++ * automatically when these endpoints are used for bulk OUT.
++ *
++ * 05000466 - This anomaly doesn't affect this driver since it never mixes
++ * concurrent DMA and core accesses to the TX endpoint FIFOs.
++ *
++ * 05000467 - The workaround for this anomaly will introduce another
++ * anomaly - 05000465.
++ */
++
+ #undef DUMP_FIFO_DATA
+ #ifdef DUMP_FIFO_DATA
+ static void dump_fifo_data(u8 *buf, u16 len)
diff --git a/usb/usb-musb-add-work-around-for-blackfin-anomaly-05000456.patch b/usb/usb-musb-add-work-around-for-blackfin-anomaly-05000456.patch
new file mode 100644
index 00000000000000..f1c8c4d2f81273
--- /dev/null
+++ b/usb/usb-musb-add-work-around-for-blackfin-anomaly-05000456.patch
@@ -0,0 +1,45 @@
+From gadiyar@ti.com Fri Nov 20 12:45:11 2009
+From: Sonic Zhang <sonic.zhang@analog.com>
+Date: Mon, 16 Nov 2009 16:19:24 +0530
+Subject: USB: musb: add work around for Blackfin anomaly 05000456
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Sonic Zhang <sonic.zhang@analog.com>, Cliff Cai <cliff.cai@analog.com>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-6-git-send-email-gadiyar@ti.com>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Only allow USE_MODE1 when the Blackfin part is not affected by anomaly
+05000456 (USB Receive Interrupt Is Not Generated in DMA Mode 1) since we
+can't support the mode in that case.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_dma.h | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/usb/musb/musb_dma.h
++++ b/drivers/usb/musb/musb_dma.h
+@@ -80,6 +80,17 @@ struct musb_hw_ep;
+ #define tusb_dma_omap() 0
+ #endif
+
++/* Anomaly 05000456 - USB Receive Interrupt Is Not Generated in DMA Mode 1
++ * Only allow DMA mode 1 to be used when the USB will actually generate the
++ * interrupts we expect.
++ */
++#ifdef CONFIG_BLACKFIN
++# undef USE_MODE1
++# if !ANOMALY_05000456
++# define USE_MODE1
++# endif
++#endif
++
+ /*
+ * DMA channel status ... updated by the dma controller driver whenever that
+ * status changes, and protected by the overall controller spinlock.
diff --git a/usb/usb-musb-blackfin-code-needs-nop_usb_xceiv-too.patch b/usb/usb-musb-blackfin-code-needs-nop_usb_xceiv-too.patch
new file mode 100644
index 00000000000000..f9410122cec2bb
--- /dev/null
+++ b/usb/usb-musb-blackfin-code-needs-nop_usb_xceiv-too.patch
@@ -0,0 +1,38 @@
+From vapier@gentoo.org Fri Nov 20 12:46:12 2009
+From: Cliff Cai <cliff.cai@analog.com>
+Date: Mon, 16 Nov 2009 20:05:03 -0500
+Subject: USB: musb: Blackfin code needs NOP_USB_XCEIV too
+To: linux-usb@vger.kernel.org, Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Cliff Cai <cliff.cai@analog.com>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258419903-29677-1-git-send-email-vapier@gentoo.org>
+
+
+From: Cliff Cai <cliff.cai@analog.com>
+
+Otherwise we get the link failure:
+drivers/built-in.o: In function 'musb_platform_init':
+drivers/usb/musb/blackfin.c:300: undefined reference to 'usb_nop_xceiv_register'
+make: *** [.tmp_vmlinux1] Error 1
+
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/Kconfig | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -10,9 +10,8 @@ comment "Enable Host or Gadget support t
+ config USB_MUSB_HDRC
+ depends on (USB || USB_GADGET)
+ depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
+- select NOP_USB_XCEIV if ARCH_DAVINCI
++ select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
+ select TWL4030_USB if MACH_OMAP_3430SDP
+- select NOP_USB_XCEIV if MACH_OMAP3EVM
+ select USB_OTG_UTILS
+ tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+ help
diff --git a/usb/usb-musb-clear-the-blackfin-interrupt-pending-bits-early-in-the-isr.patch b/usb/usb-musb-clear-the-blackfin-interrupt-pending-bits-early-in-the-isr.patch
new file mode 100644
index 00000000000000..c9b772ce512c3b
--- /dev/null
+++ b/usb/usb-musb-clear-the-blackfin-interrupt-pending-bits-early-in-the-isr.patch
@@ -0,0 +1,51 @@
+From gadiyar@ti.com Fri Nov 20 12:45:39 2009
+From: Cliff Cai <cliff.cai@analog.com>
+Date: Mon, 16 Nov 2009 16:19:26 +0530
+Subject: USB: musb: clear the Blackfin interrupt pending bits early in the ISR
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Cliff Cai <cliff.cai@analog.com>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-8-git-send-email-gadiyar@ti.com>
+
+
+From: Cliff Cai <cliff.cai@analog.com>
+
+If we clear the interrupt pending bits at the end, we sometimes return too
+fast and have the same interrupt assert itself. There is no way in a
+Blackfin system to force a sync of this state, so the hardware manual
+instructs people to clear interrupt flags early in their ISR.
+
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musbhsdma.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/musb/musbhsdma.c
++++ b/drivers/usb/musb/musbhsdma.c
+@@ -259,6 +259,11 @@ static irqreturn_t dma_controller_irq(in
+ if (!int_hsdma)
+ goto done;
+
++#ifdef CONFIG_BLACKFIN
++ /* Clear DMA interrupt flags */
++ musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
++#endif
++
+ for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+ if (int_hsdma & (1 << bchannel)) {
+ musb_channel = (struct musb_dma_channel *)
+@@ -324,11 +329,6 @@ static irqreturn_t dma_controller_irq(in
+ }
+ }
+
+-#ifdef CONFIG_BLACKFIN
+- /* Clear DMA interrup flags */
+- musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
+-#endif
+-
+ retval = IRQ_HANDLED;
+ done:
+ spin_unlock_irqrestore(&musb->lock, flags);
diff --git a/usb/usb-musb-error-out-when-anomaly-05000380-is-applicable.patch b/usb/usb-musb-error-out-when-anomaly-05000380-is-applicable.patch
new file mode 100644
index 00000000000000..5f360db66a491a
--- /dev/null
+++ b/usb/usb-musb-error-out-when-anomaly-05000380-is-applicable.patch
@@ -0,0 +1,42 @@
+From gadiyar@ti.com Fri Nov 20 12:45:56 2009
+From: Sonic Zhang <sonic.zhang@analog.com>
+Date: Mon, 16 Nov 2009 16:19:27 +0530
+Subject: USB: musb: error out when anomaly 05000380 is applicable
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Sonic Zhang <sonic.zhang@analog.com>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-9-git-send-email-gadiyar@ti.com>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Since we can't work around anomaly 05000380, throw a build error up and
+instruct the user to use a different mode.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/blackfin.h | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/usb/musb/blackfin.h
++++ b/drivers/usb/musb/blackfin.h
+@@ -41,6 +41,16 @@
+ * anomaly - 05000465.
+ */
+
++/* The Mentor USB DMA engine on BF52x (silicon v0.0 and v0.1) seems to be
++ * unstable in host mode. This may be caused by Anomaly 05000380. After
++ * digging out the root cause, we will change this number accordingly.
++ * So, need to either use silicon v0.2+ or disable DMA mode in MUSB.
++ */
++#if ANOMALY_05000380 && defined(CONFIG_BF52x) && \
++ defined(CONFIG_USB_MUSB_HDRC) && !defined(CONFIG_MUSB_PIO_ONLY)
++# error "Please use PIO mode in MUSB driver on bf52x chip v0.0 and v0.1"
++#endif
++
+ #undef DUMP_FIFO_DATA
+ #ifdef DUMP_FIFO_DATA
+ static void dump_fifo_data(u8 *buf, u16 len)
diff --git a/usb/usb-musb-fix-musb_platform_set_mode-definition.patch b/usb/usb-musb-fix-musb_platform_set_mode-definition.patch
new file mode 100644
index 00000000000000..240ac5f8b806cd
--- /dev/null
+++ b/usb/usb-musb-fix-musb_platform_set_mode-definition.patch
@@ -0,0 +1,36 @@
+From gadiyar@ti.com Fri Nov 20 12:45:25 2009
+From: Bryan Wu <cooloney@kernel.org>
+Date: Mon, 16 Nov 2009 16:19:25 +0530
+Subject: USB: musb: fix musb_platform_set_mode() definition
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Bryan Wu <cooloney@kernel.org>, Cliff Cai <cliff.cai@analog.com>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-7-git-send-email-gadiyar@ti.com>
+
+
+From: Bryan Wu <cooloney@kernel.org>
+
+Update function definition to match latest MUSB framework.
+
+Signed-off-by: Bryan Wu <cooloney@kernel.org>
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/blackfin.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/musb/blackfin.c
++++ b/drivers/usb/musb/blackfin.c
+@@ -226,8 +226,9 @@ int musb_platform_get_vbus_status(struct
+ return 0;
+ }
+
+-void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
++int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+ {
++ return -EIO;
+ }
+
+ int __init musb_platform_init(struct musb *musb)
diff --git a/usb/usb-musb-fix-printf-warning-in-debug-code.patch b/usb/usb-musb-fix-printf-warning-in-debug-code.patch
new file mode 100644
index 00000000000000..da3cd1401cf088
--- /dev/null
+++ b/usb/usb-musb-fix-printf-warning-in-debug-code.patch
@@ -0,0 +1,37 @@
+From gadiyar@ti.com Fri Nov 20 12:46:28 2009
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Mon, 16 Nov 2009 16:19:29 +0530
+Subject: USB: musb: fix printf warning in debug code
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-11-git-send-email-gadiyar@ti.com>
+
+
+From: Mike Frysinger <vapier@gentoo.org>
+
+The debug code in the DMA ISR uses a %d for a size_t when it should be
+using %zu. Otherwise gcc whines with:
+
+drivers/usb/musb/musbhsdma.c: In function 'dma_controller_irq':
+drivers/usb/musb/musbhsdma.c:288: warning: format '%d' expects type 'int',
+ but argument 7 has type 'size_t'
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musbhsdma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/musb/musbhsdma.c
++++ b/drivers/usb/musb/musbhsdma.c
+@@ -285,7 +285,7 @@ static irqreturn_t dma_controller_irq(in
+ channel->actual_len = addr
+ - musb_channel->start_addr;
+
+- DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
++ DBG(2, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n",
+ channel, musb_channel->start_addr,
+ addr, channel->actual_len,
+ musb_channel->len,
diff --git a/usb/usb-musb-kill-compile-warning-for-blackfin-systems.patch b/usb/usb-musb-kill-compile-warning-for-blackfin-systems.patch
new file mode 100644
index 00000000000000..b411d79b993833
--- /dev/null
+++ b/usb/usb-musb-kill-compile-warning-for-blackfin-systems.patch
@@ -0,0 +1,42 @@
+From gadiyar@ti.com Fri Nov 20 12:39:02 2009
+From: Bryan Wu <cooloney@kernel.org>
+Date: Mon, 16 Nov 2009 16:19:20 +0530
+Subject: USB: musb: kill compile warning for Blackfin systems
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Bryan Wu <cooloney@kernel.org>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-2-git-send-email-gadiyar@ti.com>
+
+
+From: Bryan Wu <cooloney@kernel.org>
+
+The Blackfin version of musb_read_target_reg_base() returns a u16 when the
+common code expects a (void __iomem *), so update the Blackfin function to
+return the right value. This fixes the compile warning:
+
+drivers/usb/musb/musb_core.c: In function 'musb_core_init':
+drivers/usb/musb/musb_core.c:1448: warning: assignment makes pointer from
+ integer without a cast
+
+Signed-off-by: Bryan Wu <cooloney@kernel.org>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_regs.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/musb/musb_regs.h
++++ b/drivers/usb/musb/musb_regs.h
+@@ -465,9 +465,9 @@ static inline u16 musb_read_hwvers(void
+ return 0;
+ }
+
+-static inline u16 musb_read_target_reg_base(u8 i, void __iomem *mbase)
++static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
+ {
+- return 0;
++ return NULL;
+ }
+
+ static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
diff --git a/usb/usb-musb-kill-some-useless-comments-in-blackfin-driver.patch b/usb/usb-musb-kill-some-useless-comments-in-blackfin-driver.patch
new file mode 100644
index 00000000000000..1bfb3591b69546
--- /dev/null
+++ b/usb/usb-musb-kill-some-useless-comments-in-blackfin-driver.patch
@@ -0,0 +1,34 @@
+From gadiyar@ti.com Fri Nov 20 12:39:38 2009
+From: Bryan Wu <cooloney@kernel.org>
+Date: Mon, 16 Nov 2009 16:19:21 +0530
+Subject: USB: musb: kill some useless comments in Blackfin driver
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Bryan Wu <cooloney@kernel.org>, Cliff Cai <cliff.cai@analog.com>, Mike Frysinger <vapier@gentoo.org>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-3-git-send-email-gadiyar@ti.com>
+
+
+From: Bryan Wu <cooloney@kernel.org>
+
+Signed-off-by: Bryan Wu <cooloney@kernel.org>
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/blackfin.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/usb/musb/blackfin.c
++++ b/drivers/usb/musb/blackfin.c
+@@ -262,10 +262,6 @@ int __init musb_platform_init(struct mus
+ SSYNC();
+ }
+
+- /* TODO
+- * Set SIC-IVG register
+- */
+-
+ /* Configure PLL oscillator register */
+ bfin_write_USB_PLLOSC_CTRL(0x30a8);
+ SSYNC();
diff --git a/usb/usb-musb-save-hardware-revision-at-init.patch b/usb/usb-musb-save-hardware-revision-at-init.patch
new file mode 100644
index 00000000000000..11836180620f90
--- /dev/null
+++ b/usb/usb-musb-save-hardware-revision-at-init.patch
@@ -0,0 +1,73 @@
+From gadiyar@ti.com Fri Nov 20 12:46:59 2009
+From: Anand Gadiyar <gadiyar@ti.com>
+Date: Mon, 16 Nov 2009 21:09:21 +0530
+Subject: USB: MUSB: save hardware revision at init
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Anand Gadiyar <gadiyar@ti.com>, Ajay Kumar Gupta <ajay.gupta@ti.com>, Felipe Balbi <felipe.balbi@nokia.com>, David Brownell <dbrownell@users.sourceforge.net>, Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Message-ID: <1258385961-28495-1-git-send-email-gadiyar@ti.com>
+
+
+MUSB: save hardware revision at init
+
+This can be used later to flag workarounds for issues affecting
+particular revisions. Saving this at init avoids having to
+read the HWVERS register multiple times in code.
+
+While at it, use macros to extract the version information
+instead of using hardcoded values.
+
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Cc: Ajay Kumar Gupta <ajay.gupta@ti.com>
+Acked-by: Felipe Balbi <felipe.balbi@nokia.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_core.c | 10 ++++------
+ drivers/usb/musb/musb_core.h | 8 ++++++++
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -1319,7 +1319,6 @@ static int __init musb_core_init(u16 mus
+ #endif
+ u8 reg;
+ char *type;
+- u16 hwvers, rev_major, rev_minor;
+ char aInfo[78], aRevision[32], aDate[12];
+ void __iomem *mbase = musb->mregs;
+ int status = 0;
+@@ -1391,11 +1390,10 @@ static int __init musb_core_init(u16 mus
+ }
+
+ /* log release info */
+- hwvers = musb_read_hwvers(mbase);
+- rev_major = (hwvers >> 10) & 0x1f;
+- rev_minor = hwvers & 0x3ff;
+- snprintf(aRevision, 32, "%d.%d%s", rev_major,
+- rev_minor, (hwvers & 0x8000) ? "RC" : "");
++ musb->hwvers = musb_read_hwvers(mbase);
++ snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers),
++ MUSB_HWVERS_MINOR(musb->hwvers),
++ (musb->hwvers & MUSB_HWVERS_RC) ? "RC" : "");
+ printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
+ musb_driver_name, type, aRevision, aDate);
+
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -322,6 +322,14 @@ struct musb {
+ struct clk *clock;
+ irqreturn_t (*isr)(int, void *);
+ struct work_struct irq_work;
++#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
++#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
++#define MUSB_HWVERS_RC 0x8000
++#define MUSB_HWVERS_1300 0x52C
++#define MUSB_HWVERS_1400 0x590
++#define MUSB_HWVERS_1800 0x720
++#define MUSB_HWVERS_2000 0x800
++ u16 hwvers;
+
+ /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
+ #define MUSB_PORT_STAT_RESUME (1 << 31)
diff --git a/usb/usb-musb-tweak-musb_read_fifo-to-avoid-unused-warnings.patch b/usb/usb-musb-tweak-musb_read_fifo-to-avoid-unused-warnings.patch
new file mode 100644
index 00000000000000..430cd2a400af7f
--- /dev/null
+++ b/usb/usb-musb-tweak-musb_read_fifo-to-avoid-unused-warnings.patch
@@ -0,0 +1,52 @@
+From gadiyar@ti.com Fri Nov 20 12:38:43 2009
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Mon, 16 Nov 2009 16:19:19 +0530
+Subject: USB: musb: tweak musb_read_fifo() to avoid unused warnings
+Cc: Mike Frysinger <vapier@gentoo.org>, Bryan Wu <cooloney@kernel.org>, Cliff Cai <cliff.cai@analog.com>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368569-4323-1-git-send-email-gadiyar@ti.com>
+
+
+From: Mike Frysinger <vapier@gentoo.org>
+
+Otherwise gcc will whine about epnum/dma_reg being unused when building
+for BF54x parts.
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Bryan Wu <cooloney@kernel.org>
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Acked-by: Felipe Balbi <felipe.balbi@nokia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/blackfin.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/musb/blackfin.c
++++ b/drivers/usb/musb/blackfin.c
+@@ -53,13 +53,11 @@ void musb_write_fifo(struct musb_hw_ep *
+ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+ {
+ void __iomem *fifo = hw_ep->fifo;
++
++#ifdef CONFIG_BF52x
+ u8 epnum = hw_ep->epnum;
+ u16 dma_reg = 0;
+
+- DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+- 'R', hw_ep->epnum, fifo, len, dst);
+-
+-#ifdef CONFIG_BF52x
+ invalidate_dcache_range((unsigned int)dst,
+ (unsigned int)(dst + len));
+
+@@ -102,6 +100,9 @@ void musb_read_fifo(struct musb_hw_ep *h
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ #endif
+
++ DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
++ 'R', hw_ep->epnum, fifo, len, dst);
++
+ dump_fifo_data(dst, len);
+ }
+
diff --git a/usb/usb-musb-update-blackfin-processor-dependency.patch b/usb/usb-musb-update-blackfin-processor-dependency.patch
new file mode 100644
index 00000000000000..31a464438e954c
--- /dev/null
+++ b/usb/usb-musb-update-blackfin-processor-dependency.patch
@@ -0,0 +1,36 @@
+From vapier@gentoo.org Fri Nov 20 12:41:14 2009
+From: Sonic Zhang <sonic.zhang@analog.com>
+Date: Mon, 16 Nov 2009 20:04:21 -0500
+Subject: USB: musb: update Blackfin processor dependency
+To: linux-usb@vger.kernel.org, Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Sonic Zhang <sonic.zhang@analog.com>, Bryan Wu <cooloney@kernel.org>, Cliff Cai <cliff.cai@analog.com>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258419861-29598-1-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Do not allow MUSB driver to be selected on derivatives that don't have the
+MUSB controller on them.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Bryan Wu <cooloney@kernel.org>
+Signed-off-by: Cliff Cai <cliff.cai@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -9,7 +9,7 @@ comment "Enable Host or Gadget support t
+ # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
+ config USB_MUSB_HDRC
+ depends on (USB || USB_GADGET)
+- depends on (ARM || BLACKFIN)
++ depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
+ select NOP_USB_XCEIV if ARCH_DAVINCI
+ select TWL4030_USB if MACH_OMAP_3430SDP
+ select NOP_USB_XCEIV if MACH_OMAP3EVM
diff --git a/usb/usb-musb_gadget-implement-set_wedge-method.patch b/usb/usb-musb_gadget-implement-set_wedge-method.patch
new file mode 100644
index 00000000000000..d53f6e1604e77e
--- /dev/null
+++ b/usb/usb-musb_gadget-implement-set_wedge-method.patch
@@ -0,0 +1,104 @@
+From sshtylyov@ru.mvista.com Fri Nov 20 13:07:26 2009
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Date: Wed, 18 Nov 2009 22:51:51 +0300
+Subject: USB: musb_gadget: implement set_wedge() method
+To: gregkh@suse.de, <david-b@pacbell.net>
+Cc: linux-usb@vger.kernel.org, davinci-linux-open-source@linux.davincidsp.com
+Message-ID: <200911182251.51894.sshtylyov@ru.mvista.com>
+
+
+Implement the driver's set_wedge() method by adding the 'wedged' flag
+to the 'struct musb_ep'.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_gadget.c | 20 +++++++++++++++++++-
+ drivers/usb/musb/musb_gadget.h | 2 ++
+ drivers/usb/musb/musb_gadget_ep0.c | 6 +++++-
+ 3 files changed, 26 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -966,6 +966,7 @@ static int musb_gadget_enable(struct usb
+
+ musb_ep->desc = desc;
+ musb_ep->busy = 0;
++ musb_ep->wedged = 0;
+ status = 0;
+
+ pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n",
+@@ -1262,7 +1263,8 @@ int musb_gadget_set_halt(struct usb_ep *
+ goto done;
+ }
+ }
+- }
++ } else
++ musb_ep->wedged = 0;
+
+ /* set/clear the stall and toggle bits */
+ DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
+@@ -1301,6 +1303,21 @@ done:
+ return status;
+ }
+
++/*
++ * Sets the halt feature with the clear requests ignored
++ */
++int musb_gadget_set_wedge(struct usb_ep *ep)
++{
++ struct musb_ep *musb_ep = to_musb_ep(ep);
++
++ if (!ep)
++ return -EINVAL;
++
++ musb_ep->wedged = 1;
++
++ return usb_ep_set_halt(ep);
++}
++
+ static int musb_gadget_fifo_status(struct usb_ep *ep)
+ {
+ struct musb_ep *musb_ep = to_musb_ep(ep);
+@@ -1371,6 +1388,7 @@ static const struct usb_ep_ops musb_ep_o
+ .queue = musb_gadget_queue,
+ .dequeue = musb_gadget_dequeue,
+ .set_halt = musb_gadget_set_halt,
++ .set_wedge = musb_gadget_set_wedge,
+ .fifo_status = musb_gadget_fifo_status,
+ .fifo_flush = musb_gadget_fifo_flush
+ };
+--- a/drivers/usb/musb/musb_gadget_ep0.c
++++ b/drivers/usb/musb/musb_gadget_ep0.c
+@@ -273,6 +273,11 @@ __acquires(musb->lock)
+ if (!musb_ep->desc)
+ break;
+
++ handled = 1;
++ /* Ignore request if endpoint is wedged */
++ if (musb_ep->wedged)
++ break;
++
+ /* REVISIT do it directly, no locking games */
+ spin_unlock(&musb->lock);
+ musb_gadget_set_halt(&musb_ep->end_point, 0);
+@@ -280,7 +285,6 @@ __acquires(musb->lock)
+
+ /* select ep0 again */
+ musb_ep_select(mbase, 0);
+- handled = 1;
+ } break;
+ default:
+ /* class, vendor, etc ... delegate */
+--- a/drivers/usb/musb/musb_gadget.h
++++ b/drivers/usb/musb/musb_gadget.h
+@@ -75,6 +75,8 @@ struct musb_ep {
+ /* later things are modified based on usage */
+ struct list_head req_list;
+
++ u8 wedged;
++
+ /* true if lock must be dropped but req_list may not be advanced */
+ u8 busy;
+ };
diff --git a/usb/usb-musb_gadget-remove-pointless-loop.patch b/usb/usb-musb_gadget-remove-pointless-loop.patch
new file mode 100644
index 00000000000000..8e5aad449451b5
--- /dev/null
+++ b/usb/usb-musb_gadget-remove-pointless-loop.patch
@@ -0,0 +1,216 @@
+From sshtylyov@ru.mvista.com Fri Nov 20 13:08:34 2009
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Date: Wed, 18 Nov 2009 22:55:28 +0300
+Subject: USB: musb_gadget: remove pointless loop
+To: gregkh@suse.de, <david-b@pacbell.net>
+Cc: linux-usb@vger.kernel.org, davinci-linux-open-source@linux.davincidsp.com
+Message-ID: <200911182255.28785.sshtylyov@ru.mvista.com>
+Content-Disposition: inline
+
+
+Remove the pointless 'do () while (0)' loop from musb_g_tx() -- it
+makes this function symmetric to musb_g_rx()...
+
+Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_gadget.c | 172 +++++++++++++++++++----------------------
+ 1 file changed, 81 insertions(+), 91 deletions(-)
+
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -429,112 +429,102 @@ void musb_g_tx(struct musb *musb, u8 epn
+ DBG(4, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr);
+
+ dma = is_dma_capable() ? musb_ep->dma : NULL;
+- do {
+- /* REVISIT for high bandwidth, MUSB_TXCSR_P_INCOMPTX
+- * probably rates reporting as a host error
++
++ /*
++ * REVISIT: for high bandwidth, MUSB_TXCSR_P_INCOMPTX
++ * probably rates reporting as a host error.
++ */
++ if (csr & MUSB_TXCSR_P_SENTSTALL) {
++ csr |= MUSB_TXCSR_P_WZC_BITS;
++ csr &= ~MUSB_TXCSR_P_SENTSTALL;
++ musb_writew(epio, MUSB_TXCSR, csr);
++ return;
++ }
++
++ if (csr & MUSB_TXCSR_P_UNDERRUN) {
++ /* We NAKed, no big deal... little reason to care. */
++ csr |= MUSB_TXCSR_P_WZC_BITS;
++ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
++ musb_writew(epio, MUSB_TXCSR, csr);
++ DBG(20, "underrun on ep%d, req %p\n", epnum, request);
++ }
++
++ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
++ /*
++ * SHOULD NOT HAPPEN... has with CPPI though, after
++ * changing SENDSTALL (and other cases); harmless?
+ */
+- if (csr & MUSB_TXCSR_P_SENTSTALL) {
+- csr |= MUSB_TXCSR_P_WZC_BITS;
+- csr &= ~MUSB_TXCSR_P_SENTSTALL;
+- musb_writew(epio, MUSB_TXCSR, csr);
+- break;
+- }
++ DBG(5, "%s dma still busy?\n", musb_ep->end_point.name);
++ return;
++ }
+
+- if (csr & MUSB_TXCSR_P_UNDERRUN) {
+- /* we NAKed, no big deal ... little reason to care */
++ if (request) {
++ u8 is_dma = 0;
++
++ if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
++ is_dma = 1;
+ csr |= MUSB_TXCSR_P_WZC_BITS;
+- csr &= ~(MUSB_TXCSR_P_UNDERRUN
+- | MUSB_TXCSR_TXPKTRDY);
++ csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
++ MUSB_TXCSR_TXPKTRDY);
+ musb_writew(epio, MUSB_TXCSR, csr);
+- DBG(20, "underrun on ep%d, req %p\n", epnum, request);
++ /* Ensure writebuffer is empty. */
++ csr = musb_readw(epio, MUSB_TXCSR);
++ request->actual += musb_ep->dma->actual_len;
++ DBG(4, "TXCSR%d %04x, DMA off, len %zu, req %p\n",
++ epnum, csr, musb_ep->dma->actual_len, request);
+ }
+
+- if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+- /* SHOULD NOT HAPPEN ... has with cppi though, after
+- * changing SENDSTALL (and other cases); harmless?
++ if (is_dma || request->actual == request->length) {
++ /*
++ * First, maybe a terminating short packet. Some DMA
++ * engines might handle this by themselves.
+ */
+- DBG(5, "%s dma still busy?\n", musb_ep->end_point.name);
+- break;
+- }
+-
+- if (request) {
+- u8 is_dma = 0;
++ if ((request->zero && request->length
++ && request->length % musb_ep->packet_sz == 0)
++#ifdef CONFIG_USB_INVENTRA_DMA
++ || (is_dma && (!dma->desired_mode ||
++ (request->actual &
++ (musb_ep->packet_sz - 1))))
++#endif
++ ) {
++ /*
++ * On DMA completion, FIFO may not be
++ * available yet...
++ */
++ if (csr & MUSB_TXCSR_TXPKTRDY)
++ return;
+
+- if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
+- is_dma = 1;
+- csr |= MUSB_TXCSR_P_WZC_BITS;
+- csr &= ~(MUSB_TXCSR_DMAENAB
+- | MUSB_TXCSR_P_UNDERRUN
++ DBG(4, "sending zero pkt\n");
++ musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
+ | MUSB_TXCSR_TXPKTRDY);
+- musb_writew(epio, MUSB_TXCSR, csr);
+- /* ensure writebuffer is empty */
+- csr = musb_readw(epio, MUSB_TXCSR);
+- request->actual += musb_ep->dma->actual_len;
+- DBG(4, "TXCSR%d %04x, dma off, "
+- "len %zu, req %p\n",
+- epnum, csr,
+- musb_ep->dma->actual_len,
+- request);
++ request->zero = 0;
+ }
+
+- if (is_dma || request->actual == request->length) {
+-
+- /* First, maybe a terminating short packet.
+- * Some DMA engines might handle this by
+- * themselves.
+- */
+- if ((request->zero
+- && request->length
+- && (request->length
+- % musb_ep->packet_sz)
+- == 0)
+-#ifdef CONFIG_USB_INVENTRA_DMA
+- || (is_dma &&
+- ((!dma->desired_mode) ||
+- (request->actual &
+- (musb_ep->packet_sz - 1))))
+-#endif
+- ) {
+- /* on dma completion, fifo may not
+- * be available yet ...
+- */
+- if (csr & MUSB_TXCSR_TXPKTRDY)
+- break;
+-
+- DBG(4, "sending zero pkt\n");
+- musb_writew(epio, MUSB_TXCSR,
+- MUSB_TXCSR_MODE
+- | MUSB_TXCSR_TXPKTRDY);
+- request->zero = 0;
+- }
+-
+- /* ... or if not, then complete it */
+- musb_g_giveback(musb_ep, request, 0);
++ /* ... or if not, then complete it. */
++ musb_g_giveback(musb_ep, request, 0);
+
+- /* kickstart next transfer if appropriate;
+- * the packet that just completed might not
+- * be transmitted for hours or days.
+- * REVISIT for double buffering...
+- * FIXME revisit for stalls too...
+- */
+- musb_ep_select(mbase, epnum);
+- csr = musb_readw(epio, MUSB_TXCSR);
+- if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+- break;
+- request = musb_ep->desc
+- ? next_request(musb_ep)
+- : NULL;
+- if (!request) {
+- DBG(4, "%s idle now\n",
+- musb_ep->end_point.name);
+- break;
+- }
+- }
++ /*
++ * Kickstart next transfer if appropriate;
++ * the packet that just completed might not
++ * be transmitted for hours or days.
++ * REVISIT for double buffering...
++ * FIXME revisit for stalls too...
++ */
++ musb_ep_select(mbase, epnum);
++ csr = musb_readw(epio, MUSB_TXCSR);
++ if (csr & MUSB_TXCSR_FIFONOTEMPTY)
++ return;
+
+- txstate(musb, to_musb_request(request));
++ if (!musb_ep->desc) {
++ DBG(4, "%s idle now\n",
++ musb_ep->end_point.name);
++ return;
++ } else
++ request = next_request(musb_ep);
+ }
+
+- } while (0);
++ txstate(musb, to_musb_request(request));
++ }
+ }
+
+ /* ------------------------------------------------------------ */
diff --git a/usb/usb-musb_gadget_ep0-fix-unhandled-endpoint-0-irqs-again.patch b/usb/usb-musb_gadget_ep0-fix-unhandled-endpoint-0-irqs-again.patch
new file mode 100644
index 00000000000000..c21c19ceecc158
--- /dev/null
+++ b/usb/usb-musb_gadget_ep0-fix-unhandled-endpoint-0-irqs-again.patch
@@ -0,0 +1,38 @@
+From gadiyar@ti.com Fri Nov 20 12:47:28 2009
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Date: Mon, 16 Nov 2009 16:24:05 +0530
+Subject: USB: musb_gadget_ep0: fix unhandled endpoint 0 IRQs, again
+To: "linux-usb@vger.kernel.org; Greg KH" <greg@kroah.com>
+Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1258368845-4913-1-git-send-email-gadiyar@ti.com>
+
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+
+Commit a5073b52833e4df8e16c93dc4cbb7e0c558c74a2 (musb_gadget: fix
+unhandled endpoint 0 IRQs) somehow missed its key change:
+
+"The gadget EP0 code routinely ignores an interrupt at end of
+the data phase because of musb_g_ep0_giveback() resetting the
+state machine to "idle, waiting for SETUP" phase prematurely."
+
+So, the majority of the cases of unhandled IRQs is still unfixed...
+
+Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_gadget_ep0.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/usb/musb/musb_gadget_ep0.c
++++ b/drivers/usb/musb/musb_gadget_ep0.c
+@@ -199,7 +199,6 @@ service_in_request(struct musb *musb, co
+ static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req)
+ {
+ musb_g_giveback(&musb->endpoints[0].ep_in, req, 0);
+- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+ }
+
+ /*
diff --git a/usb/usb-musb_gadget_ep0-stop-abusing-musb_gadget_set_halt.patch b/usb/usb-musb_gadget_ep0-stop-abusing-musb_gadget_set_halt.patch
new file mode 100644
index 00000000000000..012d23177bceb6
--- /dev/null
+++ b/usb/usb-musb_gadget_ep0-stop-abusing-musb_gadget_set_halt.patch
@@ -0,0 +1,141 @@
+From sshtylyov@ru.mvista.com Fri Nov 20 13:08:17 2009
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Date: Wed, 18 Nov 2009 22:54:32 +0300
+Subject: USB: musb_gadget_ep0: stop abusing musb_gadget_set_halt()
+To: gregkh@suse.de, <david-b@pacbell.net>
+Cc: linux-usb@vger.kernel.org, davinci-linux-open-source@linux.davincidsp.com
+Message-ID: <200911182254.32908.sshtylyov@ru.mvista.com>
+Content-Disposition: inline
+
+
+Stop playing with musb->lock and abusing musb_gadget_set_halt() in
+the code clearing the endpoint halt feature -- instead, manipulate
+the registers directly.
+
+While at it, get rid uf unneeded line breaks and over-indentation in
+the code setting the endpoint halt feature.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_gadget.h | 2 -
+ drivers/usb/musb/musb_gadget_ep0.c | 63 ++++++++++++++++++++++---------------
+ 2 files changed, 38 insertions(+), 27 deletions(-)
+
+--- a/drivers/usb/musb/musb_gadget_ep0.c
++++ b/drivers/usb/musb/musb_gadget_ep0.c
+@@ -257,19 +257,25 @@ __acquires(musb->lock)
+ case USB_RECIP_INTERFACE:
+ break;
+ case USB_RECIP_ENDPOINT:{
+- const u8 num = ctrlrequest->wIndex & 0x0f;
+- struct musb_ep *musb_ep;
++ const u8 epnum =
++ ctrlrequest->wIndex & 0x0f;
++ struct musb_ep *musb_ep;
++ struct musb_hw_ep *ep;
++ void __iomem *regs;
++ int is_in;
++ u16 csr;
+
+- if (num == 0
+- || num >= MUSB_C_NUM_EPS
+- || ctrlrequest->wValue
+- != USB_ENDPOINT_HALT)
++ if (epnum == 0 || epnum >= MUSB_C_NUM_EPS ||
++ ctrlrequest->wValue != USB_ENDPOINT_HALT)
+ break;
+
+- if (ctrlrequest->wIndex & USB_DIR_IN)
+- musb_ep = &musb->endpoints[num].ep_in;
++ ep = musb->endpoints + epnum;
++ regs = ep->regs;
++ is_in = ctrlrequest->wIndex & USB_DIR_IN;
++ if (is_in)
++ musb_ep = &ep->ep_in;
+ else
+- musb_ep = &musb->endpoints[num].ep_out;
++ musb_ep = &ep->ep_out;
+ if (!musb_ep->desc)
+ break;
+
+@@ -278,10 +284,23 @@ __acquires(musb->lock)
+ if (musb_ep->wedged)
+ break;
+
+- /* REVISIT do it directly, no locking games */
+- spin_unlock(&musb->lock);
+- musb_gadget_set_halt(&musb_ep->end_point, 0);
+- spin_lock(&musb->lock);
++ musb_ep_select(mbase, epnum);
++ if (is_in) {
++ csr = musb_readw(regs, MUSB_TXCSR);
++ csr |= MUSB_TXCSR_CLRDATATOG |
++ MUSB_TXCSR_P_WZC_BITS;
++ csr &= ~(MUSB_TXCSR_P_SENDSTALL |
++ MUSB_TXCSR_P_SENTSTALL |
++ MUSB_TXCSR_TXPKTRDY);
++ musb_writew(regs, MUSB_TXCSR, csr);
++ } else {
++ csr = musb_readw(regs, MUSB_RXCSR);
++ csr |= MUSB_RXCSR_CLRDATATOG |
++ MUSB_RXCSR_P_WZC_BITS;
++ csr &= ~(MUSB_RXCSR_P_SENDSTALL |
++ MUSB_RXCSR_P_SENTSTALL);
++ musb_writew(regs, MUSB_RXCSR, csr);
++ }
+
+ /* select ep0 again */
+ musb_ep_select(mbase, 0);
+@@ -377,10 +396,8 @@ stall:
+ int is_in;
+ u16 csr;
+
+- if (epnum == 0
+- || epnum >= MUSB_C_NUM_EPS
+- || ctrlrequest->wValue
+- != USB_ENDPOINT_HALT)
++ if (epnum == 0 || epnum >= MUSB_C_NUM_EPS ||
++ ctrlrequest->wValue != USB_ENDPOINT_HALT)
+ break;
+
+ ep = musb->endpoints + epnum;
+@@ -395,24 +412,20 @@ stall:
+
+ musb_ep_select(mbase, epnum);
+ if (is_in) {
+- csr = musb_readw(regs,
+- MUSB_TXCSR);
++ csr = musb_readw(regs, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ csr |= MUSB_TXCSR_P_SENDSTALL
+ | MUSB_TXCSR_CLRDATATOG
+ | MUSB_TXCSR_P_WZC_BITS;
+- musb_writew(regs, MUSB_TXCSR,
+- csr);
++ musb_writew(regs, MUSB_TXCSR, csr);
+ } else {
+- csr = musb_readw(regs,
+- MUSB_RXCSR);
++ csr = musb_readw(regs, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_P_SENDSTALL
+ | MUSB_RXCSR_FLUSHFIFO
+ | MUSB_RXCSR_CLRDATATOG
+ | MUSB_RXCSR_P_WZC_BITS;
+- musb_writew(regs, MUSB_RXCSR,
+- csr);
++ musb_writew(regs, MUSB_RXCSR, csr);
+ }
+
+ /* select ep0 again */
+--- a/drivers/usb/musb/musb_gadget.h
++++ b/drivers/usb/musb/musb_gadget.h
+@@ -105,6 +105,4 @@ extern void musb_gadget_cleanup(struct m
+
+ extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
+
+-extern int musb_gadget_set_halt(struct usb_ep *ep, int value);
+-
+ #endif /* __MUSB_GADGET_H */
diff --git a/usb/usb-r8a66597-clean-up.-remove-unneeded-null-checks.patch b/usb/usb-r8a66597-clean-up.-remove-unneeded-null-checks.patch
new file mode 100644
index 00000000000000..dfbef5d04085eb
--- /dev/null
+++ b/usb/usb-r8a66597-clean-up.-remove-unneeded-null-checks.patch
@@ -0,0 +1,45 @@
+From error27@gmail.com Fri Nov 20 11:54:00 2009
+From: Dan Carpenter <error27@gmail.com>
+Date: Tue, 10 Nov 2009 10:53:58 +0200 (SAST)
+Subject: USB: r8a66597: clean up. remove unneeded null checks
+To: shimoda.yoshihiro@renesas.com
+Cc: linux-usb@vger.kernel.org
+Message-ID: <alpine.DEB.2.00.0911082025580.12333@bicker>
+
+
+td and dev can not be null.
+
+Also they are dereferenced in list_for_each_entry_safe and list_for_each
+before the check happens so we would have an oops if it were possible
+for them to be null.
+
+Found using the smatch static checker.
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Acked-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/r8a66597-hcd.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/usb/host/r8a66597-hcd.c
++++ b/drivers/usb/host/r8a66597-hcd.c
+@@ -822,8 +822,6 @@ static void force_dequeue(struct r8a6659
+ return;
+
+ list_for_each_entry_safe(td, next, list, queue) {
+- if (!td)
+- continue;
+ if (td->address != address)
+ continue;
+
+@@ -2025,8 +2023,6 @@ static struct r8a66597_device *get_r8a66
+ struct list_head *list = &r8a66597->child_device;
+
+ list_for_each_entry(dev, list, device_list) {
+- if (!dev)
+- continue;
+ if (dev->usb_address != addr)
+ continue;
+
diff --git a/usb/usb-remove-the-auto_pm-flag.patch b/usb/usb-remove-the-auto_pm-flag.patch
new file mode 100644
index 00000000000000..61aa1da70b1964
--- /dev/null
+++ b/usb/usb-remove-the-auto_pm-flag.patch
@@ -0,0 +1,188 @@
+From stern@rowland.harvard.edu Fri Nov 20 11:52:44 2009
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 13 Nov 2009 11:53:59 -0500 (EST)
+Subject: USB: remove the auto_pm flag
+To: Greg KH <greg@kroah.com>
+Message-ID: <Pine.LNX.4.44L0.0911131151140.2654-100000@iolanthe.rowland.org>
+
+
+This patch (as1302) removes the auto_pm flag from struct usb_device.
+The flag's only purpose was to distinguish between autosuspends and
+external suspends, but that information is now available in the
+pm_message_t argument passed to suspend methods.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/usb/power-management.txt | 9 +++++----
+ drivers/bluetooth/btusb.c | 2 +-
+ drivers/hid/usbhid/hid-core.c | 8 ++++----
+ drivers/net/wimax/i2400m/usb.c | 4 ++--
+ drivers/usb/core/driver.c | 4 ----
+ drivers/usb/serial/option.c | 2 +-
+ drivers/usb/serial/sierra.c | 2 +-
+ include/linux/usb.h | 2 --
+ 8 files changed, 14 insertions(+), 19 deletions(-)
+
+--- a/Documentation/usb/power-management.txt
++++ b/Documentation/usb/power-management.txt
+@@ -423,15 +423,16 @@ an URB had completed too recently.
+
+ External suspend calls should never be allowed to fail in this way,
+ only autosuspend calls. The driver can tell them apart by checking
+-udev->auto_pm; this flag will be set to 1 for internal PM events
+-(autosuspend or autoresume) and 0 for external PM events.
++the PM_EVENT_AUTO bit in the message.event argument to the suspend
++method; this bit will be set for internal PM events (autosuspend) and
++clear for external PM events.
+
+ Many of the ingredients in the autosuspend framework are oriented
+ towards interfaces: The usb_interface structure contains the
+ pm_usage_cnt field, and the usb_autopm_* routines take an interface
+ pointer as their argument. But somewhat confusingly, a few of the
+-pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+-structure instead. Drivers need to keep this straight; they can call
++pieces (i.e., usb_mark_last_busy()) use the usb_device structure
++instead. Drivers need to keep this straight; they can call
+ interface_to_usbdev() to find the device structure for a given
+ interface.
+
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -1066,7 +1066,7 @@ static int btusb_suspend(struct usb_inte
+ return 0;
+
+ spin_lock_irq(&data->txlock);
+- if (!(interface_to_usbdev(intf)->auto_pm && data->tx_in_flight)) {
++ if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
+ set_bit(BTUSB_SUSPENDING, &data->flags);
+ spin_unlock_irq(&data->txlock);
+ } else {
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -1254,10 +1254,9 @@ static int hid_suspend(struct usb_interf
+ {
+ struct hid_device *hid = usb_get_intfdata(intf);
+ struct usbhid_device *usbhid = hid->driver_data;
+- struct usb_device *udev = interface_to_usbdev(intf);
+ int status;
+
+- if (udev->auto_pm) {
++ if (message.event & PM_EVENT_AUTO) {
+ spin_lock_irq(&usbhid->lock); /* Sync with error handler */
+ if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
+ && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
+@@ -1282,7 +1281,7 @@ static int hid_suspend(struct usb_interf
+ return -EIO;
+ }
+
+- if (!ignoreled && udev->auto_pm) {
++ if (!ignoreled && (message.event & PM_EVENT_AUTO)) {
+ spin_lock_irq(&usbhid->lock);
+ if (test_bit(HID_LED_ON, &usbhid->iofl)) {
+ spin_unlock_irq(&usbhid->lock);
+@@ -1295,7 +1294,8 @@ static int hid_suspend(struct usb_interf
+ hid_cancel_delayed_stuff(usbhid);
+ hid_cease_io(usbhid);
+
+- if (udev->auto_pm && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
++ if ((message.event & PM_EVENT_AUTO) &&
++ test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
+ /* lost race against keypresses */
+ status = hid_start_in(hid);
+ if (status < 0)
+--- a/drivers/net/wimax/i2400m/usb.c
++++ b/drivers/net/wimax/i2400m/usb.c
+@@ -498,7 +498,7 @@ void i2400mu_disconnect(struct usb_inter
+ *
+ * As well, the device might refuse going to sleep for whichever
+ * reason. In this case we just fail. For system suspend/hibernate,
+- * we *can't* fail. We look at usb_dev->auto_pm to see if the
++ * we *can't* fail. We check PM_EVENT_AUTO to see if the
+ * suspend call comes from the USB stack or from the system and act
+ * in consequence.
+ *
+@@ -517,7 +517,7 @@ int i2400mu_suspend(struct usb_interface
+ struct i2400m *i2400m = &i2400mu->i2400m;
+
+ #ifdef CONFIG_PM
+- if (usb_dev->auto_pm > 0)
++ if (pm_msg.event & PM_EVENT_AUTO)
+ is_autosuspend = 1;
+ #endif
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -1341,7 +1341,6 @@ static int usb_autopm_do_device(struct u
+ int status = 0;
+
+ usb_pm_lock(udev);
+- udev->auto_pm = 1;
+ udev->pm_usage_cnt += inc_usage_cnt;
+ WARN_ON(udev->pm_usage_cnt < 0);
+ if (inc_usage_cnt)
+@@ -1473,7 +1472,6 @@ static int usb_autopm_do_interface(struc
+ if (intf->condition == USB_INTERFACE_UNBOUND)
+ status = -ENODEV;
+ else {
+- udev->auto_pm = 1;
+ atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
+ udev->last_busy = jiffies;
+ if (inc_usage_cnt >= 0 &&
+@@ -1707,7 +1705,6 @@ int usb_external_suspend_device(struct u
+
+ do_unbind_rebind(udev, DO_UNBIND);
+ usb_pm_lock(udev);
+- udev->auto_pm = 0;
+ status = usb_suspend_both(udev, msg);
+ usb_pm_unlock(udev);
+ return status;
+@@ -1730,7 +1727,6 @@ int usb_external_resume_device(struct us
+ int status;
+
+ usb_pm_lock(udev);
+- udev->auto_pm = 0;
+ status = usb_resume_both(udev, msg);
+ udev->last_busy = jiffies;
+ usb_pm_unlock(udev);
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -1308,7 +1308,7 @@ static int option_suspend(struct usb_ser
+
+ dbg("%s entered", __func__);
+
+- if (serial->dev->auto_pm) {
++ if (message.event & PM_EVENT_AUTO) {
+ spin_lock_irq(&intfdata->susp_lock);
+ b = intfdata->in_flight;
+ spin_unlock_irq(&intfdata->susp_lock);
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -1005,7 +1005,7 @@ static int sierra_suspend(struct usb_ser
+ struct sierra_intf_private *intfdata;
+ int b;
+
+- if (serial->dev->auto_pm) {
++ if (message.event & PM_EVENT_AUTO) {
+ intfdata = serial->private;
+ spin_lock_irq(&intfdata->susp_lock);
+ b = intfdata->in_flight;
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -429,7 +429,6 @@ struct usb_tt;
+ * @last_busy: time of last use
+ * @autosuspend_delay: in jiffies
+ * @connect_time: time device was first connected
+- * @auto_pm: autosuspend/resume in progress
+ * @do_remote_wakeup: remote wakeup should be enabled
+ * @reset_resume: needs reset instead of resume
+ * @autosuspend_disabled: autosuspend disabled by the user
+@@ -514,7 +513,6 @@ struct usb_device {
+ int autosuspend_delay;
+ unsigned long connect_time;
+
+- unsigned auto_pm:1;
+ unsigned do_remote_wakeup:1;
+ unsigned reset_resume:1;
+ unsigned autosuspend_disabled:1;
diff --git a/usb/usb-twl4030-enable-usb-regulators-before-enabling-usb-charging.patch b/usb/usb-twl4030-enable-usb-regulators-before-enabling-usb-charging.patch
new file mode 100644
index 00000000000000..092f3ac78a6ba4
--- /dev/null
+++ b/usb/usb-twl4030-enable-usb-regulators-before-enabling-usb-charging.patch
@@ -0,0 +1,52 @@
+From leed.aguilar@ti.com Fri Nov 20 13:10:53 2009
+From: "Aguilar Pena, Leed" <leed.aguilar@ti.com>
+Date: Fri, 20 Nov 2009 11:32:53 -0600
+Subject: USB: twl4030: Enable USB regulators before enabling USB charging
+To: "linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>
+Cc: "dbrownell@users.sourceforge.net" <dbrownell@users.sourceforge.net>, "gregkh@suse.de" <gregkh@suse.de>
+Message-ID: <23D0CDE7C386D144A4F26EB0F427F8C074D70BE5@dlee04.ent.ti.com>
+
+
+For TWL family of power management ICs, USB charging works only
+when USB regulators are in enabled state: 3v1, 1v5, 1v8
+
+On a USB cable attach, twl4030_phy_resume(twl) function enables
+the regulators. Enable USB charging, only after all regulators
+are enabled.
+
+Its observed that enabling USB charging before regulators are
+enabled, causes USB charging to fail.
+
+Tested on: Zoom2: omap3430: ES3.1 + TWL5030
+Needs T2-MADC and T2-BCI drivers which are still not upstreamed.
+
+Signed-off-by: Moiz Sonasath <m-sonasath@ti.com>
+Signed-off-by: Leed Aguilar <leed.aguilar@ti.com>
+Acked-by: Vikram Pandita <vikram.pandita@ti.com>
+Acked-by: Anand Gadiyar <gadiyar@ti.com>
+Acked-by: Nishanth Menon <nm@ti.com>
+Acked-by: Felipe Balbi <felipe.balbi@nokia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/otg/twl4030-usb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/otg/twl4030-usb.c
++++ b/drivers/usb/otg/twl4030-usb.c
+@@ -598,12 +598,12 @@ static irqreturn_t twl4030_usb_irq(int i
+ * USB_LINK_VBUS state. musb_hdrc won't care until it
+ * starts to handle softconnect right.
+ */
+- twl4030charger_usb_en(status == USB_LINK_VBUS);
+-
+ if (status == USB_LINK_NONE)
+ twl4030_phy_suspend(twl, 0);
+ else
+ twl4030_phy_resume(twl);
++
++ twl4030charger_usb_en(status == USB_LINK_VBUS);
+ }
+ sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+
diff --git a/usb/usb-usbtmc-repeat-usb_bulk_msg-until-whole-message-is-transfered.patch b/usb/usb-usbtmc-repeat-usb_bulk_msg-until-whole-message-is-transfered.patch
new file mode 100644
index 00000000000000..00159221d7df71
--- /dev/null
+++ b/usb/usb-usbtmc-repeat-usb_bulk_msg-until-whole-message-is-transfered.patch
@@ -0,0 +1,49 @@
+From andre.herms@tec-venture.de Fri Nov 20 13:10:31 2009
+From: Andre Herms <andre.herms@tec-venture.de>
+Date: Thu, 19 Nov 2009 18:14:49 +0100
+Subject: USB: usbtmc: repeat usb_bulk_msg until whole message is transfered
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org
+Message-ID: <4B057D09.4060207@tec-venture.de>
+
+
+usb_bulk_msg() transfers only bytes up to the maximum packet size.
+It must be repeated by the usbtmc driver until all bytes of a TMC message
+are transfered.
+
+Without this patch, ETIMEDOUT is reported when writing TMC messages
+larger than the maximum USB bulk size and the transfer remains incomplete.
+The user will notice that the device hangs and must be reset by either closing
+the application or pulling the plug.
+
+Signed-off-by: Andre Herms <andre.herms@tec-venture.de>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/usbtmc.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/class/usbtmc.c
++++ b/drivers/usb/class/usbtmc.c
+@@ -562,10 +562,16 @@ static ssize_t usbtmc_write(struct file
+ n_bytes = roundup(12 + this_part, 4);
+ memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part));
+
+- retval = usb_bulk_msg(data->usb_dev,
+- usb_sndbulkpipe(data->usb_dev,
+- data->bulk_out),
+- buffer, n_bytes, &actual, USBTMC_TIMEOUT);
++ do {
++ retval = usb_bulk_msg(data->usb_dev,
++ usb_sndbulkpipe(data->usb_dev,
++ data->bulk_out),
++ buffer, n_bytes,
++ &actual, USBTMC_TIMEOUT);
++ if (retval != 0)
++ break;
++ n_bytes -= actual;
++ } while (n_bytes);
+
+ data->bTag_last_write = data->bTag;
+ data->bTag++;
diff --git a/usb/usb-xhci-add-tests-for-trb-address-translation.patch b/usb/usb-xhci-add-tests-for-trb-address-translation.patch
new file mode 100644
index 00000000000000..4aed87476671d3
--- /dev/null
+++ b/usb/usb-xhci-add-tests-for-trb-address-translation.patch
@@ -0,0 +1,227 @@
+From sarah.a.sharp@linux.intel.com Fri Nov 20 11:59:18 2009
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Mon, 9 Nov 2009 13:35:23 -0800
+Subject: USB: xhci: Add tests for TRB address translation.
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Message-ID: <20091109213523.GA2864@xanatos>
+Content-Disposition: inline
+
+
+It's not surprising that the transfer request buffer (TRB) physical to
+virtual address translation function has bugs in it, since I wrote most of
+it at 4am last October. Add a test suite to check the TRB math. This
+runs at memory initialization time, and causes the driver to fail to load
+if the TRB math fails.
+
+Please excuse the excessively long lines in the test vectors; they can't
+really be made shorter and still be readable.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-mem.c | 159 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci-ring.c | 3
+ drivers/usb/host/xhci.h | 3
+ 3 files changed, 163 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1268,6 +1268,9 @@ void xhci_reset_bandwidth(struct usb_hcd
+
+ /* xHCI ring, segment, TRB, and TD functions */
+ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
++struct xhci_segment *trb_in_td(struct xhci_segment *start_seg,
++ union xhci_trb *start_trb, union xhci_trb *end_trb,
++ dma_addr_t suspect_dma);
+ void xhci_ring_cmd_db(struct xhci_hcd *xhci);
+ void *xhci_setup_one_noop(struct xhci_hcd *xhci);
+ void xhci_handle_event(struct xhci_hcd *xhci);
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -859,6 +859,163 @@ void xhci_mem_cleanup(struct xhci_hcd *x
+ xhci->page_shift = 0;
+ }
+
++static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
++ struct xhci_segment *input_seg,
++ union xhci_trb *start_trb,
++ union xhci_trb *end_trb,
++ dma_addr_t input_dma,
++ struct xhci_segment *result_seg,
++ char *test_name, int test_number)
++{
++ unsigned long long start_dma;
++ unsigned long long end_dma;
++ struct xhci_segment *seg;
++
++ start_dma = xhci_trb_virt_to_dma(input_seg, start_trb);
++ end_dma = xhci_trb_virt_to_dma(input_seg, end_trb);
++
++ seg = trb_in_td(input_seg, start_trb, end_trb, input_dma);
++ if (seg != result_seg) {
++ xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n",
++ test_name, test_number);
++ xhci_warn(xhci, "Tested TRB math w/ seg %p and "
++ "input DMA 0x%llx\n",
++ input_seg,
++ (unsigned long long) input_dma);
++ xhci_warn(xhci, "starting TRB %p (0x%llx DMA), "
++ "ending TRB %p (0x%llx DMA)\n",
++ start_trb, start_dma,
++ end_trb, end_dma);
++ xhci_warn(xhci, "Expected seg %p, got seg %p\n",
++ result_seg, seg);
++ return -1;
++ }
++ return 0;
++}
++
++/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
++static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags)
++{
++ struct {
++ dma_addr_t input_dma;
++ struct xhci_segment *result_seg;
++ } simple_test_vector [] = {
++ /* A zeroed DMA field should fail */
++ { 0, NULL },
++ /* One TRB before the ring start should fail */
++ { xhci->event_ring->first_seg->dma - 16, NULL },
++ /* One byte before the ring start should fail */
++ { xhci->event_ring->first_seg->dma - 1, NULL },
++ /* Starting TRB should succeed */
++ { xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg },
++ /* Ending TRB should succeed */
++ { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16,
++ xhci->event_ring->first_seg },
++ /* One byte after the ring end should fail */
++ { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL },
++ /* One TRB after the ring end should fail */
++ { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL },
++ /* An address of all ones should fail */
++ { (dma_addr_t) (~0), NULL },
++ };
++ struct {
++ struct xhci_segment *input_seg;
++ union xhci_trb *start_trb;
++ union xhci_trb *end_trb;
++ dma_addr_t input_dma;
++ struct xhci_segment *result_seg;
++ } complex_test_vector [] = {
++ /* Test feeding a valid DMA address from a different ring */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = xhci->event_ring->first_seg->trbs,
++ .end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
++ .input_dma = xhci->cmd_ring->first_seg->dma,
++ .result_seg = NULL,
++ },
++ /* Test feeding a valid end TRB from a different ring */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = xhci->event_ring->first_seg->trbs,
++ .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
++ .input_dma = xhci->cmd_ring->first_seg->dma,
++ .result_seg = NULL,
++ },
++ /* Test feeding a valid start and end TRB from a different ring */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = xhci->cmd_ring->first_seg->trbs,
++ .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
++ .input_dma = xhci->cmd_ring->first_seg->dma,
++ .result_seg = NULL,
++ },
++ /* TRB in this ring, but after this TD */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = &xhci->event_ring->first_seg->trbs[0],
++ .end_trb = &xhci->event_ring->first_seg->trbs[3],
++ .input_dma = xhci->event_ring->first_seg->dma + 4*16,
++ .result_seg = NULL,
++ },
++ /* TRB in this ring, but before this TD */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = &xhci->event_ring->first_seg->trbs[3],
++ .end_trb = &xhci->event_ring->first_seg->trbs[6],
++ .input_dma = xhci->event_ring->first_seg->dma + 2*16,
++ .result_seg = NULL,
++ },
++ /* TRB in this ring, but after this wrapped TD */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
++ .end_trb = &xhci->event_ring->first_seg->trbs[1],
++ .input_dma = xhci->event_ring->first_seg->dma + 2*16,
++ .result_seg = NULL,
++ },
++ /* TRB in this ring, but before this wrapped TD */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
++ .end_trb = &xhci->event_ring->first_seg->trbs[1],
++ .input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16,
++ .result_seg = NULL,
++ },
++ /* TRB not in this ring, and we have a wrapped TD */
++ { .input_seg = xhci->event_ring->first_seg,
++ .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
++ .end_trb = &xhci->event_ring->first_seg->trbs[1],
++ .input_dma = xhci->cmd_ring->first_seg->dma + 2*16,
++ .result_seg = NULL,
++ },
++ };
++
++ unsigned int num_tests;
++ int i, ret;
++
++ num_tests = sizeof(simple_test_vector) / sizeof(simple_test_vector[0]);
++ for (i = 0; i < num_tests; i++) {
++ ret = xhci_test_trb_in_td(xhci,
++ xhci->event_ring->first_seg,
++ xhci->event_ring->first_seg->trbs,
++ &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
++ simple_test_vector[i].input_dma,
++ simple_test_vector[i].result_seg,
++ "Simple", i);
++ if (ret < 0)
++ return ret;
++ }
++
++ num_tests = sizeof(complex_test_vector) / sizeof(complex_test_vector[0]);
++ for (i = 0; i < num_tests; i++) {
++ ret = xhci_test_trb_in_td(xhci,
++ complex_test_vector[i].input_seg,
++ complex_test_vector[i].start_trb,
++ complex_test_vector[i].end_trb,
++ complex_test_vector[i].input_dma,
++ complex_test_vector[i].result_seg,
++ "Complex", i);
++ if (ret < 0)
++ return ret;
++ }
++ xhci_dbg(xhci, "TRB math tests passed.\n");
++ return 0;
++}
++
++
+ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ {
+ dma_addr_t dma;
+@@ -962,6 +1119,8 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+ xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags);
+ if (!xhci->event_ring)
+ goto fail;
++ if (xhci_check_trb_in_td_math(xhci, flags) < 0)
++ goto fail;
+
+ xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev),
+ sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma);
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -987,8 +987,7 @@ static void handle_port_status(struct xh
+ * TRB in this TD, this function returns that TRB's segment. Otherwise it
+ * returns 0.
+ */
+-static struct xhci_segment *trb_in_td(
+- struct xhci_segment *start_seg,
++struct xhci_segment *trb_in_td(struct xhci_segment *start_seg,
+ union xhci_trb *start_trb,
+ union xhci_trb *end_trb,
+ dma_addr_t suspect_dma)
diff --git a/usb/usb-xhci-handle-errors-that-cause-endpoint-halts.patch b/usb/usb-xhci-handle-errors-that-cause-endpoint-halts.patch
new file mode 100644
index 00000000000000..e6e8b420df3aec
--- /dev/null
+++ b/usb/usb-xhci-handle-errors-that-cause-endpoint-halts.patch
@@ -0,0 +1,150 @@
+From sarah.a.sharp@linux.intel.com Fri Nov 20 12:34:57 2009
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 11 Nov 2009 10:28:44 -0800
+Subject: USB: xhci: Handle errors that cause endpoint halts.
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Message-ID: <20091111182844.GA4519@xanatos>
+Content-Disposition: inline
+
+
+The xHCI 0.95 and 0.96 specification defines several transfer buffer
+request completion codes that indicate a USB transaction error occurred.
+When a stall, babble, transaction, or split transaction error completion code
+is set, the xHCI has halted that endpoint ring. Software must issue a
+Reset Endpoint command and a Set Transfer Ring Dequeue Pointer command
+to clean up the halted ring.
+
+The USB device driver is supposed to call into usb_reset_endpoint() when
+an endpoint stalls. That calls into the xHCI driver to issue the proper
+commands. However, drivers don't call that function for the other
+errors that cause the xHC to halt the endpoint ring. If a babble,
+transaction, or split transaction error occurs, check if the endpoint
+context reports a halted condition, and clean up the endpoint ring if it
+does.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 79 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 60 insertions(+), 19 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1037,6 +1037,45 @@ struct xhci_segment *trb_in_td(struct xh
+ return 0;
+ }
+
++static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
++ unsigned int slot_id, unsigned int ep_index,
++ struct xhci_td *td, union xhci_trb *event_trb)
++{
++ struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
++ ep->ep_state |= EP_HALTED;
++ ep->stopped_td = td;
++ ep->stopped_trb = event_trb;
++ xhci_queue_reset_ep(xhci, slot_id, ep_index);
++ xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
++ xhci_ring_cmd_db(xhci);
++}
++
++/* Check if an error has halted the endpoint ring. The class driver will
++ * cleanup the halt for a non-default control endpoint if we indicate a stall.
++ * However, a babble and other errors also halt the endpoint ring, and the class
++ * driver won't clear the halt in that case, so we need to issue a Set Transfer
++ * Ring Dequeue Pointer command manually.
++ */
++static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
++ struct xhci_ep_ctx *ep_ctx,
++ unsigned int trb_comp_code)
++{
++ /* TRB completion codes that may require a manual halt cleanup */
++ if (trb_comp_code == COMP_TX_ERR ||
++ trb_comp_code == COMP_BABBLE ||
++ trb_comp_code == COMP_SPLIT_ERR)
++ /* The 0.96 spec says a babbling control endpoint
++ * is not halted. The 0.96 spec says it is. Some HW
++ * claims to be 0.95 compliant, but it halts the control
++ * endpoint anyway. Check if a babble halted the
++ * endpoint.
++ */
++ if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_HALTED)
++ return 1;
++
++ return 0;
++}
++
+ /*
+ * If this function returns an error condition, it means it got a Transfer
+ * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
+@@ -1191,15 +1230,14 @@ static int handle_tx_event(struct xhci_h
+ else
+ status = 0;
+ break;
+- case COMP_BABBLE:
+- /* The 0.96 spec says a babbling control endpoint
+- * is not halted. The 0.96 spec says it is. Some HW
+- * claims to be 0.95 compliant, but it halts the control
+- * endpoint anyway. Check if a babble halted the
+- * endpoint.
+- */
+- if (ep_ctx->ep_info != EP_STATE_HALTED)
++
++ default:
++ if (!xhci_requires_manual_halt_cleanup(xhci,
++ ep_ctx, trb_comp_code))
+ break;
++ xhci_dbg(xhci, "TRB error code %u, "
++ "halted endpoint index = %u\n",
++ trb_comp_code, ep_index);
+ /* else fall through */
+ case COMP_STALL:
+ /* Did we transfer part of the data (middle) phase? */
+@@ -1211,15 +1249,9 @@ static int handle_tx_event(struct xhci_h
+ else
+ td->urb->actual_length = 0;
+
+- ep->stopped_td = td;
+- ep->stopped_trb = event_trb;
+- xhci_queue_reset_ep(xhci, slot_id, ep_index);
+- xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
+- xhci_ring_cmd_db(xhci);
++ xhci_cleanup_halted_endpoint(xhci,
++ slot_id, ep_index, td, event_trb);
+ goto td_cleanup;
+- default:
+- /* Others already handled above */
+- break;
+ }
+ /*
+ * Did we transfer any data, despite the errors that might have
+@@ -1357,16 +1389,25 @@ static int handle_tx_event(struct xhci_h
+ ep->stopped_td = td;
+ ep->stopped_trb = event_trb;
+ } else {
+- if (trb_comp_code == COMP_STALL ||
+- trb_comp_code == COMP_BABBLE) {
++ if (trb_comp_code == COMP_STALL) {
+ /* The transfer is completed from the driver's
+ * perspective, but we need to issue a set dequeue
+ * command for this stalled endpoint to move the dequeue
+ * pointer past the TD. We can't do that here because
+- * the halt condition must be cleared first.
++ * the halt condition must be cleared first. Let the
++ * USB class driver clear the stall later.
+ */
+ ep->stopped_td = td;
+ ep->stopped_trb = event_trb;
++ } else if (xhci_requires_manual_halt_cleanup(xhci,
++ ep_ctx, trb_comp_code)) {
++ /* Other types of errors halt the endpoint, but the
++ * class driver doesn't call usb_reset_endpoint() unless
++ * the error is -EPIPE. Clear the halted status in the
++ * xHCI hardware manually.
++ */
++ xhci_cleanup_halted_endpoint(xhci,
++ slot_id, ep_index, td, event_trb);
+ } else {
+ /* Update ring dequeue pointer */
+ while (ep_ring->dequeue != td->last_trb)
diff --git a/usb/usb-xhci-return-eproto-on-a-split-transaction-error.patch b/usb/usb-xhci-return-eproto-on-a-split-transaction-error.patch
new file mode 100644
index 00000000000000..f6f99ad1a9a818
--- /dev/null
+++ b/usb/usb-xhci-return-eproto-on-a-split-transaction-error.patch
@@ -0,0 +1,30 @@
+From sarah.a.sharp@linux.intel.com Fri Nov 20 12:33:23 2009
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 11 Nov 2009 10:28:36 -0800
+Subject: USB: xhci: Return -EPROTO on a split transaction error.
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Message-ID: <20091111182836.GA4439@xanatos>
+Content-Disposition: inline
+
+
+When the xHCI hardware says a transfer completed with a split
+transaction error, set the URB status to -EPROTO.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1139,6 +1139,7 @@ static int handle_tx_event(struct xhci_h
+ xhci_warn(xhci, "WARN: TRB error on endpoint\n");
+ status = -EILSEQ;
+ break;
++ case COMP_SPLIT_ERR:
+ case COMP_TX_ERR:
+ xhci_warn(xhci, "WARN: transfer error on endpoint\n");
+ status = -EPROTO;
diff --git a/usb/usb-xhci-return-success-for-vendor-specific-info-codes.patch b/usb/usb-xhci-return-success-for-vendor-specific-info-codes.patch
new file mode 100644
index 00000000000000..179ca6d90bcf64
--- /dev/null
+++ b/usb/usb-xhci-return-success-for-vendor-specific-info-codes.patch
@@ -0,0 +1,40 @@
+From sarah.a.sharp@linux.intel.com Fri Nov 20 12:34:43 2009
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 11 Nov 2009 10:28:40 -0800
+Subject: USB: xhci: Return success for vendor-specific info codes.
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Message-ID: <20091111182840.GA4479@xanatos>
+Content-Disposition: inline
+
+
+An xHCI host controller manufacturer can choose to implement several
+vendor-specific informational completion codes. These are all to be
+treated like a successful transfer completion.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1153,6 +1153,16 @@ static int handle_tx_event(struct xhci_h
+ status = -ENOSR;
+ break;
+ default:
++ if (trb_comp_code >= 224 && trb_comp_code <= 255) {
++ /* Vendor defined "informational" completion code,
++ * treat as not-an-error.
++ */
++ xhci_dbg(xhci, "Vendor defined info completion code %u\n",
++ trb_comp_code);
++ xhci_dbg(xhci, "Treating code as success.\n");
++ status = 0;
++ break;
++ }
+ xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
+ urb = NULL;
+ goto cleanup;
diff --git a/usb/usb-xhci-set-transfer-descriptor-size-field-correctly.patch b/usb/usb-xhci-set-transfer-descriptor-size-field-correctly.patch
new file mode 100644
index 00000000000000..b0d41eccf8c36a
--- /dev/null
+++ b/usb/usb-xhci-set-transfer-descriptor-size-field-correctly.patch
@@ -0,0 +1,120 @@
+From sarah.a.sharp@linux.intel.com Fri Nov 20 12:33:07 2009
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 11 Nov 2009 10:28:30 -0800
+Subject: USB: xhci: Set transfer descriptor size field correctly.
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Message-ID: <20091111182830.GA4399@xanatos>
+Content-Disposition: inline
+
+
+The transfer descriptor (TD) is a series of transfer request buffers
+(TRBs) that describe the buffer pointer, length, and other
+characteristics. The xHCI controllers want to know an estimate of how
+long the TD is, for caching reasons. In each TRB, there is a "TD size"
+field that provides a rough estimate of the remaining buffers to be
+transmitted, including the buffer pointed to by that TRB.
+
+The TD size is 5 bits long, and contains the remaining size in bytes,
+right shifted by 10 bits. So a remaining TD size less than 1024 would get
+a zero in the TD size field, and a remaining size greater than 32767 would
+get 31 in the field.
+
+This patches fixes a bug in the TD_REMAINDER macro that is triggered when
+the URB has a scatter gather list with a size bigger than 32767 bytes.
+Not all host controllers pay attention to the TD size field, so the bug
+will not appear on all USB 3.0 hosts.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 27 ++++++++++++++++++++++++---
+ drivers/usb/host/xhci.h | 3 ---
+ 2 files changed, 24 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -828,9 +828,6 @@ struct xhci_event_cmd {
+ /* Normal TRB fields */
+ /* transfer_len bitmasks - bits 0:16 */
+ #define TRB_LEN(p) ((p) & 0x1ffff)
+-/* TD size - number of bytes remaining in the TD (including this TRB):
+- * bits 17 - 21. Shift the number of bytes by 10. */
+-#define TD_REMAINDER(p) ((((p) >> 10) & 0x1f) << 17)
+ /* Interrupter Target - which MSI-X vector to target the completion event at */
+ #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
+ #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1699,6 +1699,21 @@ int xhci_queue_intr_tx(struct xhci_hcd *
+ return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
+ }
+
++/*
++ * The TD size is the number of bytes remaining in the TD (including this TRB),
++ * right shifted by 10.
++ * It must fit in bits 21:17, so it can't be bigger than 31.
++ */
++static u32 xhci_td_remainder(unsigned int remainder)
++{
++ u32 max = (1 << (21 - 17 + 1)) - 1;
++
++ if ((remainder >> 10) >= max)
++ return max << 17;
++ else
++ return (remainder >> 10) << 17;
++}
++
+ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+ struct urb *urb, int slot_id, unsigned int ep_index)
+ {
+@@ -1756,6 +1771,7 @@ static int queue_bulk_sg_tx(struct xhci_
+ do {
+ u32 field = 0;
+ u32 length_field = 0;
++ u32 remainder = 0;
+
+ /* Don't change the cycle bit of the first TRB until later */
+ if (first_trb)
+@@ -1785,8 +1801,10 @@ static int queue_bulk_sg_tx(struct xhci_
+ (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
+ (unsigned int) addr + trb_buff_len);
+ }
++ remainder = xhci_td_remainder(urb->transfer_buffer_length -
++ running_total) ;
+ length_field = TRB_LEN(trb_buff_len) |
+- TD_REMAINDER(urb->transfer_buffer_length - running_total) |
++ remainder |
+ TRB_INTR_TARGET(0);
+ queue_trb(xhci, ep_ring, false,
+ lower_32_bits(addr),
+@@ -1899,6 +1917,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
+
+ /* Queue the first TRB, even if it's zero-length */
+ do {
++ u32 remainder = 0;
+ field = 0;
+
+ /* Don't change the cycle bit of the first TRB until later */
+@@ -1917,8 +1936,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
+ td->last_trb = ep_ring->enqueue;
+ field |= TRB_IOC;
+ }
++ remainder = xhci_td_remainder(urb->transfer_buffer_length -
++ running_total);
+ length_field = TRB_LEN(trb_buff_len) |
+- TD_REMAINDER(urb->transfer_buffer_length - running_total) |
++ remainder |
+ TRB_INTR_TARGET(0);
+ queue_trb(xhci, ep_ring, false,
+ lower_32_bits(addr),
+@@ -2006,7 +2027,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
+ /* If there's data, queue data TRBs */
+ field = 0;
+ length_field = TRB_LEN(urb->transfer_buffer_length) |
+- TD_REMAINDER(urb->transfer_buffer_length) |
++ xhci_td_remainder(urb->transfer_buffer_length) |
+ TRB_INTR_TARGET(0);
+ if (urb->transfer_buffer_length > 0) {
+ if (setup->bRequestType & USB_DIR_IN)
diff --git a/usb/usbtest-make-module-param-pattern-writeable.patch b/usb/usbtest-make-module-param-pattern-writeable.patch
new file mode 100644
index 00000000000000..bc99d4b26e6d27
--- /dev/null
+++ b/usb/usbtest-make-module-param-pattern-writeable.patch
@@ -0,0 +1,44 @@
+From vikram.pandita@ti.com Fri Nov 20 11:56:34 2009
+From: Vikram Pandita <vikram.pandita@ti.com>
+Date: Mon, 9 Nov 2009 21:24:32 -0600
+Subject: usbtest: make module param pattern writeable
+To: linux-usb@vger.kernel.org, <dbrownell@users.sourceforge.net>
+Cc: linux-omap@vger.kernel.org, Vikram Pandita <vikram.pandita@ti.com>, Anand Gadiyar <gadiyar@ti.com>
+Message-ID: <1257823472-19369-1-git-send-email-vikram.pandita@ti.com>
+
+
+Allow module_param to be writeable. This allows us to change
+the parameter if usbtest is built-in in the kernel.
+
+Signed-off-by: Vikram Pandita <vikram.pandita@ti.com>
+Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
+Cc: David Brownell <david-b@pacbell.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/usbtest.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/misc/usbtest.c
++++ b/drivers/usb/misc/usbtest.c
+@@ -213,8 +213,9 @@ static struct urb *simple_alloc_urb (
+ }
+
+ static unsigned pattern = 0;
+-module_param (pattern, uint, S_IRUGO);
+-MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)");
++static unsigned mod_pattern = 0;
++module_param_named(pattern, mod_pattern, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(mod_pattern, "i/o pattern (0 == zeroes)");
+
+ static inline void simple_fill_buf (struct urb *urb)
+ {
+@@ -1567,6 +1568,8 @@ usbtest_ioctl (struct usb_interface *int
+
+ // FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is.
+
++ pattern = mod_pattern;
++
+ if (code != USBTEST_REQUEST)
+ return -EOPNOTSUPP;
+