[PATCH 067/122] USB: g_mass_storage: fsg_config added & module params handlig changed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Michal Nazarewicz <m.nazarewicz@xxxxxxxxxxx>

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: Michal Nazarewicz <m.nazarewicz@xxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>
---
 drivers/usb/gadget/f_mass_storage.c |  267 ++++++++++++++++++++++-------------
 drivers/usb/gadget/mass_storage.c   |    7 +-
 2 files changed, 178 insertions(+), 96 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 5fc01c0..e7c9f0c 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -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. */
 struct fsg_common {
 	struct usb_gadget	*gadget;
@@ -317,12 +272,34 @@ struct fsg_common {
 	struct fsg_lun		*luns;
 	struct fsg_lun		*curlun;
 
+	unsigned int		can_stall: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 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 usb_function	function;
 	struct usb_composite_dev*cdev;
@@ -351,6 +328,7 @@ struct fsg_dev {
 	unsigned int		phase_error : 1;
 	unsigned int		short_packet_received : 1;
 	unsigned int		bad_lun_okay : 1;
+	unsigned int		can_stall : 1;
 
 	unsigned long		atomic_bitflags;
 #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)
 {
+	struct fsg_lun *curlun = fsg->common->curlun;
 	u8	*buf = (u8 *) bh->buf;
 
-	static char vendor_id[] = "Linux   ";
-	static char product_disk_id[] = "File-Stor Gadget";
-	static char product_cdrom_id[] = "File-CD Gadget  ";
-
-	if (!fsg->common->curlun) {		// Unsupported LUNs are okay
+	if (!curlun) {		/* Unsupported LUNs are okay */
 		fsg->bad_lun_okay = 1;
 		memset(buf, 0, 36);
 		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;
 	}
 
-	memset(buf, 0, 8);
-	buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
-	if (mod_data.removable)
-		buf[1] = 0x80;
+	buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
+	buf[1] = curlun->removable ? 0x80 : 0;
 	buf[2] = 2;		// ANSI SCSI level 2
 	buf[3] = 2;		// SCSI-2 INQUIRY data format
 	buf[4] = 31;		// Additional length
-				// No special options
-	sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
-			(mod_data.cdrom ? product_cdrom_id :
-				product_disk_id),
-			mod_data.release);
+	buf[5] = 0;		// No special options
+	buf[6] = 0;
+	buf[7] = 0;
+	memcpy(buf + 8, fsg->common->inquiry_string,
+	       sizeof fsg->common->inquiry_string);
 	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)
 {
-	if (!mod_data.removable) {
+	if (!fsg->common->curlun) {
+		return -EINVAL;
+	} else if (!fsg->common->curlun->removable) {
 		fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
 		return -EINVAL;
 	}
@@ -1316,8 +1291,10 @@ static int do_prevent_allow(struct fsg_dev *fsg)
 	struct fsg_lun	*curlun = fsg->common->curlun;
 	int		prevent;
 
-	if (!mod_data.removable) {
-		curlun->sense_data = SS_INVALID_COMMAND;
+	if (!fsg->common->curlun) {
+		return -EINVAL;
+	} else if (!fsg->common->curlun->removable) {
+		fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
 		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
 	 * if we can and wait for a reset. */
 	case DATA_DIR_UNKNOWN:
-		if (mod_data.can_stall) {
+		if (fsg->can_stall) {
 			fsg_set_halt(fsg, fsg->bulk_out);
 			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
 		 * short packet and halt the bulk-in endpoint.  If we can't
 		 * stall, pad out the remaining data with 0's. */
-		} else if (mod_data.can_stall) {
+		} else if (fsg->can_stall) {
 			bh->inreq->zero = 1;
 			start_transfer(fsg, fsg->bulk_in, bh->inreq,
 				       &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
 		 * clear the halt -- leading to problems later on. */
 #if 0
-		else if (mod_data.can_stall) {
+		else if (fsg->can_stall) {
 			fsg_set_halt(fsg, fsg->bulk_out);
 			raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
 			rc = -EINTR;
@@ -1866,7 +1843,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 		break;
 
 	case SC_READ_HEADER:
-		if (!mod_data.cdrom)
+		if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
 			goto unknown_cmnd;
 		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
 		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
@@ -1876,7 +1853,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 		break;
 
 	case SC_READ_TOC:
-		if (!mod_data.cdrom)
+		if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
 			goto unknown_cmnd;
 		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
 		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
 		 * bulk pipes if we are allowed to. */
-		if (mod_data.can_stall) {
+		if (fsg->can_stall) {
 			fsg_set_halt(fsg, fsg->bulk_out);
 			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,
-					  struct usb_composite_dev *cdev)
+					  struct usb_composite_dev *cdev,
+					  struct fsg_config *cfg)
 {
 	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;
 
 	/* Find out how many LUNs there should be */
-	nluns = mod_data.nluns;
-	if (nluns == 0)
-		nluns = max(mod_data.num_filenames, 1u);
+	nluns = cfg->nluns;
 	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
 		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
 		return ERR_PTR(-EINVAL);
@@ -2539,10 +2516,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 
 	init_rwsem(&common->filesem);
 
-	for (i = 0; i < nluns; ++i, ++curlun) {
-		curlun->cdrom = !!mod_data.cdrom;
-		curlun->ro = mod_data.cdrom || mod_data.ro[i];
-		curlun->removable = mod_data.removable;
+	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
+		curlun->cdrom = !!lcfg->cdrom;
+		curlun->ro = lcfg->cdrom || lcfg->ro;
+		curlun->removable = lcfg->removable;
 		curlun->dev.release = fsg_lun_release;
 		curlun->dev.parent = &gadget->dev;
 		/* curlun->dev.driver = &fsg_driver.driver; XXX */
@@ -2564,11 +2541,11 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 		if (rc)
 			goto error_luns;
 
-		if (mod_data.file[i] && *mod_data.file[i]) {
-			rc = fsg_lun_open(curlun, mod_data.file[i]);
+		if (lcfg->filename) {
+			rc = fsg_lun_open(curlun, lcfg->filename);
 			if (rc)
 				goto error_luns;
-		} else if (!mod_data.removable) {
+		} else if (!curlun->removable) {
 			ERROR(common, "no file given for LUN%d\n", i);
 			rc = -EINVAL;
 			goto error_luns;
@@ -2588,33 +2565,40 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 	bh->next = common->buffhds;
 
 
-	/* Release */
-	if (mod_data.release == 0xffff) {	// Parameter wasn't set
-		int	gcnum;
-
+	/* Prepare inquiryString */
+	if (cfg->release != 0xffff) {
+		i = cfg->release;
+	} else {
 		/* The sa1100 controller is not supported */
-		if (gadget_is_sa1100(gadget))
-			gcnum = -1;
-		else
-			gcnum = usb_gadget_controller_number(gadget);
-		if (gcnum >= 0)
-			mod_data.release = 0x0300 + gcnum;
-		else {
-			WARNING(common, "controller '%s' not recognized\n",
-				gadget->name);
+		i = gadget_is_sa1100(gadget)
+			? -1
+			: usb_gadget_controller_number(gadget);
+		if (i >= 0) {
+			i = 0x0300 + i;
+		} else {
 			WARNING(common, "controller '%s' not recognized\n",
 				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
 	 * halt bulk endpoints correctly.  If one of them is present,
 	 * disable stalls.
 	 */
-	if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
-		mod_data.can_stall = 0;
+	common->can_stall = cfg->can_stall &&
+		!(gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget));
 
 
 	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
 	 * and decrement in error recovery we increment it only when
 	 * call to usb_add_function() was successful. */
+	fsg->can_stall = common->can_stall;
 
 	rc = usb_add_function(c, &fsg->function);
 
@@ -2830,3 +2815,95 @@ static int fsg_add(struct usb_composite_dev *cdev,
 
 	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);
+}
+
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 27339f0..00396a3 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -127,6 +127,11 @@ static struct usb_gadget_strings *dev_strings[] = {
 
 /****************************** 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)
 {
 	struct fsg_common *common;
@@ -137,7 +142,7 @@ static int __init msg_do_config(struct usb_configuration *c)
 		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))
 		return PTR_ERR(common);
 
-- 
1.6.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux