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

Commit 594f8926 authored by Mayank Rana's avatar Mayank Rana
Browse files

USB: android: Add support to enumerate multiple LUNs



This change allows user space to pass type of extra LUNs to enumerate
with Mass Storage driver. By default, "lun" is created for external
SD Card related mass storage functionality.  Currently "disk" is
referring storage device whereas "rom" is referring CD ROM device when
used with sysfs entry related to f_mass_storage. This change helps to
avoid usage of any platform data to control LUNs enumeration. Hence
remove pdata related to cdrom LUN passed usign DT.

e.g.
echo disk > /sys/class/android_usb/android0/f_mass_storage/luns
echo disk,disk > /sys/class/android_usb/android0/f_mass_storage/luns
echo disk,rom > /sys/class/android_usb/android0/f_mass_storage/luns

CRs-Fixed: 526542
Change-Id: I52984db8c08654e014a6a9e7e91b964ee409a532
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent d80c39cd
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -181,10 +181,6 @@ Optional properties :
  update USB PID and serial numbers used by bootloader in DLOAD mode.
- qcom,android-usb-swfi-latency : value to be used by device to vote
  for DMA latency in microsecs.
- qcom,android-usb-cdrom : if this property is present then device creates
  a new LUN as CD-ROM
- qcom,android-usb-internal-ums : if this property is present then device
  creates a new LUN as internal usb mass storage
Example Android USB device node :
	android_usb@fc42b0c8 {
		compatible = "qcom,android-usb";
+0 −5
Original line number Diff line number Diff line
@@ -487,11 +487,6 @@
	};
};

&android_usb {
	qcom,android-usb-cdrom;
	qcom,android-usb-internal-ums;
};

&mdss_mdp {
	qcom,mdss-pref-prim-intf = "dsi";
	batfet-supply = <&pm8226_chg_batif>;
+126 −24
Original line number Diff line number Diff line
@@ -2011,6 +2011,8 @@ static struct android_usb_function ecm_function = {
	.attributes	= ecm_function_attributes,
};

#define MAX_LUN_STR_LEN 25
static char lun_info[MAX_LUN_STR_LEN] = {'\0'};
struct mass_storage_function_config {
	struct fsg_config fsg;
	struct fsg_common *common;
@@ -2019,7 +2021,6 @@ struct mass_storage_function_config {
static int mass_storage_function_init(struct android_usb_function *f,
					struct usb_composite_dev *cdev)
{
	struct android_dev *dev = cdev_to_android_dev(cdev);
	struct mass_storage_function_config *config;
	struct fsg_common *common;
	int err;
@@ -2028,26 +2029,13 @@ static int mass_storage_function_init(struct android_usb_function *f,

	config = kzalloc(sizeof(struct mass_storage_function_config),
							GFP_KERNEL);
	if (!config)
	if (!config) {
		pr_err("Memory allocation failed.\n");
		return -ENOMEM;
	}

	config->fsg.nluns = 1;
	name[0] = "lun";
	if (dev->pdata && dev->pdata->cdrom) {
		config->fsg.luns[config->fsg.nluns].cdrom = 1;
		config->fsg.luns[config->fsg.nluns].ro = 1;
		config->fsg.luns[config->fsg.nluns].removable = 0;
		name[config->fsg.nluns] = "lun0";
		config->fsg.nluns++;
	}
	if (dev->pdata && dev->pdata->internal_ums) {
		config->fsg.luns[config->fsg.nluns].cdrom = 0;
		config->fsg.luns[config->fsg.nluns].ro = 0;
		config->fsg.luns[config->fsg.nluns].removable = 1;
		name[config->fsg.nluns] = "lun1";
		config->fsg.nluns++;
	}

	config->fsg.luns[0].removable = 1;

	common = fsg_common_init(NULL, cdev, &config->fsg);
@@ -2076,17 +2064,115 @@ error:
	return err;
}

static int mass_storage_lun_init(struct android_usb_function *f,
						char *lun_info)
{
	struct mass_storage_function_config *config = f->config;
	bool inc_lun = true;
	int i = config->fsg.nluns, index, length;
	static int number_of_luns;

	length = strlen(lun_info);
	if (!length) {
		pr_err("LUN_INFO is null.\n");
		return -EINVAL;
	}

	index = i + number_of_luns;
	if (index >= FSG_MAX_LUNS) {
		pr_err("Number of LUNs exceed the limit.\n");
		return -EINVAL;
	}

	if (!strcmp(lun_info, "disk")) {
		config->fsg.luns[index].removable = 1;
	} else if (!strcmp(lun_info, "rom")) {
		config->fsg.luns[index].cdrom = 1;
		config->fsg.luns[index].removable = 0;
		config->fsg.luns[index].ro = 1;
	} else {
		pr_err("Invalid LUN info.\n");
		inc_lun = false;
		return -EINVAL;
	}

	if (inc_lun)
		number_of_luns++;

	pr_debug("number_of_luns:%d\n", number_of_luns);
	return number_of_luns;
}

static void mass_storage_function_cleanup(struct android_usb_function *f)
{
	kfree(f->config);
	f->config = NULL;
}

static void mass_storage_function_enable(struct android_usb_function *f)
{
	struct usb_composite_dev *cdev = f->android_dev->cdev;
	struct mass_storage_function_config *config = f->config;
	struct fsg_common *common = config->common;
	char *lun_type;
	int i, err;
	char buf[MAX_LUN_STR_LEN], *b;
	int number_of_luns = 0;
	char buf1[5];
	char *lun_name = buf1;
	static int msc_initialized;

	if (msc_initialized)
		return;

	if (lun_info[0] != '\0') {
		strlcpy(buf, lun_info, sizeof(buf));
		b = strim(buf);

		while (b) {
			lun_type = strsep(&b, ",");
			if (lun_type)
				number_of_luns =
					mass_storage_lun_init(f, lun_type);
				if (number_of_luns <= 0)
					return;
		}
	} else {
		pr_debug("No extra msc lun required.\n");
		return;
	}

	err = fsg_add_lun(common, cdev, &config->fsg, number_of_luns);
	if (err) {
		pr_err("Failed adding LUN.\n");
		return;
	}

	pr_debug("fsg.nluns:%d\n", config->fsg.nluns);
	for (i = 1; i < config->fsg.nluns; i++) {
		snprintf(lun_name, sizeof(buf), "lun%d", (i-1));
		pr_debug("sysfs: LUN name:%s\n", lun_name);
		err = sysfs_create_link(&f->dev->kobj,
			&common->luns[i].dev.kobj, lun_name);
		if (err)
			pr_err("sysfs file creation failed: lun%d err:%d\n",
								i, err);
	}

	msc_initialized = 1;
}

static int mass_storage_function_bind_config(struct android_usb_function *f,
						struct usb_configuration *c)
{
	struct mass_storage_function_config *config = f->config;
	return fsg_bind_config(c->cdev, c, config->common);
	int ret;

	ret = fsg_bind_config(c->cdev, c, config->common);
	if (ret)
		pr_err("fsg_bind_config failed. ret:%x\n", ret);

	return ret;
}

static ssize_t mass_storage_inquiry_show(struct device *dev,
@@ -2113,8 +2199,27 @@ static DEVICE_ATTR(inquiry_string, S_IRUGO | S_IWUSR,
					mass_storage_inquiry_show,
					mass_storage_inquiry_store);

static ssize_t mass_storage_lun_info_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{

	return snprintf(buf, PAGE_SIZE, "%s\n", lun_info);
}

static ssize_t mass_storage_lun_info_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	strlcpy(lun_info, buf, sizeof(lun_info));
	return size;
}

static DEVICE_ATTR(luns, S_IRUGO | S_IWUSR,
				mass_storage_lun_info_show,
				mass_storage_lun_info_store);

static struct device_attribute *mass_storage_function_attributes[] = {
	&dev_attr_inquiry_string,
	&dev_attr_luns,
	NULL
};

@@ -2124,6 +2229,7 @@ static struct android_usb_function mass_storage_function = {
	.cleanup	= mass_storage_function_cleanup,
	.bind_config	= mass_storage_function_bind_config,
	.attributes	= mass_storage_function_attributes,
	.enable		= mass_storage_function_enable,
};


@@ -3177,10 +3283,6 @@ static int android_probe(struct platform_device *pdev)
		of_property_read_u32(pdev->dev.of_node,
				"qcom,android-usb-swfi-latency",
				&pdata->swfi_latency);
		pdata->cdrom = of_property_read_bool(pdev->dev.of_node,
				"qcom,android-usb-cdrom");
		pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
				"qcom,android-usb-internal-ums");
	} else {
		pdata = pdev->dev.platform_data;
	}
+120 −57
Original line number Diff line number Diff line
@@ -2764,6 +2764,97 @@ static inline void fsg_common_put(struct fsg_common *common)
	kref_put(&common->ref, fsg_common_release);
}

/*
 * This function creates device entry for LUN and its related paramters.
*/
static int create_lun_device(struct fsg_common *common,
				struct usb_composite_dev *cdev,
				struct fsg_config *cfg,
				int add_lun_index)
{
	struct usb_gadget *gadget = cdev->gadget;
	struct fsg_lun *curlun = common->luns;
	struct fsg_lun_config *lcfg = cfg->luns;
	int rc = 0, i;
	int nluns = cfg->nluns;

	/*
	 * Check if index is non-zero, increment current lun_config
	 * and cur_lun pointers.
	 */
	if (add_lun_index) {
		lcfg++;
		curlun++;
	}

	for (i = add_lun_index; i < nluns; ++i, ++curlun, ++lcfg) {
		curlun->cdrom = !!lcfg->cdrom;
		curlun->ro = lcfg->cdrom || lcfg->ro;
		curlun->initially_ro = curlun->ro;
		curlun->removable = lcfg->removable;
		curlun->nofua = lcfg->nofua;
		curlun->dev.release = fsg_lun_release;
		curlun->dev.parent = &gadget->dev;
		/* curlun->dev.driver = &fsg_driver.driver; XXX */
		dev_set_drvdata(&curlun->dev, &common->filesem);
		dev_set_name(&curlun->dev, "lun%d", i);

		rc = device_register(&curlun->dev);
		if (rc) {
			pr_err("failed to register LUN%d: %d\n", i, rc);
			common->nluns = i;
			put_device(&curlun->dev);
			goto error_release;
		}

		rc = device_create_file(&curlun->dev,
					curlun->cdrom
				      ? &dev_attr_ro_cdrom
				      : &dev_attr_ro);
		if (rc)
			goto error_luns;

		rc = device_create_file(&curlun->dev,
					curlun->removable
				      ? &dev_attr_file
				      : &dev_attr_file_nonremovable);
		if (rc)
			goto error_luns;

		rc = device_create_file(&curlun->dev, &dev_attr_nofua);
		if (rc)
			goto error_luns;

#ifdef CONFIG_USB_MSC_PROFILING
		rc = device_create_file(&curlun->dev, &dev_attr_perf);
		if (rc)
			pr_err("failed to create perf sysfs node:%d\n", rc);
#endif
		if (lcfg->filename) {
			rc = fsg_lun_open(curlun, lcfg->filename);
			if (rc) {
				pr_err("failed to open lun file.\n");
				goto error_luns;
			}
		} else if (!curlun->removable && !curlun->cdrom) {
			ERROR(common, "no file given for LUN%d\n", i);
			rc = -EINVAL;
			goto error_luns;
		}
	}

	common->nluns = nluns;
	return rc;

error_luns:
	common->nluns = i;
error_release:
	common->state = FSG_STATE_TERMINATED;
	fsg_common_release(&common->ref);

	return rc;
}

static struct fsg_common *fsg_common_init(struct fsg_common *common,
					  struct usb_composite_dev *cdev,
					  struct fsg_config *cfg)
@@ -2771,7 +2862,6 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
	struct usb_gadget *gadget = cdev->gadget;
	struct fsg_buffhd *bh;
	struct fsg_lun *curlun;
	struct fsg_lun_config *lcfg;
	int nluns, i, rc;
	char *pathbuf;

@@ -2817,7 +2907,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
	 * Create the LUNs, open their backing files, and register the
	 * LUN devices in sysfs.
	 */
	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
	curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL);
	if (unlikely(!curlun)) {
		rc = -ENOMEM;
		goto error_release;
@@ -2825,59 +2915,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
	common->luns = curlun;

	init_rwsem(&common->filesem);

	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
		curlun->cdrom = !!lcfg->cdrom;
		curlun->ro = lcfg->cdrom || lcfg->ro;
		curlun->initially_ro = curlun->ro;
		curlun->removable = lcfg->removable;
		curlun->nofua = lcfg->nofua;
		curlun->dev.release = fsg_lun_release;
		curlun->dev.parent = &gadget->dev;
		/* curlun->dev.driver = &fsg_driver.driver; XXX */
		dev_set_drvdata(&curlun->dev, &common->filesem);
		dev_set_name(&curlun->dev, "lun%d", i);

		rc = device_register(&curlun->dev);
		if (rc) {
			INFO(common, "failed to register LUN%d: %d\n", i, rc);
			common->nluns = i;
			put_device(&curlun->dev);
			goto error_release;
		}

		rc = device_create_file(&curlun->dev,
					curlun->cdrom
				      ? &dev_attr_ro_cdrom
				      : &dev_attr_ro);
		if (rc)
			goto error_luns;
		rc = device_create_file(&curlun->dev,
					curlun->removable
				      ? &dev_attr_file
				      : &dev_attr_file_nonremovable);
		if (rc)
			goto error_luns;
		rc = device_create_file(&curlun->dev, &dev_attr_nofua);
		if (rc)
			goto error_luns;
#ifdef CONFIG_USB_MSC_PROFILING
		rc = device_create_file(&curlun->dev, &dev_attr_perf);
		if (rc)
			dev_err(&gadget->dev, "failed to create sysfs entry:"
				"(dev_attr_perf) error: %d\n", rc);
#endif
		if (lcfg->filename) {
			rc = fsg_lun_open(curlun, lcfg->filename);
			if (rc)
				goto error_luns;
		} else if (!curlun->removable && !curlun->cdrom) {
			ERROR(common, "no file given for LUN%d\n", i);
			rc = -EINVAL;
			goto error_luns;
		}
	}
	common->nluns = nluns;
	rc = create_lun_device(common, cdev, cfg, 0);
	if (rc != 0)
		goto error;

	/* Data buffers cyclic list */
	bh = common->buffhds;
