[RFC 06/19] usb/gadget: f_mass_storage: split fsg_common initialization into a number of functions

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

 



From: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>

When configfs is in place, the things related to intialization
of struct fsg_common will be split over a number of places.
This patch adds several functions which together cover the former
intialization routine fsg_common_init. As a consequence, issuing of
some debug messages needs to be adjusted.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
 drivers/usb/gadget/f_mass_storage.c |  400 +++++++++++++++++++++++++++++++++--
 drivers/usb/gadget/f_mass_storage.h |   31 +++
 drivers/usb/gadget/storage_common.c |   24 +--
 3 files changed, 430 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 8d0b451..fc3b5ff 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -299,6 +299,7 @@ struct fsg_common {
 	unsigned int		short_packet_received:1;
 	unsigned int		bad_lun_okay:1;
 	unsigned int		running:1;
+	unsigned int		sysfs:1;
 
 	int			thread_wakeup_needed;
 	struct completion	thread_notifier;
@@ -2604,6 +2605,374 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)
 	return -EINVAL;
 }
 
+static struct fsg_common *fsg_common_setup(struct fsg_common *common, bool zero)
+{
+	if (!common) {
+		common = kzalloc(sizeof *common, GFP_KERNEL);
+		if (!common)
+			return ERR_PTR(-ENOMEM);
+		common->free_storage_on_release = 1;
+	} else {
+		if (zero)
+			memset(common, 0, sizeof *common);
+		common->free_storage_on_release = 0;
+	}
+	init_rwsem(&common->filesem);
+	spin_lock_init(&common->lock);
+	kref_init(&common->ref);
+	init_completion(&common->thread_notifier);
+	init_waitqueue_head(&common->fsg_wait);
+	common->state = FSG_STATE_TERMINATED;
+
+	return common;
+}
+
+void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs)
+{
+	common->sysfs = sysfs;
+}
+
+int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n)
+{
+	struct fsg_buffhd *bh, *new_buffhds;
+	int i, rc;
+
+	rc = fsg_num_buffers_validate(n);
+	if (rc != 0)
+		return rc;
+
+	new_buffhds = kcalloc(n, sizeof *(new_buffhds), GFP_KERNEL);
+	if (!new_buffhds)
+		return -ENOMEM;
+
+	/* Data buffers cyclic list */
+	bh = new_buffhds;
+	i = n;
+	goto buffhds_first_it;
+	do {
+		bh->next = bh + 1;
+		++bh;
+buffhds_first_it:
+		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+		if (unlikely(!bh->buf))
+			goto error_release;
+	} while (--i);
+	bh->next = new_buffhds;
+
+	common->fsg_num_buffers = n;
+	kfree(common->buffhds);
+	common->buffhds = new_buffhds;
+
+	return 0;
+
+error_release:
+	bh = new_buffhds;
+	i = n - i;
+	while (i--) {
+		kfree(bh->buf);
+		bh++;
+	};
+
+	kfree(new_buffhds);
+
+	return -ENOMEM;
+}
+
+void fsg_common_free_buffers(struct fsg_common *common)
+{
+	struct fsg_buffhd *bh;
+	int i;
+
+	bh = common->buffhds;
+	i = common->fsg_num_buffers;
+	while (i--) {
+		kfree(bh->buf);
+		bh++;
+	};
+
+	kfree(common->buffhds);
+	common->buffhds = NULL;
+}
+
+int fsg_common_set_nluns(struct fsg_common *common, int nluns)
+{
+	struct fsg_lun **curlun;
+
+	/* Find out how many LUNs there should be */
+	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+		ERROR(common, "invalid number of LUNs: %u\n", nluns);
+		return -EINVAL;
+	}
+
+	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
+	if (unlikely(!curlun))
+		return -ENOMEM;
+
+	common->luns = curlun;
+	common->nluns = nluns;
+
+	pr_info("Number of LUNs=%d\n", common->nluns);
+
+	return 0;
+}
+
+void fsg_common_free_luns(struct fsg_common *common)
+{
+	kfree(common->luns);
+	common->luns = NULL;
+}
+
+void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops)
+{
+	common->ops = ops;
+}
+
+void fsg_common_set_private_data(struct fsg_common *common, void *priv)
+{
+	common->private_data = priv;
+}
+
+int fsg_common_set_cdev(struct fsg_common *common,
+			 struct usb_composite_dev *cdev, bool can_stall)
+{
+	struct usb_string *us;
+	int rc;
+
+	common->gadget = cdev->gadget;
+	common->ep0 = cdev->gadget->ep0;
+	common->ep0req = cdev->req;
+	common->cdev = cdev;
+
+	us = usb_gstrings_attach(cdev, fsg_strings_array,
+				 ARRAY_SIZE(fsg_strings));
+	if (IS_ERR(us)) {
+		rc = PTR_ERR(us);
+		return rc;
+	}
+	fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id;
+
+	/*
+	 * Some peripheral controllers are known not to be able to
+	 * halt bulk endpoints correctly.  If one of them is present,
+	 * disable stalls.
+	 */
+	common->can_stall = can_stall && !(gadget_is_at91(common->gadget));
+
+	return 0;
+}
+
+static inline int fsg_common_add_sysfs(struct fsg_common *common,
+				       struct fsg_lun *lun)
+{
+	int rc;
+
+	rc = device_register(&lun->dev);
+	if (rc) {
+		put_device(&lun->dev);
+		return rc;
+	}
+
+	rc = device_create_file(&lun->dev,
+				lun->cdrom
+			      ? &dev_attr_ro_cdrom
+			      : &dev_attr_ro);
+	if (rc)
+		goto error_cdrom;
+	rc = device_create_file(&lun->dev,
+				lun->removable
+			      ? &dev_attr_file
+			      : &dev_attr_file_nonremovable);
+	if (rc)
+		goto error_removable;
+	rc = device_create_file(&lun->dev, &dev_attr_nofua);
+	if (rc)
+		goto error_nofua;
+
+	return 0;
+
+error_nofua:
+	device_remove_file(&lun->dev,
+			   lun->removable
+			 ? &dev_attr_file
+			 : &dev_attr_file_nonremovable);
+error_removable:
+	device_remove_file(&lun->dev,
+			   lun->cdrom
+			 ? &dev_attr_ro_cdrom
+			 : &dev_attr_ro);
+error_cdrom:
+	device_unregister(&lun->dev);
+	return rc;
+}
+
+void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs)
+{
+	if (sysfs) {
+		device_remove_file(&lun->dev, &dev_attr_nofua);
+		device_remove_file(&lun->dev,
+				   lun->cdrom
+				 ? &dev_attr_ro_cdrom
+				 : &dev_attr_ro);
+		device_remove_file(&lun->dev,
+				   lun->removable
+				 ? &dev_attr_file
+				 : &dev_attr_file_nonremovable);
+		device_unregister(&lun->dev);
+	}
+	fsg_lun_close(lun);
+	kfree(lun);
+}
+
+void fsg_common_remove_luns(struct fsg_common *common)
+{
+	int i;
+
+	for (i = 0; i < common->nluns; ++i)
+		fsg_common_remove_lun(common->luns[i], common->sysfs);
+}
+
+int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
+			  unsigned int id)
+{
+	struct fsg_lun *lun;
+	char *pathbuf;
+	int rc;
+
+	if (!common->nluns || !common->luns)
+		return -ENODEV;
+
+	if (common->luns[id])
+		return -EBUSY;
+
+	lun = kzalloc(sizeof(*lun), GFP_KERNEL);
+	if (!lun)
+		return -ENOMEM;
+
+	lun->cdrom = !!cfg->cdrom;
+	lun->ro = cfg->cdrom || cfg->ro;
+	lun->initially_ro = lun->ro;
+	lun->removable = cfg->removable;
+
+	common->luns[id] = lun;
+
+	if (common->sysfs) {
+		lun->dev.release = fsg_lun_release;
+		lun->dev.parent = &common->gadget->dev;
+		dev_set_drvdata(&lun->dev, &common->filesem);
+		dev_set_name(&lun->dev, "lun%d", id);
+
+		rc = fsg_common_add_sysfs(common, lun);
+		if (rc) {
+			pr_info("failed to register LUN%d: %d\n", id, rc);
+			goto error_sysfs;
+		}
+	}
+
+	if (cfg->filename) {
+		rc = fsg_lun_open(lun, cfg->filename);
+		if (rc)
+			goto error_lun;
+	} else if (!lun->removable) {
+		pr_err("no file given for LUN%d\n", id);
+		rc = -EINVAL;
+		goto error_lun;
+	}
+
+	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+	{
+		char *p = "(no medium)";
+		if (fsg_lun_is_open(lun)) {
+			p = "(error)";
+			if (pathbuf) {
+				p = d_path(&lun->filp->f_path,
+					   pathbuf, PATH_MAX);
+				if (IS_ERR(p))
+					p = "(error)";
+			}
+		}
+		pr_info("LUN: %s%s%sfile: %s\n",
+		      lun->removable ? "removable " : "",
+		      lun->ro ? "read only " : "",
+		      lun->cdrom ? "CD-ROM " : "",
+		      p);
+	}
+	kfree(pathbuf);
+
+	return 0;
+
+error_lun:
+	if (common->sysfs) {
+		device_remove_file(&lun->dev, &dev_attr_nofua);
+		device_remove_file(&lun->dev,
+				   lun->cdrom
+				 ? &dev_attr_ro_cdrom
+				 : &dev_attr_ro);
+		device_remove_file(&lun->dev,
+				   lun->removable
+				 ? &dev_attr_file
+				 : &dev_attr_file_nonremovable);
+		device_unregister(&lun->dev);
+	}
+	fsg_lun_close(lun);
+error_sysfs:
+	kfree(lun);
+	return rc;
+}
+
+int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg)
+{
+	int i, rc;
+
+	for (i = 0; i < common->nluns; ++i) {
+		rc = fsg_common_create_lun(common, &cfg->luns[i], i);
+		if (rc)
+			goto fail;
+	}
+
+	pr_info("Number of LUNs=%d\n", common->nluns);
+
+	return 0;
+
+fail:
+	while (--i >= 0)
+		fsg_common_remove_lun(common->luns[i], true);
+	return rc;
+}
+
+void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
+				   const char *pn)
+{
+	int i;
+
+	/* Prepare inquiryString */
+	i = get_default_bcdDevice();
+	snprintf(common->inquiry_string, sizeof common->inquiry_string,
+		 "%-8s%-16s%04x", vn ?: "Linux",
+		 /* Assume product name dependent on the first LUN */
+		 pn ?: ((*common->luns)->cdrom
+		     ? "File-CD Gadget"
+		     : "File-Stor Gadget"),
+		 i);
+}
+
+int fsg_common_run_thread(struct fsg_common *common)
+{
+	common->state = FSG_STATE_IDLE;
+	/* Tell the thread to start working */
+	common->thread_task =
+		kthread_create(fsg_main_thread, common, "file-storage");
+	if (IS_ERR(common->thread_task)) {
+		common->state = FSG_STATE_TERMINATED;
+		return PTR_ERR(common->thread_task);
+	}
+
+	DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+
+	wake_up_process(common->thread_task);
+
+	return 0;
+}
+
 struct fsg_common *fsg_common_init(struct fsg_common *common,
 				   struct usb_composite_dev *cdev,
 				   struct fsg_config *cfg)
@@ -2637,6 +3006,8 @@ struct fsg_common *fsg_common_init(struct fsg_common *common,
 		memset(common, 0, sizeof *common);
 		common->free_storage_on_release = 0;
 	}
+	common->sysfs = true;
+	common->state = FSG_STATE_IDLE;
 
 	common->fsg_num_buffers = cfg->fsg_num_buffers;
 	common->buffhds = kcalloc(common->fsg_num_buffers,
@@ -2818,6 +3189,15 @@ error_release:
 	return ERR_PTR(rc);
 }
 
+static inline void fsg_common_remove_sysfs(struct fsg_lun *lun)
+{
+	device_remove_file(&lun->dev, &dev_attr_nofua);
+	device_remove_file(&lun->dev, lun->cdrom
+			   ? &dev_attr_ro_cdrom : &dev_attr_ro);
+	device_remove_file(&lun->dev, lun->removable
+			   ? &dev_attr_file : &dev_attr_file_nonremovable);
+}
+
 static void fsg_common_release(struct kref *ref)
 {
 	struct fsg_common *common = container_of(ref, struct fsg_common, ref);
@@ -2836,32 +3216,26 @@ static void fsg_common_release(struct kref *ref)
 		for (; i; --i, ++lun) {
 			if (!*lun)
 				continue;
-			device_remove_file(&(*lun)->dev, &dev_attr_nofua);
-			device_remove_file(&(*lun)->dev,
-					   (*lun)->cdrom
-					 ? &dev_attr_ro_cdrom
-					 : &dev_attr_ro);
-			device_remove_file(&(*lun)->dev,
-					   (*lun)->removable
-					 ? &dev_attr_file
-					 : &dev_attr_file_nonremovable);
+			if (common->sysfs)
+				fsg_common_remove_sysfs(*lun);
 			fsg_lun_close(*lun);
-			device_unregister(&(*lun)->dev);
+			if (common->sysfs)
+				device_unregister(&(*lun)->dev);
 			kfree(*lun);
 		}
 
 		kfree(common->luns);
 	}
 
