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

Commit e883289f authored by Mayank Rana's avatar Mayank Rana Committed by Matt Wagantall
Browse files

USB: QTI_DPL: Add support for QTI control with DPL



This change adds required support for QTI control with QDSS driver
for DPL functionality and also handles same with QTI driver.

CRs-Fixed: 701879
Change-Id: I025740c10f3b72ad72d0749f657d81d2ac1b45c9
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 2e85bf7c
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -1496,6 +1496,7 @@ static int qdss_init_transports(int *portnum)
{
	char *ts_port;
	char *tname = NULL;
	char *ctrl_name = NULL;
	char buf[MAX_XPORT_STR_LEN], *type;
	char xport_name_buf[MAX_XPORT_STR_LEN], *tn;
	int err = 0;
@@ -1510,13 +1511,28 @@ static int qdss_init_transports(int *portnum)
	pr_debug("%s: qdss_debug_intf = %d\n",
		__func__, qdss_debug_intf);

	/*
	 * QDSS function driver is being used for QDSS and DPL
	 * functionality. ctrl_name (i.e. ctrl xport) is optional
	 * whereas data transport name is mandatory to provide
	 * while using QDSS/DPL as part of USB composition.
	 */
	while (type) {
		ctrl_name = strsep(&type, ",");
		ts_port = strsep(&type, ",");
		if (!ts_port) {
			pr_debug("%s:ctrl transport is not provided.\n",
								__func__);
			ts_port = ctrl_name;
			ctrl_name = NULL;
		}

		if (ts_port) {
			if (tn)
				tname = strsep(&tn, ",");

			err = qdss_init_port(
				ctrl_name,
				ts_port,
				tname,
				qdss_debug_intf);
@@ -1527,6 +1543,10 @@ static int qdss_init_transports(int *portnum)
				return err;
			}
			(*portnum)++;
		} else {
			pr_err("%s: No data transport name for QDSS port.\n",
								__func__);
			err = -ENODEV;
		}
	}
	return err;
+52 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/device.h>
#include <linux/usb/usb_qdss.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/usb/cdc.h>

#include "gadget_chips.h"
#include "f_qdss.h"
@@ -32,6 +33,8 @@ static unsigned int no_ipa_ports;
static struct qdss_ports {
	enum transport_type		data_xport;
	unsigned char			data_xport_num;
	enum transport_type		ctrl_xport;
	unsigned char			ctrl_xport_num;
	unsigned	char		port_num;
	struct f_qdss			*port;
	struct gadget_ipa_port		ipa_port;
@@ -493,10 +496,12 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
	int status;
	unsigned char portno;
	enum transport_type	dxport;
	enum transport_type     ctrl_xport;
	struct gadget_ipa_port *gp;

	qdss = container_of(work, struct f_qdss, disconnect_w);
	dxport = qdss_ports[qdss->port_num].data_xport;
	ctrl_xport = qdss_ports[qdss->port_num].ctrl_xport;
	portno = qdss_ports[qdss->port_num].data_xport_num;

	if (qdss->port_num >= nr_qdss_ports) {
@@ -506,6 +511,16 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
		return;
	}
	pr_debug("usb_qdss_disconnect_work\n");
	switch (ctrl_xport) {
	case USB_GADGET_XPORT_QTI:
		gqti_ctrl_disconnect(&qdss->port, DPL_QTI_CTRL_PORT_NO);
		break;
	default:
		pr_err("%s(): Un-supported transport: %u\n", __func__,
							ctrl_xport);
		return;
	}

