This patch (as1598) adds support for the new "reset" callback to the g_file_storage driver. Resets are handled slightly differently from disconnects, in that the driver doesn't sync the backing storage file during a reset but does during a disconnect. The problem is that a file sync can take a long time if there are many dirty pages, which can cause the driver's main thread to miss other USB events if they arrive too quickly. After a disconnect we generally don't expect to see other events in the near future, whereas after a reset we do. Unfortunately the driver already contains an FSG_STATE_RESET symbol. The patch renames it to FSG_STATE_CLASS_RESET, because it refers to a class-specific reset event rather than a general USB port reset, and uses FSG_STATE_RESET for port resets. The g_mass_storage driver shares a source file with g_file_storage; therefore it had to be modified accordingly. Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Reported-by: Chen Peter-B29397 <B29397@xxxxxxxxxxxxx> --- drivers/usb/gadget/f_mass_storage.c | 5 +++-- drivers/usb/gadget/file_storage.c | 20 ++++++++++++++++---- drivers/usb/gadget/storage_common.c | 3 ++- 3 files changed, 21 insertions(+), 7 deletions(-) Index: usb-3.5/drivers/usb/gadget/storage_common.c =================================================================== --- usb-3.5.orig/drivers/usb/gadget/storage_common.c +++ usb-3.5/drivers/usb/gadget/storage_common.c @@ -279,9 +279,10 @@ enum fsg_state { FSG_STATE_IDLE = 0, FSG_STATE_ABORT_BULK_OUT, - FSG_STATE_RESET, + FSG_STATE_CLASS_RESET, FSG_STATE_INTERFACE_CHANGE, FSG_STATE_CONFIG_CHANGE, + FSG_STATE_RESET, FSG_STATE_DISCONNECT, FSG_STATE_EXIT, FSG_STATE_TERMINATED Index: usb-3.5/drivers/usb/gadget/file_storage.c =================================================================== --- usb-3.5.orig/drivers/usb/gadget/file_storage.c +++ usb-3.5/drivers/usb/gadget/file_storage.c @@ -676,10 +676,18 @@ static void fsg_disconnect(struct usb_ga { struct fsg_dev *fsg = get_gadget_data(gadget); - DBG(fsg, "disconnect or port reset\n"); + DBG(fsg, "disconnect\n"); raise_exception(fsg, FSG_STATE_DISCONNECT); } +static void fsg_reset(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "port reset\n"); + raise_exception(fsg, FSG_STATE_RESET); +} + static int ep0_queue(struct fsg_dev *fsg) { @@ -816,7 +824,7 @@ static void received_cbi_adsc(struct fsg /* Raise an exception to stop the current operation * and reinitialize our state. */ DBG(fsg, "cbi reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); + raise_exception(fsg, FSG_STATE_CLASS_RESET); return; } @@ -867,7 +875,7 @@ static int class_setup_req(struct fsg_de /* 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, FSG_STATE_CLASS_RESET); value = DELAYED_STATUS; break; @@ -3006,7 +3014,7 @@ static void handle_exception(struct fsg_ spin_unlock_irq(&fsg->lock); break; - case FSG_STATE_RESET: + case FSG_STATE_CLASS_RESET: /* In case we were forced against our will to halt a * bulk endpoint, clear the halt now. (The SuperH UDC * requires this.) */ @@ -3050,6 +3058,9 @@ static void handle_exception(struct fsg_ case FSG_STATE_DISCONNECT: for (i = 0; i < fsg->nluns; ++i) fsg_lun_fsync_sub(fsg->luns + i); + /* FALL THROUGH */ + + case FSG_STATE_RESET: do_set_config(fsg, 0); // Unconfigured state break; @@ -3608,6 +3619,7 @@ static struct usb_gadget_driver fsg_dri .function = (char *) fsg_string_product, .unbind = fsg_unbind, .disconnect = fsg_disconnect, + .reset = fsg_reset, .setup = fsg_setup, .suspend = fsg_suspend, .resume = fsg_resume, Index: usb-3.5/drivers/usb/gadget/f_mass_storage.c =================================================================== --- usb-3.5.orig/drivers/usb/gadget/f_mass_storage.c +++ usb-3.5/drivers/usb/gadget/f_mass_storage.c @@ -554,7 +554,7 @@ static int fsg_setup(struct usb_function * and reinitialize our state. */ DBG(fsg, "bulk reset request\n"); - raise_exception(fsg->common, FSG_STATE_RESET); + raise_exception(fsg->common, FSG_STATE_CLASS_RESET); return DELAYED_STATUS; case US_BULK_GET_MAX_LUN: @@ -2470,7 +2470,7 @@ static void handle_exception(struct fsg_ spin_unlock_irq(&common->lock); break; - case FSG_STATE_RESET: + case FSG_STATE_CLASS_RESET: /* * In case we were forced against our will to halt a * bulk endpoint, clear the halt now. (The SuperH UDC @@ -2511,6 +2511,7 @@ static void handle_exception(struct fsg_ case FSG_STATE_INTERFACE_CHANGE: case FSG_STATE_DISCONNECT: + case FSG_STATE_RESET: case FSG_STATE_COMMAND_PHASE: case FSG_STATE_DATA_PHASE: case FSG_STATE_STATUS_PHASE: -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html