aboutsummaryrefslogtreecommitdiffstats
path: root/usb.current
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2010-06-25 11:28:30 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-25 11:28:30 -0700
commitc23087dad116bf3266e64605046361d985e7f493 (patch)
treeac685016c567fbe4c13a74d11413379554ee27f7 /usb.current
parente1e6cbaa48b0a9cc53d33cf1a9b5ffd9166bcc6f (diff)
downloadpatches-c23087dad116bf3266e64605046361d985e7f493.tar.gz
usb and staging and a firmware patch
Diffstat (limited to 'usb.current')
-rw-r--r--usb.current/usb-gadget-f_mass_storage-fixed-fs-descriptors-not-being-updated.patch106
-rw-r--r--usb.current/usb-gadget-f_mass_storage-stale-common-fsg-value-bug-fix.patch326
2 files changed, 432 insertions, 0 deletions
diff --git a/usb.current/usb-gadget-f_mass_storage-fixed-fs-descriptors-not-being-updated.patch b/usb.current/usb-gadget-f_mass_storage-fixed-fs-descriptors-not-being-updated.patch
new file mode 100644
index 00000000000000..053d59cd4fc6d1
--- /dev/null
+++ b/usb.current/usb-gadget-f_mass_storage-fixed-fs-descriptors-not-being-updated.patch
@@ -0,0 +1,106 @@
+From m.nazarewicz@samsung.com Fri Jun 25 11:23:02 2010
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Fri, 25 Jun 2010 16:29:26 +0200
+Subject: USB: gadget: f_mass_storage: fixed fs descriptors not being updated
+To: linux-usb@vger.kernel.org
+Cc: David Brownell <dbrownell@users.sourceforge.net>, Greg KH <greg@kroah.com>, Kyungmin Park <kyungmin.park@samsung.com>, Marek Szyprowski <m.szyprowski@samsung.com>, linux-kernel@vger.kernel.org, Dries Van Puymbroeck <Dries.VanPuymbroeck@dekimo.com>
+Message-ID: <195465048ef0e96371d42a9bc754a2f35a03bccd.1277461024.git.m.nazarewicz@samsung.com>
+
+
+The full speed descriptors were copied to the usb_function structure
+in the fsg_bind_config function before call to the usb_ep_autoconfig.
+The usb_ep_autoconfig was called in fsg_bind using the original
+descriptors. In effect copied descriptors were not updated.
+
+This patch changes the copy full speed descriptors after the call to
+usb_op_autoconfig is performed. This way, copied full speed
+descriptors have updated values.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Cc: Kyungmin Park <kyungmin.park@samsung.com>
+Reported-by: Dries Van Puymbroeck <Dries.VanPuymbroeck@dekimo.com>
+Tested-by: Dries Van Puymbroeck <Dries.VanPuymbroeck@dekimo.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_mass_storage.c | 34 ++++++++++++----------------------
+ 1 file changed, 12 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -2970,7 +2970,6 @@ static int fsg_bind(struct usb_configura
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+- int rc;
+ int i;
+ struct usb_ep *ep;
+
+@@ -2996,6 +2995,11 @@ static int fsg_bind(struct usb_configura
+ ep->driver_data = fsg->common; /* claim the endpoint */
+ fsg->bulk_out = ep;
+
++ /* Copy descriptors */
++ f->descriptors = usb_copy_descriptors(fsg_fs_function);
++ if (unlikely(!f->descriptors))
++ return -ENOMEM;
++
+ if (gadget_is_dualspeed(gadget)) {
+ /* Assume endpoint addresses are the same for both speeds */
+ fsg_hs_bulk_in_desc.bEndpointAddress =
+@@ -3003,16 +3007,17 @@ static int fsg_bind(struct usb_configura
+ fsg_hs_bulk_out_desc.bEndpointAddress =
+ fsg_fs_bulk_out_desc.bEndpointAddress;
+ f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
+- if (unlikely(!f->hs_descriptors))
++ if (unlikely(!f->hs_descriptors)) {
++ usb_free_descriptors(f->descriptors);
+ return -ENOMEM;
++ }
+ }
+
+ return 0;
+
+ autoconf_fail:
+ ERROR(fsg, "unable to autoconfigure all endpoints\n");
+- rc = -ENOTSUPP;
+- return rc;
++ return -ENOTSUPP;
+ }
+
+
+@@ -3036,11 +3041,6 @@ static int fsg_add(struct usb_composite_
+
+ fsg->function.name = FSG_DRIVER_DESC;
+ fsg->function.strings = fsg_strings_array;
+- fsg->function.descriptors = usb_copy_descriptors(fsg_fs_function);
+- if (unlikely(!fsg->function.descriptors)) {
+- rc = -ENOMEM;
+- goto error_free_fsg;
+- }
+ fsg->function.bind = fsg_bind;
+ fsg->function.unbind = fsg_unbind;
+ fsg->function.setup = fsg_setup;
+@@ -3056,19 +3056,9 @@ static int fsg_add(struct usb_composite_
+
+ rc = usb_add_function(c, &fsg->function);
+ if (unlikely(rc))
+- goto error_free_all;
+-
+- fsg_common_get(fsg->common);
+- return 0;
+-
+-error_free_all:
+- usb_free_descriptors(fsg->function.descriptors);
+- /* fsg_bind() might have copied those; or maybe not? who cares
+- * -- free it just in case. */
+- usb_free_descriptors(fsg->function.hs_descriptors);
+-error_free_fsg:
+- kfree(fsg);
+-
++ kfree(fsg);
++ else
++ fsg_common_get(fsg->common);
+ return rc;
+ }
+
diff --git a/usb.current/usb-gadget-f_mass_storage-stale-common-fsg-value-bug-fix.patch b/usb.current/usb-gadget-f_mass_storage-stale-common-fsg-value-bug-fix.patch
new file mode 100644
index 00000000000000..2e2d400d9aaca8
--- /dev/null
+++ b/usb.current/usb-gadget-f_mass_storage-stale-common-fsg-value-bug-fix.patch
@@ -0,0 +1,326 @@
+From m.nazarewicz@samsung.com Fri Jun 25 11:23:22 2010
+From: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Date: Fri, 25 Jun 2010 16:29:28 +0200
+Subject: USB: gadget: f_mass_storage: stale common->fsg value bug fix
+To: linux-usb@vger.kernel.org
+Cc: David Brownell <dbrownell@users.sourceforge.net>, Greg KH <greg@kroah.com>, Kyungmin Park <kyungmin.park@samsung.com>, Marek Szyprowski <m.szyprowski@samsung.com>, linux-kernel@vger.kernel.org
+Message-ID: <023d27cf18cf64018bb96f0913b0e61bade38c39.1277475111.git.m.nazarewicz@samsung.com>
+
+
+On fsg_unbind the common->fsg pointer was not NULLed if the
+unbound fsg_dev instance was the current one. As an effect,
+the incorrect pointer was preserved in all further operations
+which caused do_set_interface to reference an invalid region.
+
+This commit fixes this by raising an exception in fsg_bind
+which will change the common->fsg pointer. This also requires
+an wait queue so that the thread in fsg_bind can wait till the
+worker thread handles the exception.
+
+This commit removes also a config and new_config fields of
+fsg_common as they are no longer needed since fsg can be
+used to determine whether function is active or not.
+
+Moreover, this commit removes possible race condition where
+the fsg field was modified in both the worker thread and
+form various other contexts. This is fixed by replacing
+prev_fsg with new_fsg. At this point, fsg is assigned only
+in worker thread.
+
+Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
+Cc: Kyungmin Park <kyungmin.park@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_mass_storage.c | 162 +++++++++++++-----------------------
+ 1 file changed, 62 insertions(+), 100 deletions(-)
+
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -321,8 +321,8 @@ 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;
++ struct fsg_dev *fsg, *new_fsg;
++ wait_queue_head_t fsg_wait;
+
+ /* filesem protects: backing files in use */
+ struct rw_semaphore filesem;
+@@ -351,7 +351,6 @@ struct fsg_common {
+ 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;
+@@ -595,7 +594,7 @@ static int fsg_setup(struct usb_function
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+- if (!fsg->common->config)
++ if (!fsg_is_set(fsg->common))
+ return -EOPNOTSUPP;
+
+ switch (ctrl->bRequest) {
+@@ -2303,24 +2302,20 @@ static int alloc_request(struct fsg_comm
+ return -ENOMEM;
+ }
+
+-/*
+- * Reset interface setting and re-init endpoint state (toggle etc).
+- * 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_common *common, int altsetting)
++/* Reset interface setting and re-init endpoint state (toggle etc). */
++static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
+ {
+- int rc = 0;
+- int i;
+- const struct usb_endpoint_descriptor *d;
++ const struct usb_endpoint_descriptor *d;
++ struct fsg_dev *fsg;
++ int i, rc = 0;
+
+ if (common->running)
+ DBG(common, "reset interface\n");
+
+ reset:
+ /* Deallocate the requests */
+- if (common->prev_fsg) {
+- struct fsg_dev *fsg = common->prev_fsg;
++ if (common->fsg) {
++ fsg = common->fsg;
+
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &common->buffhds[i];
+@@ -2345,88 +2340,53 @@ reset:
+ fsg->bulk_out_enabled = 0;
+ }
+
+- common->prev_fsg = 0;
++ common->fsg = NULL;
++ wake_up(&common->fsg_wait);
+ }
+
+ common->running = 0;
+- if (altsetting < 0 || rc != 0)
++ if (!new_fsg || rc)
+ return rc;
+
+- DBG(common, "set interface %d\n", altsetting);
++ common->fsg = new_fsg;
++ 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;
++ 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;
++ fsg->bulk_out_enabled = 1;
++ common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
++ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
++
++ /* Allocate the requests */
++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
++ struct fsg_buffhd *bh = &common->buffhds[i];
+
+- 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);
++ rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
+ if (rc)
+ goto reset;
+- 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);
++ rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
+ if (rc)
+ goto reset;
+- fsg->bulk_out_enabled = 1;
+- common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+- clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+-
+- /* 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;
++ 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;
+ }
+-}
+-
+-
+-/*
+- * Change our operational configuration. This code must agree with the code
+- * that returns config descriptors, and with interface altsetting code.
+- *
+- * It's also responsible for power management interactions. Some
+- * 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_common *common, u8 new_config)
+-{
+- int rc = 0;
+
+- /* Disable the single interface */
+- 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) {
+- common->config = new_config;
+- rc = do_set_interface(common, 0);
+- if (rc != 0)
+- common->config = 0; /* Reset on errors */
+- }
++ common->running = 1;
++ for (i = 0; i < common->nluns; ++i)
++ common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+ return rc;
+ }
+
+@@ -2437,9 +2397,7 @@ static int do_set_config(struct fsg_comm
+ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
+- fsg->common->prev_fsg = fsg->common->fsg;
+- fsg->common->fsg = fsg;
+- fsg->common->new_config = 1;
++ fsg->common->new_fsg = fsg;
+ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+ return 0;
+ }
+@@ -2447,9 +2405,7 @@ static int fsg_set_alt(struct usb_functi
+ static void fsg_disable(struct usb_function *f)
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
+- fsg->common->prev_fsg = fsg->common->fsg;
+- fsg->common->fsg = fsg;
+- fsg->common->new_config = 0;
++ fsg->common->new_fsg = NULL;
+ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+ }
+
+@@ -2459,19 +2415,17 @@ static void fsg_disable(struct usb_funct
+ static void handle_exception(struct fsg_common *common)
+ {
+ siginfo_t info;
+- int sig;
+ int i;
+ struct fsg_buffhd *bh;
+ enum fsg_state old_state;
+- u8 new_config;
+ struct fsg_lun *curlun;
+ unsigned int exception_req_tag;
+- int rc;
+
+ /* Clear the existing signals. Anything but SIGUSR1 is converted
+ * into a high-priority EXIT exception. */
+ for (;;) {
+- sig = dequeue_signal_lock(current, &current->blocked, &info);
++ int sig =
++ dequeue_signal_lock(current, &current->blocked, &info);
+ if (!sig)
+ break;
+ if (sig != SIGUSR1) {
+@@ -2482,7 +2436,7 @@ static void handle_exception(struct fsg_
+ }
+
+ /* Cancel all the pending transfers */
+- if (fsg_is_set(common)) {
++ if (likely(common->fsg)) {
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ bh = &common->buffhds[i];
+ if (bh->inreq_busy)
+@@ -2523,7 +2477,6 @@ static void handle_exception(struct fsg_
+ 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)
+@@ -2573,12 +2526,12 @@ static void handle_exception(struct fsg_
+ break;
+
+ case FSG_STATE_CONFIG_CHANGE:
+- rc = do_set_config(common, new_config);
++ do_set_interface(common, common->new_fsg);
+ break;
+
+ case FSG_STATE_EXIT:
+ case FSG_STATE_TERMINATED:
+- do_set_config(common, 0); /* Free resources */
++ do_set_interface(common, NULL); /* Free resources */
+ spin_lock_irq(&common->lock);
+ common->state = FSG_STATE_TERMINATED; /* Stop the thread */
+ spin_unlock_irq(&common->lock);
+@@ -2863,6 +2816,7 @@ buffhds_first_it:
+ goto error_release;
+ }
+ init_completion(&common->thread_notifier);
++ init_waitqueue_head(&common->fsg_wait);
+ #undef OR
+
+
+@@ -2957,9 +2911,17 @@ static void fsg_common_release(struct kr
+ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+ {
+ struct fsg_dev *fsg = fsg_from_func(f);
++ struct fsg_common *common = fsg->common;
+
+ DBG(fsg, "unbind\n");
+- fsg_common_put(fsg->common);
++ if (fsg->common->fsg == fsg) {
++ fsg->common->new_fsg = NULL;
++ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
++ /* FIXME: make interruptible or killable somehow? */
++ wait_event(common->fsg_wait, common->fsg != fsg);
++ }
++
++ fsg_common_put(common);
+ usb_free_descriptors(fsg->function.descriptors);
+ usb_free_descriptors(fsg->function.hs_descriptors);
+ kfree(fsg);