@@ -2958,12 +2998,11 @@ buffhds_first_it:

	return common;

error_luns:
	common->nluns = i + 1;
error_release:
	common->state = FSG_STATE_TERMINATED;	/* The thread is dead */
	/* Call fsg_common_release() directly, ref might be not initialised. */
	fsg_common_release(&common->ref);
error:
	return ERR_PTR(rc);
}

@@ -3237,3 +3276,27 @@ fsg_common_from_params(struct fsg_common *common,
	fsg_config_from_params(&cfg, params);
	return fsg_common_init(common, cdev, &cfg);
}

/*
 * This API allows to add luns devices when MSC is being enabled.
 */
static int fsg_add_lun(struct fsg_common *common,
			struct usb_composite_dev *cdev,
			struct fsg_config *cfg,
			int add_luns)
{
	int nluns, rc = 0;
	int total_luns;

	if (add_luns) {
		nluns = common->nluns;
		total_luns = nluns + add_luns;
		pr_debug("total_luns:%d\n", total_luns);
		cfg->nluns = total_luns;
		rc = create_lun_device(common, cdev, cfg, nluns);
		if (rc)
			pr_err("Failed device lun creation.\n");
	}

	return rc;
}
+0 −2
Original line number Diff line number Diff line
@@ -23,8 +23,6 @@ struct android_usb_platform_data {
	int (*update_pid_and_serial_num)(uint32_t, const char *);
	u32 swfi_latency;
	u8 usb_core_id;
	bool cdrom;
	bool internal_ums;
};

#ifndef CONFIG_TARGET_CORE