diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-25 11:28:30 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-25 11:28:30 -0700 |
| commit | c23087dad116bf3266e64605046361d985e7f493 (patch) | |
| tree | ac685016c567fbe4c13a74d11413379554ee27f7 /usb.current | |
| parent | e1e6cbaa48b0a9cc53d33cf1a9b5ffd9166bcc6f (diff) | |
| download | patches-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.patch | 106 | ||||
| -rw-r--r-- | usb.current/usb-gadget-f_mass_storage-stale-common-fsg-value-bug-fix.patch | 326 |
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, ¤t->blocked, &info); ++ int sig = ++ dequeue_signal_lock(current, ¤t->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); |