	switch (dxport) {
	case USB_GADGET_XPORT_BAM:
		/*
@@ -638,9 +653,11 @@ static void usb_qdss_connect_work(struct work_struct *work)
	int status;
	unsigned char port_num;
	enum transport_type	dxport;
	enum transport_type     ctrl_xport;

	qdss = container_of(work, struct f_qdss, connect_w);
	dxport = qdss_ports[qdss->port_num].data_xport;
	ctrl_xport = qdss_ports[qdss->port_num].ctrl_xport;
	port_num = qdss_ports[qdss->port_num].data_xport_num;
	pr_debug("%s: data xport: %s dev: %p portno: %d\n",
			__func__, xport_to_str(dxport),
@@ -659,6 +676,25 @@ static void usb_qdss_connect_work(struct work_struct *work)
	}

	pr_debug("usb_qdss_connect_work\n");

	switch (ctrl_xport) {
	case USB_GADGET_XPORT_QTI:
		status = gqti_ctrl_connect(&qdss->port, DPL_QTI_CTRL_PORT_NO,
					qdss->data_iface_id, ctrl_xport,
					USB_GADGET_DPL);
		if (status) {
			pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
						__func__, status);
			return;
		}
		qdss->port.send_encap_cmd(DPL_QTI_CTRL_PORT_NO, NULL, 0);
		break;
	default:
		pr_err("%s(): Un-supported control transport: %u\n", __func__,
								ctrl_xport);
		return;
	}

	switch (dxport) {
	case USB_GADGET_XPORT_BAM:
		status = init_data(qdss->port.data);
@@ -693,7 +729,6 @@ static void usb_qdss_connect_work(struct work_struct *work)
			return;
		}
		qdss->data_enabled = 1;
		qdss->usb_connected = 1;
		break;
	case USB_GADGET_XPORT_HSIC:
		pr_debug("usb_qdss_connect_work: HSIC transport\n");
@@ -743,6 +778,7 @@ static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			return -EINVAL;

		if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA) {
			qdss->usb_connected = 1;
			usb_qdss_connect_work(&qdss->connect_w);
			return 0;
		}
@@ -1113,7 +1149,7 @@ static int qdss_setup(void)
	return 0;
}

static int qdss_init_port(const char *data_name,
static int qdss_init_port(const char *ctrl_name, const char *data_name,
			const char *port_name, bool debug_enable)
{
	struct f_qdss			*dev;
@@ -1145,6 +1181,19 @@ static int qdss_init_port(const char *data_name,
	qdss_port->data_xport = str_to_xport(data_name);
	qdss_port->port->debug_inface_enabled = debug_enable;

	if (ctrl_name) {
		qdss_port->ctrl_xport = str_to_xport(ctrl_name);
		pr_debug("%s(): ctrl_name:%s ctrl_xport:%d\n", __func__,
				ctrl_name, qdss_port->ctrl_xport);
		switch (qdss_port->ctrl_xport) {
		case USB_GADGET_XPORT_QTI:
			pr_debug("USB_GADGET_XPORT_QTI is used.\n");
			break;
		default:
			pr_debug("%s(): No ctrl transport.\n", __func__);
		}
	}

	switch (qdss_port->data_xport) {
	case USB_GADGET_XPORT_BAM:
		qdss_port->data_xport_num = no_data_bam_ports;
+2 −1
Original line number Diff line number Diff line
@@ -25,11 +25,12 @@ struct gqdss {
	struct usb_ep *ctrl_out;
	struct usb_ep *ctrl_in;
	struct usb_ep *data;
	int (*send_encap_cmd)(u8 port_num, void *buf, size_t len);
	void (*notify_modem)(void *g, u8 port_num, int cbits);
};

/* struct f_qdss - USB qdss function driver private structure */
struct f_qdss {

	struct gqdss port;
	struct usb_composite_dev *cdev;
	u8 port_num;
+81 −29
Original line number Diff line number Diff line
@@ -20,10 +20,17 @@
#include "usb_gadget_xport.h"

#define RMNET_CTRL_QTI_NAME "rmnet_ctrl"
#define DPL_CTRL_QTI_NAME "dpl_ctrl"
/*
 * Use size of gadget's qti control name. Here currently RMNET and DPL
 * gadget is using QTI as control transport. Hence using RMNET ctrl name
 * (as it is bigger in size) for QTI_CTRL_NAME_LEN.
 */
#define QTI_CTRL_NAME_LEN (sizeof(RMNET_CTRL_QTI_NAME)+2)

struct qti_ctrl_port {
	void		*port_usb;
	char		name[sizeof(RMNET_CTRL_QTI_NAME) + 2];
	char		name[QTI_CTRL_NAME_LEN];
	struct miscdevice ctrl_device;

	bool		is_open;
@@ -122,8 +129,8 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
	memcpy(cpkt->buf, buf, len);
	cpkt->len = len;

	pr_debug("%s: Add to cpkt_req_q packet with len = %zu\n",
			__func__, len);
	pr_debug("%s: gtype:%d: Add to cpkt_req_q packet with len = %zu\n",
			__func__, port->gtype, len);
	spin_lock_irqsave(&port->lock, flags);

	/* drop cpkt if port is not open */
@@ -168,31 +175,23 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
{
	struct qti_ctrl_port	*port;
	struct grmnet *g_rmnet = NULL;
	struct gqdss *g_dpl = NULL;
	unsigned long flags;

	pr_debug("%s: grmnet:%p\n", __func__, gr);
	pr_debug("%s: gtype:%d gadget:%p\n", __func__, gtype, gr);
	if (port_num >= NR_QTI_PORTS) {
		pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
		return -ENODEV;
	}

	if (gtype != USB_GADGET_RMNET) {
		pr_err("%s(): unrecognized gadget type(%d).\n",
						__func__, gtype);
		return -EINVAL;
	}

	port = ctrl_port[port_num];

	if (!gr || !port) {
		pr_err("%s: grmnet port is null\n", __func__);
	if (!port) {
		pr_err("%s: gadget port is null\n", __func__);
		return -ENODEV;
	}


	spin_lock_irqsave(&port->lock, flags);
	port->gtype = gtype;
	port->port_usb = gr;
	if (dxport == USB_GADGET_XPORT_BAM) {
		/*
		 * BAM-DMUX data transport is used for RMNET
@@ -216,16 +215,28 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
		port->intf = intf;
	}

	if (gr && port->gtype == USB_GADGET_RMNET) {
		port->port_usb = gr;
		g_rmnet = (struct grmnet *)gr;
		g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem;
		g_rmnet->notify_modem = gqti_ctrl_notify_modem;
	} else if (gr && port->gtype == USB_GADGET_DPL) {
		port->port_usb = gr;
		g_dpl = (struct gqdss *)gr;
		g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem;
		g_dpl->notify_modem = gqti_ctrl_notify_modem;
		atomic_set(&port->line_state, 1);
	} else {
		spin_unlock_irqrestore(&port->lock, flags);
		pr_err("%s(): Port is used without gtype.\n", __func__);
		return -ENODEV;
	}

	spin_unlock_irqrestore(&port->lock, flags);

	atomic_set(&port->connected, 1);
	wake_up(&port->read_wq);

	if (g_rmnet && g_rmnet->connect)
	if (port->port_usb && g_rmnet && g_rmnet->connect)
		g_rmnet->connect(port->port_usb);

	return 0;
@@ -237,8 +248,9 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
	unsigned long		flags;
	struct rmnet_ctrl_pkt	*cpkt;
	struct grmnet *g_rmnet = NULL;
	struct gqdss *g_dpl = NULL;

	pr_debug("%s: grmnet:%p\n", __func__, gr);
	pr_debug("%s: gadget:%p\n", __func__, gr);

	if (port_num >= NR_QTI_PORTS) {
		pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
@@ -247,20 +259,23 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)

	port = ctrl_port[port_num];

	if (!gr || !port) {
		pr_err("%s: grmnet port is null\n", __func__);
	if (!port) {
		pr_err("%s: gadget port is null\n", __func__);
		return;
	}

	if (port->gtype != USB_GADGET_RMNET) {
	if (gr && (port->gtype == USB_GADGET_RMNET)) {
		g_rmnet = (struct grmnet *)gr;
		g_rmnet->disconnect(port->port_usb);
	} else if (gr && (port->gtype == USB_GADGET_DPL)) {
		g_dpl = (struct gqdss *)gr;
		gqti_ctrl_send_cpkt_tomodem(DPL_QTI_CTRL_PORT_NO, NULL, 0);
	} else {
		pr_err("%s(): unrecognized gadget type(%d).\n",
					__func__, port->gtype);
		return;
	}

	g_rmnet = (struct grmnet *)gr;
	g_rmnet->disconnect(port->port_usb);

	atomic_set(&port->connected, 0);
	atomic_set(&port->line_state, 0);
	spin_lock_irqsave(&port->lock, flags);
@@ -271,6 +286,11 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
		g_rmnet->notify_modem = NULL;
	}

	if (g_dpl) {
		g_dpl->send_encap_cmd = NULL;
		g_dpl->notify_modem = NULL;
	}

	while (!list_empty(&port->cpkt_req_q)) {
		cpkt = list_first_entry(&port->cpkt_req_q,
					struct rmnet_ctrl_pkt, list);
@@ -512,6 +532,11 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)

	switch (cmd) {
	case QTI_CTRL_MODEM_OFFLINE:
		if (port && (port->gtype == USB_GADGET_DPL)) {
			pr_err("%s(): Modem Offline not handled\n", __func__);
			goto exit_ioctl;
		}

		if (port && port->port_usb)
			gr = port->port_usb;

@@ -519,6 +544,11 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
			gr->disconnect(gr);
		break;
	case QTI_CTRL_MODEM_ONLINE:
		if (port && (port->gtype == USB_GADGET_DPL)) {
			pr_err("%s(): Modem Online not handled\n", __func__);
			goto exit_ioctl;
		}

		if (port && port->port_usb)
			gr = port->port_usb;

@@ -536,6 +566,9 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
				atomic_read(&port->line_state), port->gtype);
		break;
	case QTI_CTRL_EP_LOOKUP:

		pr_debug("%s(): EP_LOOKUP for gtype:%d\n", __func__,
							port->gtype);
		val = atomic_read(&port->connected);
		if (!val) {
			pr_err("EP_LOOKUP failed - not connected");
@@ -568,6 +601,7 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
		ret = -EINVAL;
	}

exit_ioctl:
	qti_ctrl_unlock(&port->ioctl_excl);

	return ret;
@@ -611,10 +645,23 @@ static const struct file_operations qti_ctrl_fops = {
#endif
	.poll = qti_ctrl_poll,
};
/* file operations for DPL device /dev/dpl_ctrl */
static const struct file_operations dpl_qti_ctrl_fops = {
	.owner = THIS_MODULE,
	.open = qti_ctrl_open,
	.release = qti_ctrl_release,
	.read = qti_ctrl_read,
	.write = NULL,
	.unlocked_ioctl = qti_ctrl_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = qti_ctrl_ioctl,
#endif
	.poll = qti_ctrl_poll,
};

static int __init gqti_ctrl_init(void)
{
	int ret, i, sz = sizeof(RMNET_CTRL_QTI_NAME)+2;
	int ret, i, sz = QTI_CTRL_NAME_LEN;
	struct qti_ctrl_port *port = NULL;

	for (i = 0; i < NR_QTI_PORTS; i++) {
@@ -644,11 +691,16 @@ static int __init gqti_ctrl_init(void)

		if (i == 0)
			strlcat(port->name, RMNET_CTRL_QTI_NAME, sz);
		else if (i == DPL_QTI_CTRL_PORT_NO)
			strlcat(port->name, DPL_CTRL_QTI_NAME, sz);
		else
			snprintf(port->name, sz, "%s%d",
					RMNET_CTRL_QTI_NAME, i);

		port->ctrl_device.name = port->name;
		if (i == DPL_QTI_CTRL_PORT_NO)
			port->ctrl_device.fops = &dpl_qti_ctrl_fops;
		else
			port->ctrl_device.fops = &qti_ctrl_fops;
		port->ctrl_device.minor = MISC_DYNAMIC_MINOR;

+2 −1
Original line number Diff line number Diff line
@@ -47,8 +47,9 @@ struct grmnet {
	void (*connect)(struct grmnet *g);
};

#define NR_QTI_PORTS	4
#define NR_QTI_PORTS	(NR_RMNET_PORTS + NR_DPL_PORTS)
#define NR_RMNET_PORTS	4
#define NR_DPL_PORTS	1

enum ctrl_client {
	FRMNET_CTRL_CLIENT,
Loading