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

Commit 4f3365f4 authored by Sreelakshmi Gownipalli's avatar Sreelakshmi Gownipalli Committed by Gerrit - the friendly Code Review server
Browse files

diag: Add usb events to a queue



Add usb connect and disconnect events to a queue and
process each event in work function so that all of the
usb connect and disconnect events are processed without
any miss.

Change-Id: I2b5debef28d683f55a727e53e41c811419d2bf3f
Signed-off-by: default avatarSreelakshmi Gownipalli <sgownipa@codeaurora.org>
parent 80eeb91a
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -440,8 +440,7 @@ static ssize_t diag_dbgfs_read_usbinfo(struct file *file, char __user *ubuf,
			"write count: %lu\n"
			"read work pending: %d\n"
			"read done work pending: %d\n"
			"connect work pending: %d\n"
			"disconnect work pending: %d\n"
			"event work pending: %d\n"
			"max size supported: %d\n\n",
			usb_info->id,
			usb_info->name,
@@ -455,8 +454,7 @@ static ssize_t diag_dbgfs_read_usbinfo(struct file *file, char __user *ubuf,
			usb_info->write_cnt,
			work_pending(&usb_info->read_work),
			work_pending(&usb_info->read_done_work),
			work_pending(&usb_info->connect_work),
			work_pending(&usb_info->disconnect_work),
			work_pending(&usb_info->event_work),
			usb_info->max_size);
		bytes_in_buffer += bytes_written;

+62 −43
Original line number Diff line number Diff line
@@ -86,7 +86,29 @@ struct diag_usb_info diag_usb[NUM_DIAG_USB_DEV] = {
	}
#endif
};
static int diag_usb_event_add(struct diag_usb_info *usb_info, int data)
{
	struct diag_usb_event_q *entry = NULL;

	entry = kzalloc(sizeof(struct diag_usb_event_q), GFP_ATOMIC);
	if (!entry)
		return -ENOMEM;

	entry->data = data;
	INIT_LIST_HEAD(&entry->link);
	list_add_tail(&entry->link, &usb_info->event_q);

	return 0;
}
static void diag_usb_event_remove(struct diag_usb_event_q *entry)
{
	if (!entry)
		return;

	list_del(&entry->link);
	kfree(entry);
	entry = NULL;
}
static int diag_usb_buf_tbl_add(struct diag_usb_info *usb_info,
				unsigned char *buf, uint32_t len, int ctxt)
{
@@ -194,25 +216,6 @@ static void usb_connect(struct diag_usb_info *ch)
	queue_work(ch->usb_wq, &(ch->read_work));
}

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);
}

/*
 * This function is called asynchronously when USB is disconnected
 * and synchronously when Diag wants to disconnect from USB
@@ -224,32 +227,48 @@ static void usb_disconnect(struct diag_usb_info *ch)
		ch->ops->close(ch->ctxt, DIAG_USB_MODE);
}

static void usb_disconnect_work_fn(struct work_struct *work)
static void usb_event_work_fn(struct work_struct *work)
{
	struct diag_usb_info *ch = container_of(work, struct diag_usb_info,
						disconnect_work);
						event_work);
	struct diag_usb_event_q *entry = NULL;

	if (!ch)
		return;
	entry = list_first_entry(&(ch->event_q), struct diag_usb_event_q, link);
	if (!entry)
		return;

	switch (entry->data) {
	case USB_DIAG_CONNECT:
		wait_event_interruptible(ch->wait_q, ch->enabled > 0);
		ch->max_size = usb_diag_request_size(ch->hdl);
		atomic_set(&ch->connected, 1);

	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));
		"diag: USB channel %s: connected_status: %d\n",
		ch->name, atomic_read(&ch->connected));

	wait_event_interruptible(ch->wait_q, atomic_read(&ch->connected) > 0);
		usb_connect(ch);
		break;
	case USB_DIAG_DISCONNECT:
		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));
				 "diag: USB channel %s: Cleared connected(%d) status\n",
				 ch->name, atomic_read(&ch->connected));

		if (!atomic_read(&ch->connected) &&
		driver->usb_connected && diag_mask_param() &&
		ch->id == DIAG_USB_LOCAL)
			driver->usb_connected &&
			(ch->id == DIAG_USB_LOCAL) && diag_mask_param())
			diag_clear_masks(0);

		usb_disconnect(ch);
		break;
	}
	diag_usb_event_remove(entry);
	if (!list_empty(&ch->event_q))
		queue_work(ch->usb_wq, &(ch->event_work));

}

static void usb_read_work_fn(struct work_struct *work)
@@ -378,15 +397,16 @@ static void diag_usb_notifier(void *priv, unsigned int event,
	case USB_DIAG_CONNECT:
		pr_info("diag: USB channel %s: Received Connect event\n",
			usb_info->name);
		if (!atomic_read(&usb_info->connected))
		diag_usb_event_add(usb_info, USB_DIAG_CONNECT);
		queue_work(usb_info->usb_wq,
			   &usb_info->connect_work);
			   &usb_info->event_work);
		break;
	case USB_DIAG_DISCONNECT:
		pr_info("diag: USB channel %s: Received Disconnect event\n",
			usb_info->name);
		diag_usb_event_add(usb_info, USB_DIAG_DISCONNECT);
		queue_work(usb_info->usb_wq,
			   &usb_info->disconnect_work);
			   &usb_info->event_work);
		break;
	case USB_DIAG_READ_DONE:
		spin_lock_irqsave(&usb_info->lock, flags);
@@ -665,7 +685,6 @@ 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.
@@ -674,11 +693,11 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops)
	 */
	atomic_set(&ch->diag_state, 1);
	INIT_LIST_HEAD(&ch->buf_tbl);
	INIT_LIST_HEAD(&ch->event_q);
	diagmem_init(driver, ch->mempool);
	INIT_WORK(&(ch->read_work), usb_read_work_fn);
	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_WORK(&(ch->event_work), usb_event_work_fn);
	init_waitqueue_head(&ch->wait_q);
	strlcpy(wq_name, "DIAG_USB_", sizeof(wq_name));
	strlcat(wq_name, ch->name, sizeof(wq_name));
+7 −3
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@ struct diag_usb_buf_tbl_t {
	int ctxt;
};

struct diag_usb_event_q {
	struct list_head link;
	int data;
};

struct diag_usb_info {
	int id;
	int ctxt;
@@ -45,7 +50,6 @@ 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;
@@ -60,10 +64,10 @@ struct diag_usb_info {
	struct diag_request *read_ptr;
	struct work_struct read_work;
	struct work_struct read_done_work;
	struct work_struct connect_work;
	struct work_struct disconnect_work;
	struct work_struct event_work;
	struct workqueue_struct *usb_wq;
	wait_queue_head_t wait_q;
	struct list_head event_q;
};

#ifdef CONFIG_DIAG_OVER_USB