Apply b894f60a23
				
					
				
			This commit is contained in:
		@@ -317,8 +317,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;
 | 
			
		||||
@@ -347,7 +347,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;
 | 
			
		||||
@@ -587,7 +586,7 @@ static int fsg_setup(struct usb_function *f,
 | 
			
		||||
	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) {
 | 
			
		||||
@@ -2267,24 +2266,20 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 | 
			
		||||
	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;
 | 
			
		||||
	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];
 | 
			
		||||
@@ -2309,18 +2304,16 @@ 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);
 | 
			
		||||
 | 
			
		||||
	if (fsg_is_set(common)) {
 | 
			
		||||
		struct fsg_dev *fsg = common->fsg;
 | 
			
		||||
		common->prev_fsg = common->fsg;
 | 
			
		||||
	common->fsg = new_fsg;
 | 
			
		||||
	fsg = common->fsg;
 | 
			
		||||
 | 
			
		||||
	/* Enable the endpoints */
 | 
			
		||||
	d = fsg_ep_desc(common->gadget,
 | 
			
		||||
@@ -2359,39 +2352,6 @@ reset:
 | 
			
		||||
	for (i = 0; i < common->nluns; ++i)
 | 
			
		||||
		common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
 | 
			
		||||
	return rc;
 | 
			
		||||
	} else {
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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 */
 | 
			
		||||
	}
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -2401,9 +2361,7 @@ static int do_set_config(struct fsg_common *common, u8 new_config)
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
@@ -2411,9 +2369,7 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2423,19 +2379,17 @@ static void fsg_disable(struct usb_function *f)
 | 
			
		||||
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) {
 | 
			
		||||
@@ -2446,7 +2400,7 @@ static void handle_exception(struct fsg_common *common)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 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)
 | 
			
		||||
@@ -2487,7 +2441,6 @@ static void handle_exception(struct fsg_common *common)
 | 
			
		||||
	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)
 | 
			
		||||
@@ -2537,12 +2490,12 @@ static void handle_exception(struct fsg_common *common)
 | 
			
		||||
		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);
 | 
			
		||||
@@ -2860,6 +2813,7 @@ buffhds_first_it:
 | 
			
		||||
		goto error_release;
 | 
			
		||||
	}
 | 
			
		||||
	init_completion(&common->thread_notifier);
 | 
			
		||||
	init_waitqueue_head(&common->fsg_wait);
 | 
			
		||||
#undef OR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -2954,9 +2908,19 @@ static void fsg_common_release(struct kref *ref)
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
	kfree(fsg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user