-	{
+	if (likely(common->buffhds)){
 		struct fsg_buffhd *bh = common->buffhds;
 		unsigned i = common->fsg_num_buffers;
 		do {
 			kfree(bh->buf);
 		} while (++bh, --i);
-	}
 
-	kfree(common->buffhds);
+		kfree(common->buffhds);
+	}
 	if (common->free_storage_on_release)
 		kfree(common);
 }
diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h
index b64761d..46e6863 100644
--- a/drivers/usb/gadget/f_mass_storage.h
+++ b/drivers/usb/gadget/f_mass_storage.h
@@ -102,6 +102,37 @@ struct fsg_common *fsg_common_init(struct fsg_common *common,
 				   struct usb_composite_dev *cdev,
 				   struct fsg_config *cfg);
 
+void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs);
+
+int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n);
+
+void fsg_common_free_buffers(struct fsg_common *common);
+
+int fsg_common_set_nluns(struct fsg_common *common, int nluns);
+
+void fsg_common_free_luns(struct fsg_common *common);
+
+void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops);
+
+void fsg_common_set_private_data(struct fsg_common *common, void *priv);
+
+int fsg_common_set_cdev(struct fsg_common *common,
+			struct usb_composite_dev *cdev, bool can_stall);
+
+void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs);
+
+void fsg_common_remove_luns(struct fsg_common *common);
+
+int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
+			  unsigned int id);
+
+int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg);
+
+void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
+				   const char *pn);
+
+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);
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 942324c..a70a5d3 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -179,7 +179,7 @@ EXPORT_SYMBOL(fsg_ss_function);
 void fsg_lun_close(struct fsg_lun *curlun)
 {
 	if (curlun->filp) {
-		LDBG(curlun, "close backing file\n");
+		pr_debug("close backing file\n");
 		fput(curlun->filp);
 		curlun->filp = NULL;
 	}
@@ -208,7 +208,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	if (ro)
 		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
 	if (IS_ERR(filp)) {
-		LINFO(curlun, "unable to open backing file: %s\n", filename);
+		pr_info("unable to open backing file: %s\n", filename);
 		return PTR_ERR(filp);
 	}
 
@@ -217,7 +217,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 
 	inode = file_inode(filp);
 	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
-		LINFO(curlun, "invalid file type: %s\n", filename);
+		pr_info("invalid file type: %s\n", filename);
 		goto out;
 	}
 
@@ -226,7 +226,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	 * If we can't write the file, use it read-only.
 	 */
 	if (!(filp->f_op->read || filp->f_op->aio_read)) {
-		LINFO(curlun, "file not readable: %s\n", filename);
+		pr_info("file not readable: %s\n", filename);
 		goto out;
 	}
 	if (!(filp->f_op->write || filp->f_op->aio_write))
@@ -234,7 +234,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 
 	size = i_size_read(inode->i_mapping->host);
 	if (size < 0) {
-		LINFO(curlun, "unable to find file size: %s\n", filename);
+		pr_info("unable to find file size: %s\n", filename);
 		rc = (int) size;
 		goto out;
 	}
@@ -256,13 +256,13 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 		min_sectors = 300;	/* Smallest track is 300 frames */
 		if (num_sectors >= 256*60*75) {
 			num_sectors = 256*60*75 - 1;
-			LINFO(curlun, "file too big: %s\n", filename);
-			LINFO(curlun, "using only first %d blocks\n",
+			pr_info("file too big: %s\n", filename);
+			pr_info("using only first %d blocks\n",
 					(int) num_sectors);
 		}
 	}
 	if (num_sectors < min_sectors) {
-		LINFO(curlun, "file too small: %s\n", filename);
+		pr_info("file too small: %s\n", filename);
 		rc = -ETOOSMALL;
 		goto out;
 	}
@@ -276,7 +276,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	curlun->filp = filp;
 	curlun->file_length = size;
 	curlun->num_sectors = num_sectors;
-	LDBG(curlun, "open backing file: %s\n", filename);
+	pr_debug("open backing file: %s\n", filename);
 	return 0;
 
 out:
@@ -391,12 +391,12 @@ ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
 	 */
 	down_read(filesem);
 	if (fsg_lun_is_open(curlun)) {
-		LDBG(curlun, "read-only status change prevented\n");
+		pr_debug("read-only status change prevented\n");
 		rc = -EBUSY;
 	} else {
 		curlun->ro = ro;
 		curlun->initially_ro = ro;
-		LDBG(curlun, "read-only status set to %d\n", curlun->ro);
+		pr_debug("read-only status set to %d\n", curlun->ro);
 		rc = count;
 	}
 	up_read(filesem);
@@ -434,7 +434,7 @@ ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
 	int		rc = 0;
 
 	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
-		LDBG(curlun, "eject attempt prevented\n");
+		pr_debug("eject attempt prevented\n");
 		return -EBUSY;				/* "Door is locked" */
 	}
 
-- 
1.7.9.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