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

Commit 9ad1e0c0 authored by Manu Gautam's avatar Manu Gautam Committed by Stephen Boyd
Browse files

USB: android: Fix missing USB DISCONNECT uevent



Some userspace modules, e.g. MTP, work correctly only if
CONFIGURED uevent is preceded by DISCONNECT uevent. Hence,
explicitly send DISCONNECT uevent if missed out due to
really quick enumeration by USB Host.
Also, wait for some time before sending out CONFIGURED uevent
to give function drivers a chance to wakeup userspace threads
and notify previous disconnect.

Change-Id: I231b8de60b25a05e2316074b8694c9cbc15bb556
CRs-Fixed: 348066
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent 010284de
Loading
Loading
Loading
Loading
+34 −2
Original line number Diff line number Diff line
@@ -156,6 +156,12 @@ static struct usb_configuration android_config_driver = {
	.MaxPower	= 500, /* 500ma */
};

enum android_device_state {
	USB_DISCONNECTED,
	USB_CONNECTED,
	USB_CONFIGURED,
};

static void android_pm_qos_update_latency(struct android_dev *dev, int vote)
{
	struct android_usb_platform_data *pdata = dev->pdata;
@@ -184,14 +190,17 @@ static void android_work(struct work_struct *data)
	char *connected[2]    = { "USB_STATE=CONNECTED", NULL };
	char *configured[2]   = { "USB_STATE=CONFIGURED", NULL };
	char **uevent_envp = NULL;
	static enum android_device_state last_uevent, next_state;
	unsigned long flags;
	int pm_qos_vote = -1;

	spin_lock_irqsave(&cdev->lock, flags);
	if (cdev->config)
	if (cdev->config) {
		uevent_envp = configured;
	else if (dev->connected != dev->sw_connected) {
		next_state = USB_CONFIGURED;
	} else if (dev->connected != dev->sw_connected) {
		uevent_envp = dev->connected ? connected : disconnected;
		next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
		if (dev->connected && strncmp(dev->pm_qos, "low", 3))
			pm_qos_vote = 1;
		else if (!dev->connected || !strncmp(dev->pm_qos, "low", 3))
@@ -204,7 +213,30 @@ static void android_work(struct work_struct *data)
		android_pm_qos_update_latency(dev, pm_qos_vote);

	if (uevent_envp) {
		/*
		 * Some userspace modules, e.g. MTP, work correctly only if
		 * CONFIGURED uevent is preceded by DISCONNECT uevent.
		 * Check if we missed sending out a DISCONNECT uevent. This can
		 * happen if host PC resets and configures device really quick.
		 */
		if (((uevent_envp == connected) &&
		      (last_uevent != USB_DISCONNECTED)) ||
		    ((uevent_envp == configured) &&
		      (last_uevent == USB_CONFIGURED))) {
			pr_info("%s: sent missed DISCONNECT event\n", __func__);
			kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE,
								disconnected);
			msleep(20);
		}
		/*
		 * Before sending out CONFIGURED uevent give function drivers
		 * a chance to wakeup userspace threads and notify disconnect
		 */
		if (uevent_envp == configured)
			msleep(50);

		kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
		last_uevent = next_state;
		pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
	} else {
		pr_info("%s: did not send uevent (%d %d %p)\n", __func__,