Commit 78db441d authored by Alan Stern's avatar Alan Stern Committed by Felipe Balbi

USB: f_mass_storage: improve async notification handling

This patch makes several adjustments to the way f_mass_storage.c
handles its internal state and asynchronous notifications (AKA
exceptions):

	A number of states weren't being used for anything.
	They are removed.

	The FSG_STATE_IDLE state was renamed to FSG_STATE_NORMAL,
	because it now applies whenever the gadget is operating
	normally, not just when the gadget is idle.

	The FSG_STATE_RESET state was renamed to
	FSG_STATE_PROTOCOL_RESET, indicating that it represents a
	Bulk-Only Transport protocol reset and not a general USB
	reset.

	When a signal arrives, it's silly for the signal handler to
	send itself another signal!  Now it takes care of everything
	inline.

Along with an assortment of other minor changes in the same category.
Tested-by: default avatarThinh Nguyen <thinhn@synopsys.com>
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 2ea659a9
...@@ -355,7 +355,7 @@ typedef void (*fsg_routine_t)(struct fsg_dev *); ...@@ -355,7 +355,7 @@ typedef void (*fsg_routine_t)(struct fsg_dev *);
static int exception_in_progress(struct fsg_common *common) static int exception_in_progress(struct fsg_common *common)
{ {
return common->state > FSG_STATE_IDLE; return common->state > FSG_STATE_NORMAL;
} }
/* Make bulk-out requests be divisible by the maxpacket size */ /* Make bulk-out requests be divisible by the maxpacket size */
...@@ -528,7 +528,7 @@ static int fsg_setup(struct usb_function *f, ...@@ -528,7 +528,7 @@ static int fsg_setup(struct usb_function *f,
* and reinitialize our state. * and reinitialize our state.
*/ */
DBG(fsg, "bulk reset request\n"); DBG(fsg, "bulk reset request\n");
raise_exception(fsg->common, FSG_STATE_RESET); raise_exception(fsg->common, FSG_STATE_PROTOCOL_RESET);
return USB_GADGET_DELAYED_STATUS; return USB_GADGET_DELAYED_STATUS;
case US_BULK_GET_MAX_LUN: case US_BULK_GET_MAX_LUN:
...@@ -1625,7 +1625,7 @@ static int finish_reply(struct fsg_common *common) ...@@ -1625,7 +1625,7 @@ static int finish_reply(struct fsg_common *common)
return rc; return rc;
} }
static int send_status(struct fsg_common *common) static void send_status(struct fsg_common *common)
{ {
struct fsg_lun *curlun = common->curlun; struct fsg_lun *curlun = common->curlun;
struct fsg_buffhd *bh; struct fsg_buffhd *bh;
...@@ -1639,7 +1639,7 @@ static int send_status(struct fsg_common *common) ...@@ -1639,7 +1639,7 @@ static int send_status(struct fsg_common *common)
while (bh->state != BUF_STATE_EMPTY) { while (bh->state != BUF_STATE_EMPTY) {
rc = sleep_thread(common, true); rc = sleep_thread(common, true);
if (rc) if (rc)
return rc; return;
} }
if (curlun) { if (curlun) {
...@@ -1674,10 +1674,10 @@ static int send_status(struct fsg_common *common) ...@@ -1674,10 +1674,10 @@ static int send_status(struct fsg_common *common)
bh->inreq->zero = 0; bh->inreq->zero = 0;
if (!start_in_transfer(common, bh)) if (!start_in_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */ /* Don't know what to do if common->fsg is NULL */
return -EIO; return;
common->next_buffhd_to_fill = bh->next; common->next_buffhd_to_fill = bh->next;
return 0; return;
} }
...@@ -2362,9 +2362,11 @@ static void handle_exception(struct fsg_common *common) ...@@ -2362,9 +2362,11 @@ static void handle_exception(struct fsg_common *common)
if (!sig) if (!sig)
break; break;
if (sig != SIGUSR1) { if (sig != SIGUSR1) {
spin_lock_irq(&common->lock);
if (common->state < FSG_STATE_EXIT) if (common->state < FSG_STATE_EXIT)
DBG(common, "Main thread exiting on signal\n"); DBG(common, "Main thread exiting on signal\n");
raise_exception(common, FSG_STATE_EXIT); common->state = FSG_STATE_EXIT;
spin_unlock_irq(&common->lock);
} }
} }
...@@ -2413,10 +2415,9 @@ static void handle_exception(struct fsg_common *common) ...@@ -2413,10 +2415,9 @@ static void handle_exception(struct fsg_common *common)
common->next_buffhd_to_drain = &common->buffhds[0]; common->next_buffhd_to_drain = &common->buffhds[0];
exception_req_tag = common->exception_req_tag; exception_req_tag = common->exception_req_tag;
old_state = common->state; old_state = common->state;
common->state = FSG_STATE_NORMAL;
if (old_state == FSG_STATE_ABORT_BULK_OUT) if (old_state != FSG_STATE_ABORT_BULK_OUT) {
common->state = FSG_STATE_STATUS_PHASE;
else {
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
curlun = common->luns[i]; curlun = common->luns[i];
if (!curlun) if (!curlun)
...@@ -2427,21 +2428,19 @@ static void handle_exception(struct fsg_common *common) ...@@ -2427,21 +2428,19 @@ static void handle_exception(struct fsg_common *common)
curlun->sense_data_info = 0; curlun->sense_data_info = 0;
curlun->info_valid = 0; curlun->info_valid = 0;
} }
common->state = FSG_STATE_IDLE;
} }
spin_unlock_irq(&common->lock); spin_unlock_irq(&common->lock);
/* Carry out any extra actions required for the exception */ /* Carry out any extra actions required for the exception */
switch (old_state) { switch (old_state) {
case FSG_STATE_NORMAL:
break;
case FSG_STATE_ABORT_BULK_OUT: case FSG_STATE_ABORT_BULK_OUT:
send_status(common); 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; break;
case FSG_STATE_RESET: case FSG_STATE_PROTOCOL_RESET:
/* /*
* In case we were forced against our will to halt a * In case we were forced against our will to halt a
* bulk endpoint, clear the halt now. (The SuperH UDC * bulk endpoint, clear the halt now. (The SuperH UDC
...@@ -2474,19 +2473,13 @@ static void handle_exception(struct fsg_common *common) ...@@ -2474,19 +2473,13 @@ static void handle_exception(struct fsg_common *common)
break; break;
case FSG_STATE_EXIT: case FSG_STATE_EXIT:
case FSG_STATE_TERMINATED:
do_set_interface(common, NULL); /* Free resources */ do_set_interface(common, NULL); /* Free resources */
spin_lock_irq(&common->lock); spin_lock_irq(&common->lock);
common->state = FSG_STATE_TERMINATED; /* Stop the thread */ common->state = FSG_STATE_TERMINATED; /* Stop the thread */
spin_unlock_irq(&common->lock); spin_unlock_irq(&common->lock);
break; break;
case FSG_STATE_INTERFACE_CHANGE: case FSG_STATE_TERMINATED:
case FSG_STATE_DISCONNECT:
case FSG_STATE_COMMAND_PHASE:
case FSG_STATE_DATA_PHASE:
case FSG_STATE_STATUS_PHASE:
case FSG_STATE_IDLE:
break; break;
} }
} }
...@@ -2529,29 +2522,13 @@ static int fsg_main_thread(void *common_) ...@@ -2529,29 +2522,13 @@ static int fsg_main_thread(void *common_)
continue; continue;
} }
if (get_next_command(common)) if (get_next_command(common) || exception_in_progress(common))
continue; continue;
if (do_scsi_command(common) || exception_in_progress(common))
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(common) || finish_reply(common))
continue; continue;
if (finish_reply(common) || exception_in_progress(common))
spin_lock_irq(&common->lock);
if (!exception_in_progress(common))
common->state = FSG_STATE_STATUS_PHASE;
spin_unlock_irq(&common->lock);
if (send_status(common))
continue; continue;
send_status(common);
spin_lock_irq(&common->lock);
if (!exception_in_progress(common))
common->state = FSG_STATE_IDLE;
spin_unlock_irq(&common->lock);
} }
spin_lock_irq(&common->lock); spin_lock_irq(&common->lock);
...@@ -2972,7 +2949,6 @@ static void fsg_common_release(struct kref *ref) ...@@ -2972,7 +2949,6 @@ static void fsg_common_release(struct kref *ref)
if (common->state != FSG_STATE_TERMINATED) { if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT); raise_exception(common, FSG_STATE_EXIT);
wait_for_completion(&common->thread_notifier); wait_for_completion(&common->thread_notifier);
common->thread_task = NULL;
} }
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
...@@ -3021,11 +2997,11 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -3021,11 +2997,11 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
} }
if (!common->thread_task) { if (!common->thread_task) {
common->state = FSG_STATE_IDLE; common->state = FSG_STATE_NORMAL;
common->thread_task = common->thread_task =
kthread_create(fsg_main_thread, common, "file-storage"); kthread_create(fsg_main_thread, common, "file-storage");
if (IS_ERR(common->thread_task)) { if (IS_ERR(common->thread_task)) {
int ret = PTR_ERR(common->thread_task); ret = PTR_ERR(common->thread_task);
common->thread_task = NULL; common->thread_task = NULL;
common->state = FSG_STATE_TERMINATED; common->state = FSG_STATE_TERMINATED;
return ret; return ret;
......
...@@ -157,17 +157,10 @@ struct fsg_buffhd { ...@@ -157,17 +157,10 @@ struct fsg_buffhd {
}; };
enum fsg_state { enum fsg_state {
/* This one isn't used anywhere */ FSG_STATE_NORMAL,
FSG_STATE_COMMAND_PHASE = -10,
FSG_STATE_DATA_PHASE,
FSG_STATE_STATUS_PHASE,
FSG_STATE_IDLE = 0,
FSG_STATE_ABORT_BULK_OUT, FSG_STATE_ABORT_BULK_OUT,
FSG_STATE_RESET, FSG_STATE_PROTOCOL_RESET,
FSG_STATE_INTERFACE_CHANGE,
FSG_STATE_CONFIG_CHANGE, FSG_STATE_CONFIG_CHANGE,
FSG_STATE_DISCONNECT,
FSG_STATE_EXIT, FSG_STATE_EXIT,
FSG_STATE_TERMINATED FSG_STATE_TERMINATED
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment