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

Commit ed0d9679 authored by Hemant Kumar's avatar Hemant Kumar Committed by Devdutt Patnaik
Browse files

usb: gadget: Create supported function list dynamically



If android_usb platform driver passes list of supported
function, create the list of supported functions dynamically.
This allows to create the list specific to a particular target
and avoid allocating and initializing memory for un-needed
function drivers.

Change-Id: I48a67d55265a909a7c711edc7dbb24f9b1830ad2
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent e86d5332
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -28,11 +28,16 @@ Optional properties :
- qcom,usb-core-id: Index to refer USB hardware core to bind android gadget driver
  with UDC if multiple USB peripheral controllers are present. If unspecified,
  core is set to zero by default.
- qcom,supported-func: Represents list of supported function drivers. If this
  property is present android USB driver dynamically creats the list of
  supported function drivers and uses this list instead of statically defined default
  supported function driver list.
Example Android USB device node :
	android_usb@fc42b0c8 {
		compatible = "qcom,android-usb";
		reg = <0xfc42b0c8 0xc8>;
		qcom,pm-qos-latency = <2 1001 12701>;
		qcom,streaming-func = "rndis","mtp";
		qcom,supported-func = "rndis_gsi","ecm_gsi","rmnet_gsi";
		qcom,usb-core-id = <1>;
	};
+71 −3
Original line number Diff line number Diff line
@@ -2833,6 +2833,36 @@ static struct android_usb_function midi_function = {
};
#endif
static struct android_usb_function *supported_functions[] = {
	[ANDROID_FFS] = &ffs_function,
	[ANDROID_MBIM_BAM] = &mbim_function,
	[ANDROID_ECM_BAM] = &ecm_qc_function,
#ifdef CONFIG_SND_PCM
	[ANDROID_AUDIO] = &audio_function,
#endif
	[ANDROID_RMNET] = &rmnet_function,
	[ANDROID_GPS] = &gps_function,
	[ANDROID_DIAG] = &diag_function,
	[ANDROID_QDSS_BAM] = &qdss_function,
	[ANDROID_SERIAL] = &serial_function,
	[ANDROID_CCID] = &ccid_function,
	[ANDROID_ACM] = &acm_function,
	[ANDROID_MTP] = &mtp_function,
	[ANDROID_PTP] = &ptp_function,
	[ANDROID_RNDIS] = &rndis_function,
	[ANDROID_RNDIS_BAM] = &rndis_qc_function,
	[ANDROID_ECM] = &ecm_function,
	[ANDROID_NCM] = &ncm_function,
	[ANDROID_UMS] = &mass_storage_function,
	[ANDROID_ACCESSORY] = &accessory_function,
	[ANDROID_AUDIO_SRC] = &audio_source_function,
	[ANDROID_CHARGER] = &charger_function,
#ifdef CONFIG_SND_RAWMIDI
	[ANDROID_MIDI] = &midi_function,
#endif
	NULL
};

static struct android_usb_function *default_functions[] = {
	&ffs_function,
	&mbim_function,
	&ecm_qc_function,
@@ -3850,6 +3880,7 @@ static int android_probe(struct platform_device *pdev)
{
	struct android_usb_platform_data *pdata;
	struct android_dev *android_dev;
	struct android_usb_function **supported_list = NULL;
	struct resource *res;
	int ret = 0, i, len = 0, prop_len = 0;
	u32 usb_core_id = 0;
@@ -3910,10 +3941,45 @@ static int android_probe(struct platform_device *pdev)
		pdata = pdev->dev.platform_data;
	}

	len = of_property_count_strings(pdev->dev.of_node,
			"qcom,supported-func");
	if (len > ANDROID_MAX_FUNC_CNT) {
		pr_err("Invalid number of functions used.\n");
		return -EINVAL;
	} else if (len > 0) {
		/* one extra for NULL termination */
		supported_list = devm_kzalloc(
				&pdev->dev, sizeof(supported_list) * (len + 1),
				GFP_KERNEL);
		if (!supported_list)
			return -ENOMEM;

		for (i = 0; i < len; i++) {
			const char *name = NULL;

			of_property_read_string_index(pdev->dev.of_node,
				"qcom,supported-func", i, &name);

			if (!name || sizeof(name) > FUNC_NAME_LEN ||
			name_to_func_idx(name) == ANDROID_INVALID_FUNC) {
				pr_err("Invalid Function name %s\n", name);
				ret = -EINVAL;
				goto err;
			}

			supported_list[i] =
				supported_functions[name_to_func_idx(name)];
			pr_debug("name of supported function:%s\n",
				supported_list[i]->name);
		}
	}

	if (!android_class) {
		android_class = class_create(THIS_MODULE, "android_usb");
		if (IS_ERR(android_class))
			return PTR_ERR(android_class);
		if (IS_ERR(android_class)) {
			ret = PTR_ERR(android_class);
			goto err;
		}
	}

