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

Commit 481e4929 authored by Michal Nazarewicz's avatar Michal Nazarewicz Committed by Greg Kroah-Hartman
Browse files

USB: g_mass_storage: fsg_config added & module params handlig changed



Removed all references to mod_data in f_mass_storage.c and
instead created fsg_config structure fsg_common_init() takes
as an argument -- it stores all configuration options that
were previously taken from mod_data.

Moreover, The fsg_config structure allows per-LUN
configuration of removable and CD-ROM emulation.

Module parameters are handled by defining an object of
fsg_module_parameters structure and then declaring module
parameters via FSG_MODULE_PARAMETERS() macro.  It adds proper
declarations to the code making specified object be populated
from module parameters.

To use values stored there one may use either
fsg_config_from_params() which will will a fsg_config structure
with values taken from fsg_module_parameters structure or
fsg_common_from_params() which will initialise fsg_common
structure directly.

Signed-off-by: default avatarMichal Nazarewicz <m.nazarewicz@samsung.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d23b0f08
Loading
Loading
Loading
Loading
+172 −95
Original line number Original line Diff line number Diff line
@@ -253,51 +253,6 @@ static const char fsg_string_interface[] = "Mass Storage";
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/




/* Encapsulate the module parameter settings */

static struct {
	char		*file[FSG_MAX_LUNS];
	int		ro[FSG_MAX_LUNS];
	unsigned int	num_filenames;
	unsigned int	num_ros;
	unsigned int	nluns;

	int		removable;
	int		can_stall;
	int		cdrom;

	unsigned short	release;
} mod_data = {					// Default values
	.removable		= 0,
	.can_stall		= 1,
	.cdrom			= 0,
	.release		= 0xffff,
	};


module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
		S_IRUGO);
MODULE_PARM_DESC(file, "names of backing files or devices");

module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
MODULE_PARM_DESC(ro, "true to force read-only");

module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
MODULE_PARM_DESC(luns, "number of LUNs");

module_param_named(removable, mod_data.removable, bool, S_IRUGO);
MODULE_PARM_DESC(removable, "true to simulate removable media");

module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");

module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");


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


/* Data shared by all the FSG instances. */
/* Data shared by all the FSG instances. */
struct fsg_common {
struct fsg_common {
	struct usb_gadget	*gadget;
	struct usb_gadget	*gadget;
@@ -317,12 +272,34 @@ struct fsg_common {
	struct fsg_lun		*luns;
	struct fsg_lun		*luns;
	struct fsg_lun		*curlun;
	struct fsg_lun		*curlun;


	unsigned int		can_stall:1;
	unsigned int		free_storage_on_release:1;
	unsigned int		free_storage_on_release:1;


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

	struct kref		ref;
	struct kref		ref;
};
};




struct fsg_config {
	unsigned nluns;
	struct fsg_lun_config {
		const char *filename;
		char ro;
		char removable;
		char cdrom;
	} luns[FSG_MAX_LUNS];

	const char *vendor_name;		/*  8 characters or less */
	const char *product_name;		/* 16 characters or less */
	u16 release;

