Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 314846a3 authored by Ajay Agarwal's avatar Ajay Agarwal Committed by Gustavo Solaira
Browse files

usb: gadget: f_ipc: Mark current state to CONNECTED before registering pdev



Currently as a part of set_alt, the driver first registers
'ipc_bridge' platform device and then marks the current_state to
IPC_CONNECTED. But as soon as the pdev is registered, the
ipc_router transport driver queues read request which will fail
because the current_state is still IPC_DISCONNECTED. Hence IPC
core misses the reply to the hello packet leading to
functionality failure.
Fix this by first marking current_state to IPC_CONNECTED and
then going to register platform device with ipc_bridge. While at
it, also use interruptible variant of wait_for_completion method
to unblock thread is request completion is stuck.

Change-Id: Ib2b5cd86f93af4947ec95047f803f8e08c156537
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent d3664b60
Loading
Loading
Loading
Loading
+22 −11
Original line number Diff line number Diff line
@@ -273,7 +273,10 @@ retry_write:
		goto retry_write;
	}

	wait_for_completion(&ipc_dev->write_done);
	if (unlikely(wait_for_completion_interruptible(&ipc_dev->write_done))) {
		usb_ep_dequeue(in, req);
		return -EINTR;
	}

	return !req->status ? req->actual : req->status;
}
@@ -337,7 +340,10 @@ retry_read:
		goto retry_read;
	}

	wait_for_completion(&ipc_dev->read_done);
	if (unlikely(wait_for_completion_interruptible(&ipc_dev->read_done))) {
		usb_ep_dequeue(out, req);
		return -EINTR;
	}

	return !req->status ? req->actual : req->status;
}
@@ -399,42 +405,47 @@ static void ipc_function_work(struct work_struct *w)
	switch (ctxt->current_state) {
	case IPC_DISCONNECTED:
		if (!ctxt->connected)
			return;
			break;

		ctxt->current_state = IPC_CONNECTED;
		ctxt->online = 1;
		ctxt->pdev = platform_device_alloc("ipc_bridge", -1);
		if (!ctxt->pdev)
			return;
			goto pdev_fail;

		ret = platform_device_add_data(ctxt->pdev, &ipc_pdata,
				sizeof(struct ipc_bridge_platform_data));
		if (ret) {
			platform_device_put(ctxt->pdev);
			pr_err("%s: fail to add pdata\n", __func__);
			return;
			goto pdev_fail;
		}

		ret = platform_device_add(ctxt->pdev);
		if (ret) {
			platform_device_put(ctxt->pdev);
			pr_err("%s: fail to add pdev\n", __func__);
			return;
			goto pdev_fail;
		}
		ctxt->current_state = IPC_CONNECTED;
		ctxt->online = 1;
		break;

	case IPC_CONNECTED:
		if (ctxt->connected)
			return;
			break;

		platform_device_unregister(ctxt->pdev);
		ctxt->current_state = IPC_DISCONNECTED;
		wake_up(&ctxt->state_wq);
		break;

	default:
		pr_debug("%s: Unknown current state\n", __func__);
	}

	return;

pdev_fail:
	ctxt->online = 0;
	ctxt->current_state = IPC_DISCONNECTED;
	return;
}

static int ipc_bind(struct usb_configuration *c, struct usb_function *f)