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

Commit dba6a24d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: f_qdss: Add support for mdm qdss channel" into msm-4.14

parents 0f2330d9 5d13333b
Loading
Loading
Loading
Loading
+119 −25
Original line number Original line Diff line number Diff line
@@ -183,15 +183,28 @@ struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *fi)
}
}
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/


static void qdss_ctrl_write_complete(struct usb_ep *ep,
static void qdss_write_complete(struct usb_ep *ep,
	struct usb_request *req)
	struct usb_request *req)
{
{
	struct f_qdss *qdss = ep->driver_data;
	struct f_qdss *qdss = ep->driver_data;
	struct qdss_request *d_req = req->context;
	struct qdss_request *d_req = req->context;
	struct usb_ep *in;
	struct list_head *list_pool;
	enum qdss_state state;
	unsigned long flags;
	unsigned long flags;


	pr_debug("%s\n", __func__);
	pr_debug("%s\n", __func__);


	if (qdss->debug_inface_enabled) {
		in = qdss->port.ctrl_in;
		list_pool = &qdss->ctrl_write_pool;
		state = USB_QDSS_CTRL_WRITE_DONE;
	} else {
		in = qdss->port.data;
		list_pool = &qdss->data_write_pool;
		state = USB_QDSS_DATA_WRITE_DONE;
	}

	if (!req->status) {
	if (!req->status) {
		/* send zlp */
		/* send zlp */
		if ((req->length >= ep->maxpacket) &&
		if ((req->length >= ep->maxpacket) &&
@@ -199,13 +212,13 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep,
			req->length = 0;
			req->length = 0;
			d_req->actual = req->actual;
			d_req->actual = req->actual;
			d_req->status = req->status;
			d_req->status = req->status;
			if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC))
			if (!usb_ep_queue(in, req, GFP_ATOMIC))
				return;
				return;
		}
		}
	}
	}


	spin_lock_irqsave(&qdss->lock, flags);
	spin_lock_irqsave(&qdss->lock, flags);
	list_add_tail(&req->list, &qdss->ctrl_write_pool);
	list_add_tail(&req->list, list_pool);
	if (req->length != 0) {
	if (req->length != 0) {
		d_req->actual = req->actual;
		d_req->actual = req->actual;
		d_req->status = req->status;
		d_req->status = req->status;
@@ -213,8 +226,7 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep,
	spin_unlock_irqrestore(&qdss->lock, flags);
	spin_unlock_irqrestore(&qdss->lock, flags);


	if (qdss->ch.notify)
	if (qdss->ch.notify)
		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req,
		qdss->ch.notify(qdss->ch.priv, state, d_req, NULL);
			NULL);
}
}


