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

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

Merge "USB: android: Add support to enumerate multiple LUNs"

parents e757b761 594f8926
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