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

Commit 99e899ad authored by Sreelakshmi Gownipalli's avatar Sreelakshmi Gownipalli Committed by Manoj Prabhu B
Browse files

diag: Wait until usb diag channel opens during cable connect



If USB cable is connected before diag opens its usb channel,
the cable connect notification is missed for diag USB channel.
USB has now provisioned for a connect notification during USB
open. The patch adds a mechanism for diag to wait on connect
notification until the usb open call is completed and fix for
a possible race condition between connect and disconnect events.

Change-Id: I62c4cb80fec23c2b6f1dc8312ee2a4e0c96c03ac
Signed-off-by: default avatarSreelakshmi Gownipalli <sgownipa@codeaurora.org>
Signed-off-by: default avatarManoj Prabhu B <bmanoj@codeaurora.org>
parent dd753cb7
Loading
Loading
Loading
Loading
+36 −7
Original line number Diff line number Diff line
@@ -206,7 +206,19 @@ static void usb_connect_work_fn(struct work_struct *work)
{
	struct diag_usb_info *ch = container_of(work, struct diag_usb_info,
						connect_work);

	wait_event_interruptible(ch->wait_q, ch->enabled > 0);
	ch->max_size = usb_diag_request_size(ch->hdl);
	atomic_set(&ch->connected, 1);

	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
	"diag: USB channel %s: disconnected_status: %d, connected_status: %d\n",
	ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected));

	usb_connect(ch);

	if (atomic_read(&ch->disconnected))
		wake_up_interruptible(&ch->wait_q);
}

/*
@@ -231,6 +243,19 @@ static void usb_disconnect_work_fn(struct work_struct *work)
{
	struct diag_usb_info *ch = container_of(work, struct diag_usb_info,
						disconnect_work);

	atomic_set(&ch->disconnected, 1);
	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
	"diag: USB channel %s: disconnected_status: %d, connected_status: %d\n",
	ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected));

	wait_event_interruptible(ch->wait_q, atomic_read(&ch->connected) > 0);
	atomic_set(&ch->connected, 0);
	atomic_set(&ch->disconnected, 0);
	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
	"diag: USB channel %s: Cleared disconnected(%d) and connected(%d) status\n",
	ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected));

	usb_disconnect(ch);
}

@@ -357,15 +382,15 @@ static void diag_usb_notifier(void *priv, unsigned int event,

	switch (event) {
	case USB_DIAG_CONNECT:
		usb_info->max_size = usb_diag_request_size(usb_info->hdl);
		atomic_set(&usb_info->connected, 1);
		pr_info("diag: USB channel %s connected\n", usb_info->name);
		pr_info("diag: USB channel %s: Received Connect event\n",
			usb_info->name);
		if (!atomic_read(&usb_info->connected))
			queue_work(usb_info->usb_wq,
			   &usb_info->connect_work);
		break;
	case USB_DIAG_DISCONNECT:
		atomic_set(&usb_info->connected, 0);
		pr_info("diag: USB channel %s disconnected\n", usb_info->name);
		pr_info("diag: USB channel %s: Received Disconnect event\n",
			usb_info->name);
		queue_work(usb_info->usb_wq,
			   &usb_info->disconnect_work);
		break;
@@ -618,6 +643,7 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops)
	if (!ch->read_ptr)
		goto err;
	atomic_set(&ch->connected, 0);
	atomic_set(&ch->disconnected, 0);
	atomic_set(&ch->read_pending, 0);
	/*
	 * This function is called when the mux registers with Diag-USB.
@@ -631,6 +657,7 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops)
	INIT_WORK(&(ch->read_done_work), usb_read_done_work_fn);
	INIT_WORK(&(ch->connect_work), usb_connect_work_fn);
	INIT_WORK(&(ch->disconnect_work), usb_disconnect_work_fn);
	init_waitqueue_head(&ch->wait_q);
	strlcpy(wq_name, "DIAG_USB_", DIAG_USB_STRING_SZ);
	strlcat(wq_name, ch->name, sizeof(ch->name));
	ch->usb_wq = create_singlethread_workqueue(wq_name);
@@ -643,7 +670,9 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops)
		goto err;
	}
	ch->enabled = 1;
	pr_debug("diag: Successfully registered USB %s\n", ch->name);
	wake_up_interruptible(&ch->wait_q);
	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"diag: Successfully registered USB %s\n", ch->name);
	return 0;

err:
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -53,6 +53,7 @@ struct diag_usb_info {
	atomic_t connected;
	atomic_t diag_state;
	atomic_t read_pending;
	atomic_t disconnected;
	int enabled;
	int mempool;
	int max_size;
@@ -70,6 +71,7 @@ struct diag_usb_info {
	struct work_struct connect_work;
	struct work_struct disconnect_work;
	struct workqueue_struct *usb_wq;
	wait_queue_head_t wait_q;
};

#ifdef CONFIG_DIAG_OVER_USB