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

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

USB: mass_storage: Fix mass storage LUN creation with Android gadget



Mass storage driver has changed in terms of its usage due to moving
with configfs functionality. This change adds minimum LUN creation
functionality in order to work with Android gadget driver. It also
adds support to create sysfs entry to access created LUN.

Android gadget driver is not having any requirement to use more than
one instance of mass storage driver as one instance of mass storage
driver supports 8 LUNS. Hence move to creating and using one instance
of USB mass storage driver.

Change-Id: I1c2655da1cac069abce679ca3b969e264edf0b09
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
[jackp@codeaurora.org: Also convert android.c to use the
 USB_FUNCTION API of the mass_storage driver]
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 041ad2ee
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -417,6 +417,8 @@ config USB_G_ANDROID
	select USB_LIBCOMPOSITE
	select USB_F_FS
	select USB_U_SERIAL
	select USB_F_MASS_STORAGE
	select SND_PCM
	help
	  The Android Composite Gadget supports multiple USB
	  functions: adb, acm, mass storage, mtp, accessory
+120 −26
Original line number Diff line number Diff line
@@ -32,13 +32,15 @@

#include "u_fs.h"
#include "f_diag.c"
#include "f_mass_storage.c"
#include "f_mtp.c"
#include "f_accessory.c"
#define USB_ETH_RNDIS y
#include "f_rndis.c"
#include "rndis.c"
#include "u_ether.c"
#include "f_mass_storage.h"

USB_ETHERNET_MODULE_PARAMETERS();

MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -668,7 +670,7 @@ rndis_function_bind_config(struct android_usb_function *f,
		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);

	dev = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
	dev = gether_setup_name(c->cdev->gadget,dev_addr, host_addr, rndis->ethaddr, qmult, "rndis");
	if (IS_ERR(dev)) {
		ret = PTR_ERR(dev);
		pr_err("%s: gether_setup failed\n", __func__);
@@ -819,55 +821,143 @@ static struct android_usb_function rndis_function = {


struct mass_storage_function_config {
	struct fsg_config fsg;
	struct fsg_common *common;
	struct usb_function *f_ms;
	struct usb_function_instance *f_ms_inst;
	char inquiry_string[INQUIRY_MAX_LEN];
};

static int mass_storage_function_init(struct android_usb_function *f,
					struct usb_composite_dev *cdev)
{
	struct mass_storage_function_config *config;
	struct fsg_common *common;
	int err;
	int ret;

	pr_debug("%s(): Inside\n", __func__);
	config = kzalloc(sizeof(struct mass_storage_function_config),
								GFP_KERNEL);
	if (!config)
		return -ENOMEM;
	f->config = config;

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

	common = fsg_common_init(NULL, cdev, &config->fsg);
	if (IS_ERR(common)) {
		kfree(config);
		return PTR_ERR(common);
	config->f_ms_inst = usb_get_function_instance("mass_storage");
	if (IS_ERR(config->f_ms_inst)) {
		ret = PTR_ERR(config->f_ms_inst);
		goto err_usb_get_function_instance;
	}

	err = sysfs_create_link(&f->dev->kobj,
				&common->luns[0].dev.kobj,
				"lun");
	if (err) {
		kfree(config);
		return err;
	config->f_ms = usb_get_function(config->f_ms_inst);
	if (IS_ERR(config->f_ms)) {
		ret = PTR_ERR(config->f_ms);
		goto err_usb_get_function;
	}

	config->common = common;
	f->config = config;
	return 0;

err_usb_get_function:
	usb_put_function_instance(config->f_ms_inst);

err_usb_get_function_instance:
	return ret;
}

static void mass_storage_function_cleanup(struct android_usb_function *f)
{
	struct mass_storage_function_config *config = f->config;

	pr_debug("%s(): Inside\n", __func__);
	usb_put_function(config->f_ms);
	usb_put_function_instance(config->f_ms_inst);
	kfree(f->config);
	f->config = NULL;
}

#ifdef CONFIG_USB_GADGET_DEBUG_FILES
static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
#else
#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);

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 = 0;
	int i;
	struct fsg_opts *fsg_opts;
	struct fsg_config m_config;

	ret = usb_add_function(c, config->f_ms);
	if (ret) {
		pr_err("Could not bind ms%u config\n", i);
		goto err_usb_add_function;
	}

	fsg_mod_data.removable[0] = true;
	fsg_config_from_params(&m_config, &fsg_mod_data, fsg_num_buffers);
	fsg_opts = fsg_opts_from_func_inst(config->f_ms_inst);
	fsg_opts->no_configfs = true;
	ret = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers);
	if (ret) {
		pr_err("%s(): error(%d) for fsg_common_set_num_buffers\n",
						__func__, ret);
		goto err_set_num_buffers;
	}

	ret = fsg_common_set_nluns(fsg_opts->common, m_config.nluns);
	if (ret) {
		pr_err("%s(): error(%d) for fsg_common_set_nluns\n",
						__func__, ret);
		goto err_set_nluns;
	}

	ret = fsg_common_set_cdev(fsg_opts->common, c->cdev,
						m_config.can_stall);
	if (ret) {
		pr_err("%s(): error(%d) for fsg_common_set_cdev\n",
						__func__, ret);
		goto err_set_cdev;
	}

	fsg_common_set_sysfs(fsg_opts->common, true);
	ret = fsg_common_create_luns(fsg_opts->common, &m_config);
	if (ret) {
		pr_err("%s(): error(%d) for fsg_common_create_luns\n",
						__func__, ret);
		goto err_create_luns;
	}

	/* use default one currently */
	fsg_common_set_inquiry_string(fsg_opts->common, m_config.vendor_name,
							m_config.product_name);

	ret = fsg_sysfs_update(fsg_opts->common, f->dev, true);
	if (ret)
		pr_err("%s(): error(%d) for creating sysfs\n", __func__, ret);

	return 0;

err_create_luns:
err_set_cdev:
	fsg_common_free_luns(fsg_opts->common);
err_set_nluns:
	fsg_common_free_buffers(fsg_opts->common);
err_set_num_buffers:
	usb_remove_function(c, config->f_ms);

err_usb_add_function:
	return ret;
}

static void mass_storage_function_unbind_config(struct android_usb_function *f,
					       struct usb_configuration *c)
{
	struct fsg_opts *fsg_opts;
	struct mass_storage_function_config *config = f->config;

	fsg_opts = fsg_opts_from_func_inst(config->f_ms_inst);
	fsg_sysfs_update(fsg_opts->common, f->dev, false);
	fsg_common_free_luns(fsg_opts->common);
}

static ssize_t mass_storage_inquiry_show(struct device *dev,
@@ -875,7 +965,8 @@ static ssize_t mass_storage_inquiry_show(struct device *dev,
{
	struct android_usb_function *f = dev_get_drvdata(dev);
	struct mass_storage_function_config *config = f->config;
	return sprintf(buf, "%s\n", config->common->inquiry_string);

	return snprintf(buf, PAGE_SIZE, "%s\n", config->inquiry_string);
}

static ssize_t mass_storage_inquiry_store(struct device *dev,
@@ -883,10 +974,13 @@ static ssize_t mass_storage_inquiry_store(struct device *dev,
{
	struct android_usb_function *f = dev_get_drvdata(dev);
	struct mass_storage_function_config *config = f->config;
	if (size >= sizeof(config->common->inquiry_string))

	if (size >= sizeof(config->inquiry_string))
		return -EINVAL;
	if (sscanf(buf, "%s", config->common->inquiry_string) != 1)

	if (sscanf(buf, "%28s", config->inquiry_string) != 1)
		return -EINVAL;

	return size;
}

+40 −6
Original line number Diff line number Diff line
@@ -312,12 +312,9 @@ struct fsg_common {
	/* Gadget's private data. */
	void			*private_data;

	/*
	 * Vendor (8 chars), product (16 chars), release (4
	 * hexadecimal digits) and NUL byte
	 */
	char inquiry_string[8 + 16 + 4 + 1];

	char inquiry_string[INQUIRY_MAX_LEN];
	/* LUN name for sysfs purpose */
	char name[FSG_MAX_LUNS][LUN_NAME_LEN];
	struct kref		ref;
};

@@ -3093,6 +3090,43 @@ static void fsg_common_release(struct kref *ref)
		kfree(common);
}

int fsg_sysfs_update(struct fsg_common *common, struct device *dev, bool create)
{
	int ret = 0, i;

	pr_debug("%s(): common->nluns:%d\n", __func__, common->nluns);
	if (create) {
		for (i = 0; i < common->nluns; i++) {
			if (i == 0)
				snprintf(common->name[i], 8, "lun");
			else
				snprintf(common->name[i], 8, "lun%d", i-1);
			ret = sysfs_create_link(&dev->kobj,
					&common->luns[i]->dev.kobj,
					common->name[i]);
			if (ret) {
				pr_err("%s(): failed creating sysfs:%d %s)\n",
						__func__, i, common->name[i]);
				goto remove_sysfs;
			}
		}
	} else {
		i = common->nluns;
		goto remove_sysfs;
	}

	return 0;

remove_sysfs:
	for (; i > 0; i--) {
		pr_debug("%s(): delete sysfs for lun(id:%d)(name:%s)\n",
					__func__, i, common->name[i-1]);
		sysfs_remove_link(&dev->kobj, common->name[i-1]);
	}

	return ret;
}
EXPORT_SYMBOL(fsg_sysfs_update);

/*-------------------------------------------------------------------------*/

+2 −1
Original line number Diff line number Diff line
@@ -162,5 +162,6 @@ int fsg_common_run_thread(struct fsg_common *common);
void fsg_config_from_params(struct fsg_config *cfg,
			    const struct fsg_module_parameters *params,
			    unsigned int fsg_num_buffers);

int fsg_sysfs_update(struct fsg_common *common, struct device *dev,
				bool create);
#endif /* USB_F_MASS_STORAGE_H */
+6 −0
Original line number Diff line number Diff line
@@ -124,6 +124,12 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)

/* Maximal number of LUNs supported in mass storage function */
#define FSG_MAX_LUNS	8
/*
 * Vendor (8 chars), product (16 chars), release (4 hexadecimal
 * digits) and NULL byte
 */
#define INQUIRY_MAX_LEN	29
#define LUN_NAME_LEN	8

enum fsg_buffer_state {
	BUF_STATE_EMPTY = 0,