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

Commit b2b0da54 authored by Manu Gautam's avatar Manu Gautam
Browse files

usb: gadget: android: Add serial function support in 2nd config



Serial function driver is used for DUN/MODEM and NMEA use-cases
and it uses various transports as well e.g. tty, smd and
char-bridge. Current design allow Serial function to be present
only in one configuration at a time. Add another instance of
serial function that re-uses transports from first instance
of serial instance and allows to have serial function in
second configuration as well.

Change-Id: I09340ea04da32c7935462295f302a8d4a520b4da
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent c294345c
Loading
Loading
Loading
Loading
+25 −10
Original line number Diff line number Diff line
@@ -1971,6 +1971,7 @@ static struct android_usb_function qdss_function = {
#define MAX_SERIAL_INSTANCES 4
struct serial_function_config {
	int instances_on;
	bool serial_initialized;
	struct usb_function *f_serial[MAX_SERIAL_INSTANCES];
	struct usb_function_instance *f_serial_inst[MAX_SERIAL_INSTANCES];
};
@@ -2097,8 +2098,9 @@ static int serial_function_bind_config(struct android_usb_function *f,
	char *name, *xport_name = NULL;
	char buf[32], *b, xport_name_buf[32], *tb;
	int err = -1, i, ports = 0;
	static int serial_initialized;
	struct serial_function_config *config = f->config;
	static bool transports_initialized;

	strlcpy(buf, serial_transports, sizeof(buf));
	b = strim(buf);

@@ -2111,7 +2113,7 @@ static int serial_function_bind_config(struct android_usb_function *f,
		if (name) {
			if (tb)
				xport_name = strsep(&tb, ",");
			if (!serial_initialized) {
			if (!config->serial_initialized) {
				err = gserial_init_port(ports, name,
						xport_name);
				if (err) {
@@ -2133,7 +2135,7 @@ static int serial_function_bind_config(struct android_usb_function *f,
	 * switching composition from 1 serial function to 2 serial functions.
	 * Mark 2nd port to use tty if user didn't specify transport.
	 */
	if ((config->instances_on == 1) && !serial_initialized) {
	if ((config->instances_on == 1) && !config->serial_initialized) {
		err = gserial_init_port(ports, "tty", "serial_tty");
		if (err) {
			pr_err("serial: Cannot open port '%s'", "tty");
@@ -2146,15 +2148,19 @@ static int serial_function_bind_config(struct android_usb_function *f,
	if (ports > config->instances_on)
		ports = config->instances_on;

	if (serial_initialized)
	if (config->serial_initialized)
		goto bind_config;

	if (!transports_initialized) {
		err = gport_setup(c);
		if (err) {
			pr_err("serial: Cannot setup transports");
			gserial_deinit_port();
			goto out;
		}
		/* transports are initialized once and shared across configs */
		transports_initialized = true;
	}

	for (i = 0; i < config->instances_on; i++) {
		config->f_serial_inst[i] = usb_get_function_instance("gser");
@@ -2169,7 +2175,7 @@ static int serial_function_bind_config(struct android_usb_function *f,
		}
	}

	serial_initialized = 1;
	config->serial_initialized = true;

bind_config:
	for (i = 0; i < ports; i++) {
@@ -2206,6 +2212,13 @@ static struct android_usb_function serial_function = {
	.attributes	= serial_function_attributes,
};

static struct android_usb_function serial_function_config2 = {
	.name		= "serial_config2",
	.init		= serial_function_init,
	.cleanup	= serial_function_cleanup,
	.bind_config	= serial_function_bind_config,
};

/* CCID */
static int ccid_function_init(struct android_usb_function *f,
					struct usb_composite_dev *cdev)
@@ -3282,6 +3295,7 @@ static struct android_usb_function *supported_functions[] = {
	[ANDROID_DIAG] = &diag_function,
	[ANDROID_QDSS_BAM] = &qdss_function,
	[ANDROID_SERIAL] = &serial_function,
	[ANDROID_SERIAL_CONFIG2] = &serial_function_config2,
	[ANDROID_CCID] = &ccid_function,
	[ANDROID_ACM] = &acm_function,
	[ANDROID_MTP] = &mtp_function,
@@ -3321,6 +3335,7 @@ static struct android_usb_function *default_functions[] = {
	&diag_function,
	&qdss_function,
	&serial_function,
	&serial_function_config2,
	&ccid_function,
	&acm_function,
	&mtp_function,
+45 −12
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
 * Copyright (C) 2008 by David Brownell
 * Copyright (C) 2008 by Nokia Corporation
 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
 *
 * This software is distributed under the terms of the GNU General
 * Public License ("GPL") as published by the Free Software Foundation,
@@ -44,7 +44,7 @@
#define GSERIAL_SET_XPORT_TYPE_SMD 1

#define GSERIAL_BUF_LEN  256
#define GSERIAL_NO_PORTS 3
#define GSERIAL_NO_PORTS 6

struct ioctl_smd_write_arg_type {
	char		*buf;
@@ -1176,27 +1176,57 @@ int gserial_init_port(int port_num, const char *name,
{
	enum transport_type transport;
	int ret = 0;
	bool reuse_transports_for_config2 = false;
	u8 client_port_num;

	transport = str_to_xport(name);

	/* port_num is reset by gadget when initializing ports in 2nd config */
	if (port_num < nr_ports) {
		/* ports in different configurations share same transport */
		transport = gserial_ports[port_num].transport;
		reuse_transports_for_config2 = true;
		/* Skip ports already claimed by previous configuration */
		port_num += nr_ports;
	}

	if (port_num >= GSERIAL_NO_PORTS)
		return -ENODEV;

	transport = str_to_xport(name);
	pr_debug("%s, port:%d, transport:%s\n", __func__,
			port_num, xport_to_str(transport));
	pr_debug("%s: nr_ports:%d, port:%d, transport:%s\n", __func__,
				nr_ports, port_num, xport_to_str(transport));

	gserial_ports[port_num].transport = transport;
	gserial_ports[port_num].port_num = port_num;

	switch (transport) {
	case USB_GADGET_XPORT_TTY:
		if (!reuse_transports_for_config2)
			no_tty_ports++;
		break;
	case USB_GADGET_XPORT_SMD:
		gserial_ports[port_num].client_port_num = no_smd_ports;
		if (reuse_transports_for_config2) {
			client_port_num =
			     gserial_ports[port_num - nr_ports].client_port_num;
		} else {
			client_port_num = no_smd_ports;
		}
		gserial_ports[port_num].client_port_num = client_port_num;
		/* transport port is shared between different configurations */
		if (!reuse_transports_for_config2)
			no_smd_ports++;
		break;
	case USB_GADGET_XPORT_CHAR_BRIDGE:
		gserial_ports[port_num].client_port_num = no_char_bridge_ports;
		if (reuse_transports_for_config2) {
			client_port_num =
			     gserial_ports[port_num - nr_ports].client_port_num;
		} else {
			client_port_num = no_char_bridge_ports;
		}

		gserial_ports[port_num].client_port_num = client_port_num;
		/* transport port is shared between different configurations */
		if (!reuse_transports_for_config2)
			no_char_bridge_ports++;
		break;
	case USB_GADGET_XPORT_HSIC:
@@ -1204,6 +1234,7 @@ int gserial_init_port(int port_num, const char *name,
		ghsic_data_set_port_name(port_name, name);

		/*client port number will be updated in gport_setup*/
		if (!reuse_transports_for_config2)
			no_hsic_sports++;
		break;
	default:
@@ -1212,6 +1243,8 @@ int gserial_init_port(int port_num, const char *name,
		return -ENODEV;
	}

	/* transport ports are shared between different configurations */
	if (!reuse_transports_for_config2)
		nr_ports++;

	return ret;
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ enum android_function_index {
	ANDROID_DIAG,
	ANDROID_QDSS_BAM,
	ANDROID_SERIAL,
	ANDROID_SERIAL_CONFIG2,
	ANDROID_CCID,
	ANDROID_ACM,
	ANDROID_MTP,
@@ -74,6 +75,8 @@ static enum android_function_index name_to_func_idx(const char *name)
		return ANDROID_QDSS_BAM;
	if (!strncasecmp("SERIAL", name, FUNC_NAME_LEN))
		return ANDROID_SERIAL;
	if (!strncasecmp("SERIAL_CONFIG2", name, FUNC_NAME_LEN))
		return ANDROID_SERIAL_CONFIG2;
	if (!strncasecmp("CCID", name, FUNC_NAME_LEN))
		return ANDROID_CCID;
	if (!strncasecmp("ACM", name, FUNC_NAME_LEN))