	char			can_stall;
};


struct fsg_dev {
struct fsg_dev {
	struct usb_function	function;
	struct usb_function	function;
	struct usb_composite_dev*cdev;
	struct usb_composite_dev*cdev;
@@ -351,6 +328,7 @@ struct fsg_dev {
	unsigned int		phase_error : 1;
	unsigned int		phase_error : 1;
	unsigned int		short_packet_received : 1;
	unsigned int		short_packet_received : 1;
	unsigned int		bad_lun_okay : 1;
	unsigned int		bad_lun_okay : 1;
	unsigned int		can_stall : 1;


	unsigned long		atomic_bitflags;
	unsigned long		atomic_bitflags;
#define REGISTERED		0
#define REGISTERED		0
@@ -1065,13 +1043,10 @@ static int do_verify(struct fsg_dev *fsg)


static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
{
	struct fsg_lun *curlun = fsg->common->curlun;
	u8	*buf = (u8 *) bh->buf;
	u8	*buf = (u8 *) bh->buf;


	static char vendor_id[] = "Linux   ";
	if (!curlun) {		/* Unsupported LUNs are okay */
	static char product_disk_id[] = "File-Stor Gadget";
	static char product_cdrom_id[] = "File-CD Gadget  ";

	if (!fsg->common->curlun) {		// Unsupported LUNs are okay
		fsg->bad_lun_okay = 1;
		fsg->bad_lun_okay = 1;
		memset(buf, 0, 36);
		memset(buf, 0, 36);
		buf[0] = 0x7f;		// Unsupported, no device-type
		buf[0] = 0x7f;		// Unsupported, no device-type
@@ -1079,18 +1054,16 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
		return 36;
		return 36;
	}
	}


	memset(buf, 0, 8);
	buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
	buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
	buf[1] = curlun->removable ? 0x80 : 0;
	if (mod_data.removable)
		buf[1] = 0x80;
	buf[2] = 2;		// ANSI SCSI level 2
	buf[2] = 2;		// ANSI SCSI level 2
	buf[3] = 2;		// SCSI-2 INQUIRY data format
	buf[3] = 2;		// SCSI-2 INQUIRY data format
	buf[4] = 31;		// Additional length
	buf[4] = 31;		// Additional length
				// No special options
	buf[5] = 0;		// No special options
	sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
	buf[6] = 0;
			(mod_data.cdrom ? product_cdrom_id :
	buf[7] = 0;
				product_disk_id),
	memcpy(buf + 8, fsg->common->inquiry_string,
			mod_data.release);
	       sizeof fsg->common->inquiry_string);
	return 36;
	return 36;
}
}


@@ -1303,7 +1276,9 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)


static int do_start_stop(struct fsg_dev *fsg)
static int do_start_stop(struct fsg_dev *fsg)
{
{
	if (!mod_data.removable) {
	if (!fsg->common->curlun) {
		return -EINVAL;
	} else if (!fsg->common->curlun->removable) {
		fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
		fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
		return -EINVAL;
		return -EINVAL;
	}
	}
@@ -1316,8 +1291,10 @@ static int do_prevent_allow(struct fsg_dev *fsg)
	struct fsg_lun	*curlun = fsg->common->curlun;
	struct fsg_lun	*curlun = fsg->common->curlun;
	int		prevent;
	int		prevent;


	if (!mod_data.removable) {
	if (!fsg->common->curlun) {
		curlun->sense_data = SS_INVALID_COMMAND;
		return -EINVAL;
	} else if (!fsg->common->curlun->removable) {
		fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
		return -EINVAL;
		return -EINVAL;
	}
	}


@@ -1505,7 +1482,7 @@ static int finish_reply(struct fsg_dev *fsg)
	 * try to send or receive any data.  So stall both bulk pipes
	 * try to send or receive any data.  So stall both bulk pipes
	 * if we can and wait for a reset. */
	 * if we can and wait for a reset. */
	case DATA_DIR_UNKNOWN:
	case DATA_DIR_UNKNOWN:
		if (mod_data.can_stall) {
		if (fsg->can_stall) {
			fsg_set_halt(fsg, fsg->bulk_out);
			fsg_set_halt(fsg, fsg->bulk_out);
			rc = halt_bulk_in_endpoint(fsg);
			rc = halt_bulk_in_endpoint(fsg);
		}
		}
@@ -1526,7 +1503,7 @@ static int finish_reply(struct fsg_dev *fsg)
		/* For Bulk-only, if we're allowed to stall then send the
		/* For Bulk-only, if we're allowed to stall then send the
		 * short packet and halt the bulk-in endpoint.  If we can't
		 * short packet and halt the bulk-in endpoint.  If we can't
		 * stall, pad out the remaining data with 0's. */
		 * stall, pad out the remaining data with 0's. */
		} else if (mod_data.can_stall) {
		} else if (fsg->can_stall) {
			bh->inreq->zero = 1;
			bh->inreq->zero = 1;
			start_transfer(fsg, fsg->bulk_in, bh->inreq,
			start_transfer(fsg, fsg->bulk_in, bh->inreq,
				       &bh->inreq_busy, &bh->state);
				       &bh->inreq_busy, &bh->state);
@@ -1556,7 +1533,7 @@ static int finish_reply(struct fsg_dev *fsg)
		 * STALL.  Not realizing the endpoint was halted, it wouldn't
		 * STALL.  Not realizing the endpoint was halted, it wouldn't
		 * clear the halt -- leading to problems later on. */
		 * clear the halt -- leading to problems later on. */
#if 0
#if 0
		else if (mod_data.can_stall) {
		else if (fsg->can_stall) {
			fsg_set_halt(fsg, fsg->bulk_out);
			fsg_set_halt(fsg, fsg->bulk_out);
			raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
			raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
			rc = -EINTR;
			rc = -EINTR;
@@ -1866,7 +1843,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
		break;
		break;


	case SC_READ_HEADER:
	case SC_READ_HEADER:
		if (!mod_data.cdrom)
		if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
			goto unknown_cmnd;
			goto unknown_cmnd;
		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
@@ -1876,7 +1853,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
		break;
		break;


	case SC_READ_TOC:
	case SC_READ_TOC:
		if (!mod_data.cdrom)
		if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
			goto unknown_cmnd;
			goto unknown_cmnd;
		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
@@ -2043,7 +2020,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)


		/* We can do anything we want here, so let's stall the
		/* We can do anything we want here, so let's stall the
		 * bulk pipes if we are allowed to. */
		 * bulk pipes if we are allowed to. */
		if (mod_data.can_stall) {
		if (fsg->can_stall) {
			fsg_set_halt(fsg, fsg->bulk_out);
			fsg_set_halt(fsg, fsg->bulk_out);
			halt_bulk_in_endpoint(fsg);
			halt_bulk_in_endpoint(fsg);
		}
		}
@@ -2499,18 +2476,18 @@ static inline void fsg_common_put(struct fsg_common *common)




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


	/* Find out how many LUNs there should be */
	/* Find out how many LUNs there should be */
	nluns = mod_data.nluns;
	nluns = cfg->nluns;
	if (nluns == 0)
		nluns = max(mod_data.num_filenames, 1u);
	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);
@@ -2539,10 +2516,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,


	init_rwsem(&common->filesem);
	init_rwsem(&common->filesem);


	for (i = 0; i < nluns; ++i, ++curlun) {
	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
		curlun->cdrom = !!mod_data.cdrom;
		curlun->cdrom = !!lcfg->cdrom;
		curlun->ro = mod_data.cdrom || mod_data.ro[i];
		curlun->ro = lcfg->cdrom || lcfg->ro;
		curlun->removable = mod_data.removable;
		curlun->removable = lcfg->removable;
		curlun->dev.release = fsg_lun_release;
		curlun->dev.release = fsg_lun_release;
		curlun->dev.parent = &gadget->dev;
		curlun->dev.parent = &gadget->dev;
		/* curlun->dev.driver = &fsg_driver.driver; XXX */
		/* curlun->dev.driver = &fsg_driver.driver; XXX */
@@ -2564,11 +2541,11 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
		if (rc)
		if (rc)
			goto error_luns;
			goto error_luns;


		if (mod_data.file[i] && *mod_data.file[i]) {
		if (lcfg->filename) {
			rc = fsg_lun_open(curlun, mod_data.file[i]);
			rc = fsg_lun_open(curlun, lcfg->filename);
			if (rc)
			if (rc)
				goto error_luns;
				goto error_luns;
		} else if (!mod_data.removable) {
		} else if (!curlun->removable) {
			ERROR(common, "no file given for LUN%d\n", i);
			ERROR(common, "no file given for LUN%d\n", i);
			rc = -EINVAL;
			rc = -EINVAL;
			goto error_luns;
			goto error_luns;
@@ -2588,33 +2565,40 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
	bh->next = common->buffhds;
	bh->next = common->buffhds;




	/* Release */
	/* Prepare inquiryString */
	if (mod_data.release == 0xffff) {	// Parameter wasn't set
	if (cfg->release != 0xffff) {
		int	gcnum;
		i = cfg->release;

	} else {
		/* The sa1100 controller is not supported */
		/* The sa1100 controller is not supported */
		if (gadget_is_sa1100(gadget))
		i = gadget_is_sa1100(gadget)
			gcnum = -1;
			? -1
		else
			: usb_gadget_controller_number(gadget);
			gcnum = usb_gadget_controller_number(gadget);
		if (i >= 0) {
		if (gcnum >= 0)
			i = 0x0300 + i;
			mod_data.release = 0x0300 + gcnum;
		} else {
		else {
			WARNING(common, "controller '%s' not recognized\n",
				gadget->name);
			WARNING(common, "controller '%s' not recognized\n",
			WARNING(common, "controller '%s' not recognized\n",
				gadget->name);
				gadget->name);
			mod_data.release = 0x0399;
			i = 0x0399;
		}
		}
	}
	}
#define OR(x, y) ((x) ? (x) : (y))
	snprintf(common->inquiry_string, sizeof common->inquiry_string,
		 "%-8s%-16s%04x",
		 OR(cfg->vendor_name, "Linux   "),
		 /* Assume product name dependent on the first LUN */
		 OR(cfg->product_name, common->luns->cdrom
				     ? "File-Stor Gadget"
				     : "File-CD Gadget  "),
		 i);
#undef OR




	/* Some peripheral controllers are known not to be able to
	/* Some peripheral controllers are known not to be able to
	 * halt bulk endpoints correctly.  If one of them is present,
	 * halt bulk endpoints correctly.  If one of them is present,
	 * disable stalls.
	 * disable stalls.
	 */
	 */
	if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
	common->can_stall = cfg->can_stall &&
		mod_data.can_stall = 0;
		!(gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget));




	kref_init(&common->ref);
	kref_init(&common->ref);
@@ -2820,6 +2804,7 @@ static int fsg_add(struct usb_composite_dev *cdev,
	 * from this function.  So instead of incrementing counter now
	 * from this function.  So instead of incrementing counter now
	 * and decrement in error recovery we increment it only when
	 * and decrement in error recovery we increment it only when
	 * call to usb_add_function() was successful. */
	 * call to usb_add_function() was successful. */
	fsg->can_stall = common->can_stall;


	rc = usb_add_function(c, &fsg->function);
	rc = usb_add_function(c, &fsg->function);


@@ -2830,3 +2815,95 @@ static int fsg_add(struct usb_composite_dev *cdev,


	return rc;
	return rc;
}
}



/************************* Module parameters *************************/


struct fsg_module_parameters {
	char		*file[FSG_MAX_LUNS];
	int		ro[FSG_MAX_LUNS];
	int		removable[FSG_MAX_LUNS];
	int		cdrom[FSG_MAX_LUNS];

	unsigned int	file_count, ro_count, removable_count, cdrom_count;
	unsigned int	luns;	/* nluns */
	int		stall;	/* can_stall */
};


#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)	\
	module_param_array_named(prefix ## name, params.name, type,	\
				 &prefix ## params.name ## _count,	\
				 S_IRUGO);				\
	MODULE_PARM_DESC(prefix ## name, desc)

#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)		\
	module_param_named(prefix ## name, params.name, type,		\
			   S_IRUGO);					\
	MODULE_PARM_DESC(prefix ## name, desc)

#define FSG_MODULE_PARAMETERS(prefix, params)				\
	_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,		\
				"names of backing files or devices");	\
	_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,		\
				"true to force read-only");		\
	_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,	\
				"true to simulate removable media");	\
	_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,		\
				"true to simulate CD-ROM instead of disk"); \
	_FSG_MODULE_PARAM(prefix, params, luns, uint,			\
			  "number of LUNs");				\
	_FSG_MODULE_PARAM(prefix, params, stall, bool,			\
			  "false to prevent bulk stalls")


static void
fsg_config_from_params(struct fsg_config *cfg,
		       const struct fsg_module_parameters *params)
{
	struct fsg_lun_config *lun;
	unsigned i, nluns;

	/* Configure LUNs */
	nluns = cfg->nluns = !params->luns
		? params->file_count ? params->file_count : 1
		: params->luns;
	for (i = 0, lun = cfg->luns;
	     i < FSG_MAX_LUNS && i < nluns;
	     ++i, ++lun) {
		lun->ro = !!params->ro[i];
		lun->cdrom = !!params->cdrom[i];
		lun->removable =
			params->removable_count <= i || params->removable[i];
		lun->filename =
			params->file_count > i && params->file[i][0]
			? params->file[i]
			: 0;
	}

	/* Let FSG use defaults */
	cfg->vendor_name = 0;
	cfg->product_name = 0;
	cfg->release = 0xffff;

	/* Finalise */
	cfg->can_stall = params->stall;
}

static inline struct fsg_common *
fsg_common_from_params(struct fsg_common *common,
		       struct usb_composite_dev *cdev,
		       const struct fsg_module_parameters *params)
	__attribute__((unused));
static inline struct fsg_common *
fsg_common_from_params(struct fsg_common *common,
		       struct usb_composite_dev *cdev,
		       const struct fsg_module_parameters *params)
{
	struct fsg_config cfg;
	fsg_config_from_params(&cfg, params);
	return fsg_common_init(common, cdev, &cfg);
}
+6 −1
Original line number Original line Diff line number Diff line
@@ -127,6 +127,11 @@ static struct usb_gadget_strings *dev_strings[] = {


/****************************** Configurations ******************************/
/****************************** Configurations ******************************/


static struct fsg_module_parameters mod_data = {
	.stall = 1
};
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);

static int __init msg_do_config(struct usb_configuration *c)
static int __init msg_do_config(struct usb_configuration *c)
{
{
	struct fsg_common *common;
	struct fsg_common *common;
@@ -137,7 +142,7 @@ static int __init msg_do_config(struct usb_configuration *c)
		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
	}
	}


	common = fsg_common_init(0, c->cdev);
	common = fsg_common_from_params(0, c->cdev, &mod_data);
	if (IS_ERR(common))
	if (IS_ERR(common))
		return PTR_ERR(common);
		return PTR_ERR(common);