static void qdss_ctrl_read_complete(struct usb_ep *ep,
static void qdss_ctrl_read_complete(struct usb_ep *ep,
@@ -252,6 +264,12 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch)
		return;
		return;
	}
	}


	list_for_each_safe(act, tmp, &qdss->data_write_pool) {
		req = list_entry(act, struct usb_request, list);
		list_del(&req->list);
		usb_ep_free_request(qdss->port.data, req);
	}

	list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) {
	list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) {
		req = list_entry(act, struct usb_request, list);
		req = list_entry(act, struct usb_request, list);
		list_del(&req->list);
		list_del(&req->list);
@@ -271,23 +289,41 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf,
{
{
	struct f_qdss *qdss = ch->priv_usb;
	struct f_qdss *qdss = ch->priv_usb;
	struct usb_request *req;
	struct usb_request *req;
	struct usb_ep *in;
	struct list_head *list_pool;
	int i;
	int i;


	pr_debug("%s\n", __func__);
	pr_debug("%s\n", __func__);


	if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) {
	if (!qdss) {
		pr_err("%s: %s closed\n", __func__, ch->name);
		return -ENODEV;
	}

	if ((qdss->debug_inface_enabled &&
		(no_write_buf <= 0 || no_read_buf <= 0)) ||
		(!qdss->debug_inface_enabled &&
		(no_write_buf <= 0 || no_read_buf))) {
		pr_err("%s: missing params\n", __func__);
		pr_err("%s: missing params\n", __func__);
		return -ENODEV;
		return -ENODEV;
	}
	}


	if (qdss->debug_inface_enabled) {
		in = qdss->port.ctrl_in;
		list_pool = &qdss->ctrl_write_pool;
	} else {
		in = qdss->port.data;
		list_pool = &qdss->data_write_pool;
	}

	for (i = 0; i < no_write_buf; i++) {
	for (i = 0; i < no_write_buf; i++) {
		req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC);
		req = usb_ep_alloc_request(in, GFP_ATOMIC);
		if (!req) {
		if (!req) {
			pr_err("%s: ctrl_in allocation err\n", __func__);
			pr_err("%s: ctrl_in allocation err\n", __func__);
			goto fail;
			goto fail;
		}
		}
		req->complete = qdss_ctrl_write_complete;
		req->complete = qdss_write_complete;
		list_add_tail(&req->list, &qdss->ctrl_write_pool);
		list_add_tail(&req->list, list_pool);
	}
	}


	for (i = 0; i < no_read_buf; i++) {
	for (i = 0; i < no_read_buf; i++) {
@@ -378,6 +414,10 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
		qdss_ctrl_intf_desc.iInterface = id;
		qdss_ctrl_intf_desc.iInterface = id;
	}
	}


	/* for non-accelerated path keep tx fifo size 1k */
	if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM))
		qdss_data_ep_comp_desc.bMaxBurst = 0;

	ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_data_desc,
	ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_data_desc,
		&qdss_data_ep_comp_desc);
		&qdss_data_ep_comp_desc);
	if (!ep) {
	if (!ep) {
@@ -491,21 +531,20 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
	qdss = container_of(work, struct f_qdss, disconnect_w);
	qdss = container_of(work, struct f_qdss, disconnect_w);
	pr_debug("%s\n", __func__);
	pr_debug("%s\n", __func__);


	/*
	 * Uninitialized init data i.e. ep specific operation.
	 * Notify qdss to cancel all active transfers.
	 */
	if (qdss->ch.app_conn) {
		status = uninit_data(qdss->port.data);
		if (status)
			pr_err("%s: uninit_data error\n", __func__);


	/* Notify qdss to cancel all active transfers */
	if (qdss->ch.notify)
	if (qdss->ch.notify)
		qdss->ch.notify(qdss->ch.priv,
		qdss->ch.notify(qdss->ch.priv,
			USB_QDSS_DISCONNECT,
			USB_QDSS_DISCONNECT,
			NULL,
			NULL,
			NULL);
			NULL);


	/* Uninitialized init data i.e. ep specific operation */
	if (qdss->ch.app_conn && !strcmp(qdss->ch.name, USB_QDSS_CH_MSM)) {
		status = uninit_data(qdss->port.data);
		if (status)
			pr_err("%s: uninit_data error\n", __func__);

		status = set_qdss_data_connection(qdss, 0);
		status = set_qdss_data_connection(qdss, 0);
		if (status)
		if (status)
			pr_err("qdss_disconnect error");
			pr_err("qdss_disconnect error");
@@ -562,15 +601,16 @@ static void usb_qdss_connect_work(struct work_struct *work)
	}
	}


	pr_debug("%s\n", __func__);
	pr_debug("%s\n", __func__);

	if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM))
		goto notify;

	status = set_qdss_data_connection(qdss, 1);
	status = set_qdss_data_connection(qdss, 1);
	if (status) {
	if (status) {
		pr_err("set_qdss_data_connection error(%d)", status);
		pr_err("set_qdss_data_connection error(%d)", status);
		return;
		return;
	}
	}


	if (qdss->ch.notify)
		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
						NULL, &qdss->ch);
	spin_lock_irqsave(&qdss->lock, flags);
	spin_lock_irqsave(&qdss->lock, flags);
	req = qdss->endless_req;
	req = qdss->endless_req;
	spin_unlock_irqrestore(&qdss->lock, flags);
	spin_unlock_irqrestore(&qdss->lock, flags);
@@ -578,8 +618,15 @@ static void usb_qdss_connect_work(struct work_struct *work)
		return;
		return;


	status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC);
	status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC);
	if (status)
	if (status) {
		pr_err("%s: usb_ep_queue error (%d)\n", __func__, status);
		pr_err("%s: usb_ep_queue error (%d)\n", __func__, status);
		return;
	}