	android_dev = kzalloc(sizeof(*android_dev), GFP_KERNEL);
@@ -3926,7 +3992,8 @@ static int android_probe(struct platform_device *pdev)

	android_dev->name = pdev->name;
	android_dev->disable_depth = 1;
	android_dev->functions = supported_functions;
	android_dev->functions =
		supported_list ? supported_list : default_functions;
	android_dev->configs_num = 0;
	INIT_LIST_HEAD(&android_dev->configs);
	INIT_WORK(&android_dev->work, android_work);
@@ -4002,6 +4069,7 @@ err_alloc:
		android_class = NULL;
	}
	debug_debugfs_exit();
err:
	return ret;
}

+81 −1
Original line number Diff line number Diff line
@@ -18,7 +18,87 @@
#define	__LINUX_USB_ANDROID_H

#define MAX_STREAMING_FUNCS 6
#define FUNC_NAME_LEN 10
#define FUNC_NAME_LEN 15

enum android_function_index {
	ANDROID_FFS,
	ANDROID_MBIM_BAM,
	ANDROID_ECM_BAM,
	ANDROID_AUDIO,
	ANDROID_RMNET,
	ANDROID_GPS,
	ANDROID_DIAG,
	ANDROID_QDSS_BAM,
	ANDROID_SERIAL,
	ANDROID_CCID,
	ANDROID_ACM,
	ANDROID_MTP,
	ANDROID_PTP,
	ANDROID_RNDIS,
	ANDROID_RNDIS_BAM,
	ANDROID_ECM,
	ANDROID_NCM,
	ANDROID_UMS,
	ANDROID_ACCESSORY,
	ANDROID_AUDIO_SRC,
	ANDROID_CHARGER,
	ANDROID_MIDI,
	ANDROID_MAX_FUNC_CNT,
	ANDROID_INVALID_FUNC,
};

static enum android_function_index name_to_func_idx(const char *name)
{
	if (!name)
		return ANDROID_INVALID_FUNC;

	if (!strncasecmp("FFS", name, FUNC_NAME_LEN))
		return ANDROID_FFS;
	if (!strncasecmp("USB_MBIM", name, FUNC_NAME_LEN))
		return ANDROID_MBIM_BAM;
	if (!strncasecmp("ECM_QC", name, FUNC_NAME_LEN))
		return ANDROID_ECM_BAM;
	if (!strncasecmp("AUDIO", name, FUNC_NAME_LEN))
		return ANDROID_AUDIO;
	if (!strncasecmp("RMNET", name, FUNC_NAME_LEN))
		return ANDROID_RMNET;
	if (!strncasecmp("GPS", name, FUNC_NAME_LEN))
		return ANDROID_GPS;
	if (!strncasecmp("DIAG", name, FUNC_NAME_LEN))
		return ANDROID_DIAG;
	if (!strncasecmp("QDSS", name, FUNC_NAME_LEN))
		return ANDROID_QDSS_BAM;
	if (!strncasecmp("SERIAL", name, FUNC_NAME_LEN))
		return ANDROID_SERIAL;
	if (!strncasecmp("CCID", name, FUNC_NAME_LEN))
		return ANDROID_CCID;
	if (!strncasecmp("ACM", name, FUNC_NAME_LEN))
		return ANDROID_ACM;
	if (!strncasecmp("MTP", name, FUNC_NAME_LEN))
		return ANDROID_MTP;
	if (!strncasecmp("PTP", name, FUNC_NAME_LEN))
		return ANDROID_PTP;
	if (!strncasecmp("RNDIS", name, FUNC_NAME_LEN))
		return ANDROID_RNDIS;
	if (!strncasecmp("RNDIS_QC", name, FUNC_NAME_LEN))
		return ANDROID_RNDIS_BAM;
	if (!strncasecmp("ECM", name, FUNC_NAME_LEN))
		return ANDROID_ECM;
	if (!strncasecmp("NCM", name, FUNC_NAME_LEN))
		return ANDROID_NCM;
	if (!strncasecmp("MASS_STORAGE", name, FUNC_NAME_LEN))
		return ANDROID_UMS;
	if (!strncasecmp("ACCESSORY", name, FUNC_NAME_LEN))
		return ANDROID_ACCESSORY;
	if (!strncasecmp("AUDIO_SOURCE", name, FUNC_NAME_LEN))
		return ANDROID_AUDIO_SRC;
	if (!strncasecmp("CHARGING", name, FUNC_NAME_LEN))
		return ANDROID_AUDIO_SRC;
	if (!strncasecmp("MIDI", name, FUNC_NAME_LEN))
		return ANDROID_MIDI;

	return ANDROID_INVALID_FUNC;
}

enum android_pm_qos_state {
	WFI,