notify:
	if (qdss->ch.notify)
		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
						NULL, &qdss->ch);
}
}


static int qdss_set_alt(struct usb_function *f, unsigned int intf,
static int qdss_set_alt(struct usb_function *f, unsigned int intf,
@@ -722,6 +769,7 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name)
	spin_lock_init(&qdss->lock);
	spin_lock_init(&qdss->lock);
	INIT_LIST_HEAD(&qdss->ctrl_read_pool);
	INIT_LIST_HEAD(&qdss->ctrl_read_pool);
	INIT_LIST_HEAD(&qdss->ctrl_write_pool);
	INIT_LIST_HEAD(&qdss->ctrl_write_pool);
	INIT_LIST_HEAD(&qdss->data_write_pool);
	INIT_WORK(&qdss->connect_w, usb_qdss_connect_work);
	INIT_WORK(&qdss->connect_w, usb_qdss_connect_work);
	INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work);
	INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work);


@@ -817,6 +865,50 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
}
}
EXPORT_SYMBOL(usb_qdss_ctrl_write);
EXPORT_SYMBOL(usb_qdss_ctrl_write);


int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
{
	struct f_qdss *qdss = ch->priv_usb;
	unsigned long flags;
	struct usb_request *req = NULL;

	pr_debug("usb_qdss_ctrl_write\n");

	if (!qdss)
		return -ENODEV;

	spin_lock_irqsave(&qdss->lock, flags);

	if (qdss->usb_connected == 0) {
		spin_unlock_irqrestore(&qdss->lock, flags);
		return -EIO;
	}

	if (list_empty(&qdss->data_write_pool)) {
		pr_err("error: usb_qdss_data_write list is empty\n");
		spin_unlock_irqrestore(&qdss->lock, flags);
		return -EAGAIN;
	}

	req = list_first_entry(&qdss->data_write_pool, struct usb_request,
		list);
	list_del(&req->list);
	spin_unlock_irqrestore(&qdss->lock, flags);

	req->buf = d_req->buf;
	req->length = d_req->length;
	req->context = d_req;
	if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) {
		spin_lock_irqsave(&qdss->lock, flags);
		list_add_tail(&req->list, &qdss->data_write_pool);
		spin_unlock_irqrestore(&qdss->lock, flags);
		pr_err("qdss usb_ep_queue failed\n");
		return -EIO;
	}

	return 0;
}
EXPORT_SYMBOL(usb_qdss_write);

struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
	void (*notify)(void *priv, unsigned int event,
	void (*notify)(void *priv, unsigned int event,
		struct qdss_request *d_req, struct usb_qdss_ch *))
		struct qdss_request *d_req, struct usb_qdss_ch *))
@@ -874,7 +966,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
	pr_debug("%s\n", __func__);
	pr_debug("%s\n", __func__);


	spin_lock_irqsave(&qdss_lock, flags);
	spin_lock_irqsave(&qdss_lock, flags);
	if (!qdss || !qdss->usb_connected) {
	ch->priv_usb = NULL;
	if (!qdss || !qdss->usb_connected ||
			!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) {
		ch->app_conn = 0;
		ch->app_conn = 0;
		spin_unlock_irqrestore(&qdss_lock, flags);
		spin_unlock_irqrestore(&qdss_lock, flags);
		return;
		return;
+4 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,10 @@ struct f_qdss {
	struct usb_qdss_ch ch;
	struct usb_qdss_ch ch;
	struct list_head ctrl_read_pool;
	struct list_head ctrl_read_pool;
	struct list_head ctrl_write_pool;
	struct list_head ctrl_write_pool;

	/* for mdm channel SW path */
	struct list_head data_write_pool;

	struct work_struct connect_w;
	struct work_struct connect_w;
	struct work_struct disconnect_w;
	struct work_struct disconnect_w;
	spinlock_t lock;
	spinlock_t lock;
+3 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,9 @@


#include <linux/kernel.h>
#include <linux/kernel.h>


#define USB_QDSS_CH_MDM	"qdss_mdm"
#define USB_QDSS_CH_MSM	"qdss"

struct qdss_request {
struct qdss_request {
	char *buf;
	char *buf;
	int length;
	int length;