[RFC v5 3/3] usb: gadget: example port of mass storage to UFG: create storage_common.h and factor out code from storage_common.c

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

 



Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>

---
 drivers/usb/gadget/Kconfig          |    4 +
 drivers/usb/gadget/Makefile         |    3 +
 drivers/usb/gadget/f_mass_storage.c |  825 +++++++++++++++++------------------
 drivers/usb/gadget/f_mass_storage.h |   99 +++++
 drivers/usb/gadget/storage_common.c |  175 +++++---
 drivers/usb/gadget/storage_common.h |   43 ++
 6 files changed, 648 insertions(+), 501 deletions(-)
 create mode 100644 drivers/usb/gadget/f_mass_storage.h
 create mode 100644 drivers/usb/gadget/storage_common.h

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 80ab9a5..f142db3 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -501,6 +501,9 @@ config USB_LIBCOMPOSITE
 	tristate
 	depends on USB_GADGET
 
+config USB_F_MASS_STORAGE
+	tristate
+
 choice
 	tristate "USB Gadget Drivers"
 	default USB_ETH
@@ -524,6 +527,7 @@ choice
 
 config USB_FG
 	tristate "USB Functions Gadget"
+        select USB_F_MASS_STORAGE
 	depends on CONFIGFS_FS
 	help
 	  USB Functions Gadget is a device which aggregates a number of
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 378296b..536f4d6 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -75,3 +75,6 @@ obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
 obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
 obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
+
+# USB Functions
+obj-$(CONFIG_USB_F_MASS_STORAGE) += f_mass_storage.o
\ No newline at end of file
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 5d027b3..a558f32 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -213,12 +213,14 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/freezer.h>
+#include <linux/module.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/composite.h>
 
 #include "gadget_chips.h"
+#include "usb_functions.h"
 
 
 /*------------------------------------------------------------------------*/
@@ -229,124 +231,11 @@
 static const char fsg_string_interface[] = "Mass Storage";
 
 #include "storage_common.c"
-
+#include "f_mass_storage.h"
 
 /*-------------------------------------------------------------------------*/
 
-struct fsg_dev;
-struct fsg_common;
-
-/* FSF callback functions */
-struct fsg_operations {
-	/*
-	 * Callback function to call when thread exits.  If no
-	 * callback is set or it returns value lower then zero MSF
-	 * will force eject all LUNs it operates on (including those
-	 * marked as non-removable or with prevent_medium_removal flag
-	 * set).
-	 */
-	int (*thread_exits)(struct fsg_common *common);
-
-	/*
-	 * Called prior to ejection.  Negative return means error,
-	 * zero means to continue with ejection, positive means not to
-	 * eject.
-	 */
-	int (*pre_eject)(struct fsg_common *common,
-			 struct fsg_lun *lun, int num);
-	/*
-	 * Called after ejection.  Negative return means error, zero
-	 * or positive is just a success.
-	 */
-	int (*post_eject)(struct fsg_common *common,
-			  struct fsg_lun *lun, int num);
-};
-
-/* Data shared by all the FSG instances. */
-struct fsg_common {
-	struct usb_gadget	*gadget;
-	struct usb_composite_dev *cdev;
-	struct fsg_dev		*fsg, *new_fsg;
-	wait_queue_head_t	fsg_wait;
-
-	/* filesem protects: backing files in use */
-	struct rw_semaphore	filesem;
-
-	/* lock protects: state, all the req_busy's */
-	spinlock_t		lock;
-
-	struct usb_ep		*ep0;		/* Copy of gadget->ep0 */
-	struct usb_request	*ep0req;	/* Copy of cdev->req */
-	unsigned int		ep0_req_tag;
-
-	struct fsg_buffhd	*next_buffhd_to_fill;
-	struct fsg_buffhd	*next_buffhd_to_drain;
-	struct fsg_buffhd	*buffhds;
-
-	int			cmnd_size;
-	u8			cmnd[MAX_COMMAND_SIZE];
-
-	unsigned int		nluns;
-	unsigned int		lun;
-	struct fsg_lun		*luns;
-	struct fsg_lun		*curlun;
-
-	unsigned int		bulk_out_maxpacket;
-	enum fsg_state		state;		/* For exception handling */
-	unsigned int		exception_req_tag;
-
-	enum data_direction	data_dir;
-	u32			data_size;
-	u32			data_size_from_cmnd;
-	u32			tag;
-	u32			residue;
-	u32			usb_amount_left;
-
-	unsigned int		can_stall:1;
-	unsigned int		free_storage_on_release:1;
-	unsigned int		phase_error:1;
-	unsigned int		short_packet_received:1;
-	unsigned int		bad_lun_okay:1;
-	unsigned int		running:1;
-
-	int			thread_wakeup_needed;
-	struct completion	thread_notifier;
-	struct task_struct	*thread_task;
-
-	/* Callback functions. */
-	const struct fsg_operations	*ops;
-	/* 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];
-
-	struct kref		ref;
-};
-
-struct fsg_config {
-	unsigned nluns;
-	struct fsg_lun_config {
-		const char *filename;
-		char ro;
-		char removable;
-		char cdrom;
-		char nofua;
-	} luns[FSG_MAX_LUNS];
-
-	/* Callback functions. */
-	const struct fsg_operations	*ops;
-	/* Gadget's private data. */
-	void			*private_data;
-
-	const char *vendor_name;		/*  8 characters or less */
-	const char *product_name;		/* 16 characters or less */
-
-	char			can_stall;
-};
+static unsigned long msg_registered;
 
 struct fsg_dev {
 	struct usb_function	function;
@@ -1374,26 +1263,13 @@ static int do_start_stop(struct fsg_common *common)
 	if (!loej)
 		return 0;
 
-	/* Simulate an unload/eject */
-	if (common->ops && common->ops->pre_eject) {
-		int r = common->ops->pre_eject(common, curlun,
-					       curlun - common->luns);
-		if (unlikely(r < 0))
-			return r;
-		else if (r)
-			return 0;
-	}
-
 	up_read(&common->filesem);
 	down_write(&common->filesem);
 	fsg_lun_close(curlun);
 	up_write(&common->filesem);
 	down_read(&common->filesem);
 
-	return common->ops && common->ops->post_eject
-		? min(0, common->ops->post_eject(common, curlun,
-						 curlun - common->luns))
-		: 0;
+	return 0;
 }
 
 static int do_prevent_allow(struct fsg_common *common)
@@ -2196,9 +2072,23 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 	if (common->data_size == 0)
 		common->data_dir = DATA_DIR_NONE;
 	common->lun = cbw->Lun;
-	if (common->lun >= 0 && common->lun < common->nluns)
-		common->curlun = &common->luns[common->lun];
-	else
+	if (common->lun >= 0 && common->lun < common->nluns) {
+		struct config_item *it;
+
+		mutex_lock(&common->group.group.cg_subsys->su_mutex);
+		list_for_each_entry(it, &common->group.group.cg_children,
+				    ci_entry) {
+			struct fsg_lun *lun;
+
+			lun = to_fsg_lun(it);
+			if (lun->n_lun == common->lun) {
+				common->curlun = lun;
+
+				break;
+			}
+		}
+		mutex_unlock(&common->group.group.cg_subsys->su_mutex);
+	} else
 		common->curlun = NULL;
 	common->tag = cbw->Tag;
 	return 0;
@@ -2258,6 +2148,7 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 /* Reset interface setting and re-init endpoint state (toggle etc). */
 static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
 {
+	struct config_item *item;
 	struct fsg_dev *fsg;
 	int i, rc = 0;
 
@@ -2342,8 +2233,14 @@ reset:
 	}
 
 	common->running = 1;
-	for (i = 0; i < common->nluns; ++i)
-		common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+	mutex_lock(&common->group.group.cg_subsys->su_mutex);
+	list_for_each_entry(item, &common->group.group.cg_children, ci_entry) {
+		struct fsg_lun *lun;
+
+		lun = to_fsg_lun(item);
+		lun->unit_attention_data = SS_RESET_OCCURRED;
+	}
+	mutex_unlock(&common->group.group.cg_subsys->su_mutex);
 	return rc;
 }
 
@@ -2374,7 +2271,6 @@ static void handle_exception(struct fsg_common *common)
 	int			i;
 	struct fsg_buffhd	*bh;
 	enum fsg_state		old_state;
-	struct fsg_lun		*curlun;
 	unsigned int		exception_req_tag;
 
 	/*
@@ -2442,14 +2338,21 @@ static void handle_exception(struct fsg_common *common)
 	if (old_state == FSG_STATE_ABORT_BULK_OUT)
 		common->state = FSG_STATE_STATUS_PHASE;
 	else {
-		for (i = 0; i < common->nluns; ++i) {
-			curlun = &common->luns[i];
+		struct config_item *it;
+
+		mutex_lock(&common->group.group.cg_subsys->su_mutex);
+		list_for_each_entry(it, &common->group.group.cg_children,
+				    ci_entry) {
+			struct fsg_lun *curlun;
+
+			curlun = to_fsg_lun(it);
 			curlun->prevent_medium_removal = 0;
 			curlun->sense_data = SS_NO_SENSE;
 			curlun->unit_attention_data = SS_NO_SENSE;
 			curlun->sense_data_info = 0;
 			curlun->info_valid = 0;
 		}
+		mutex_unlock(&common->group.group.cg_subsys->su_mutex);
 		common->state = FSG_STATE_IDLE;
 	}
 	spin_unlock_irq(&common->lock);
@@ -2582,17 +2485,25 @@ static int fsg_main_thread(void *common_)
 
 	if (!common->ops || !common->ops->thread_exits
 	 || common->ops->thread_exits(common) < 0) {
-		struct fsg_lun *curlun = common->luns;
-		unsigned i = common->nluns;
+		struct list_head *cursor;
 
 		down_write(&common->filesem);
-		for (; i--; ++curlun) {
+
+		mutex_lock(&common->group.group.cg_subsys->su_mutex);
+		list_for_each_prev(cursor, &common->group.group.cg_children) {
+			struct config_item *item;
+			struct fsg_lun *curlun;
+
+			item = list_entry(cursor, struct config_item, ci_entry);
+
+			curlun = to_fsg_lun(item);
 			if (!fsg_lun_is_open(curlun))
 				continue;
 
 			fsg_lun_close(curlun);
 			curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
 		}
+		mutex_unlock(&common->group.group.cg_subsys->su_mutex);
 		up_write(&common->filesem);
 	}
 
@@ -2600,156 +2511,241 @@ static int fsg_main_thread(void *common_)
 	complete_and_exit(&common->thread_notifier, 0);
 }
 
+/****************************** FSG COMMON ******************************/
 
-/*************************** DEVICE ATTRIBUTES ***************************/
+static void fsg_common_release(struct kref *ref);
 
-static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
-static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
-static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+void fsg_common_get(struct fsg_common *common)
+{
+	kref_get(&common->ref);
+}
+EXPORT_SYMBOL(fsg_common_get);
 
-static struct device_attribute dev_attr_ro_cdrom =
-	__ATTR(ro, 0444, fsg_show_ro, NULL);
-static struct device_attribute dev_attr_file_nonremovable =
-	__ATTR(file, 0444, fsg_show_file, NULL);
+void fsg_common_put(struct fsg_common *common)
+{
+	kref_put(&common->ref, fsg_common_release);
+}
+EXPORT_SYMBOL(fsg_common_put);
 
+static struct fsg_lun *alloc_fsg_lun(struct config_group *group,
+					 const char *name)
+{
+	struct fsg_common *common;
+	struct ufg_function_grp *ufg_function_grp;
+	struct fsg_lun *lun;
+	struct config_item *item;
+	unsigned int tmp;
+	unsigned int leading_zeros;
+	int len;
+	const char *p;
+
+	ufg_function_grp = group ?
+		container_of(group, struct ufg_function_grp, group) : NULL;
+	if (!ufg_function_grp)
+		return ERR_PTR(-ENOMEM);
+	common = ufg_function_grp ?
+		container_of(ufg_function_grp, struct fsg_common, group) : NULL;
 
-/****************************** FSG COMMON ******************************/
+	if (strncmp(name, "lun", 3))
+		return ERR_PTR(-EINVAL);
+	p = name + 3;
+	if (sscanf(p, "%d%n", &tmp, &len) < 1)
+		return ERR_PTR(-EINVAL);
+	leading_zeros = 0;
+	while (*p++ == '0')
+		leading_zeros++;
+	if (!tmp)
+		leading_zeros--;
+	if (leading_zeros > 0)
+		return ERR_PTR(-EINVAL);
+	if (strlen(name) != len + 3)
+		return ERR_PTR(-EINVAL);
 
-static void fsg_common_release(struct kref *ref);
+	list_for_each_entry(item, &common->group.group.cg_children, ci_entry) {
+		lun = to_fsg_lun(item);
+		if (tmp == lun->n_lun)
+			return ERR_PTR(-EBUSY);
+	}
 
-static void fsg_lun_release(struct device *dev)
+	lun = kzalloc(sizeof(*lun), GFP_KERNEL);
+	if (!lun)
+		return ERR_PTR(-ENOMEM);
+	lun->filesem = &common->filesem;
+	lun->n_lun = tmp;
+
+	config_item_init_type_name(&lun->item.cg_item, name,
+				   &fsg_lun_item_type);
+
+	LINFO(lun, "LUN: %s%s%sfile: %s\n",
+	      lun->removable ? "removable " : "",
+	      lun->ro ? "read only " : "",
+	      lun->cdrom ? "CD-ROM " : "",
+	      "(no medium)");
+
+	return lun;
+}
+
+static ssize_t fsg_common_show_luns(struct fsg_common *common, char *buf)
 {
-	/* Nothing needs to be done */
+	return sprintf(buf, "%d\n", common->nluns);
 }
 
-static inline void fsg_common_get(struct fsg_common *common)
+static ssize_t fsg_common_store_luns(struct fsg_common *common, const char *buf,
+				     size_t count)
 {
-	kref_get(&common->ref);
+	struct config_item *function, *config, *gadget;
+	struct fsg_lun *new;
+	char n[LUN_NAME_MAX];
+	u16 tmp;
+	char *p = (char *)buf;
+	int rc;
+
+	function = common->group.group.cg_item.ci_parent;
+	if (!function)
+		return -EBUSY;
+
+	config = function->ci_parent;
+	if (!config)
+		return -EBUSY;
+
+	gadget = config->ci_parent;
+	if (!gadget)
+		return -EBUSY;
+
+	rc = kstrtou16(p, 10, &tmp);
+	if (rc < 0)
+		return rc;
+	if (tmp > FSG_MAX_LUNS)
+		return -ERANGE;
+
+	common->nluns = tmp;
+	for (tmp = 0; tmp < common->nluns; tmp++) {
+
+		sprintf(n, "lun%d", tmp);
+		new = alloc_fsg_lun(&common->group.group, n);
+		if (IS_ERR(new))
+			goto rollback;
+
+		rc = configfs_create_group(&common->group.group, &new->item);
+		if (rc) {
+			kfree(new);
+
+			goto rollback;
+		}
+
+	}
+
+	return count;
+
+rollback:
+	while (tmp--) {
+		struct config_item *child;
+
+		sprintf(n, "lun%d", tmp);
+		child = config_group_find_item(&common->group.group, n);
+		if (child)
+			configfs_remove_group(to_config_group(child));
+	}
+	return rc;
 }
 
-static inline void fsg_common_put(struct fsg_common *common)
+static ssize_t fsg_common_show_stall(struct fsg_common *common, char *buf)
 {
-	kref_put(&common->ref, fsg_common_release);
+	return sprintf(buf, "%d\n", common->can_stall);
 }
 
-static struct fsg_common *fsg_common_init(struct fsg_common *common,
-					  struct usb_composite_dev *cdev,
-					  struct fsg_config *cfg)
+static ssize_t fsg_common_store_stall(struct fsg_common *common,
+				      const char *buf, size_t count)
+{
+	if (count > 2)
+		return -EINVAL;
+
+	if (buf[0] != '0' && buf[0] != '1')
+		return -EINVAL;
+
+	if (count > 1 && buf[1] != '\0')
+		return -EINVAL;
+
+	common->can_stall = buf[0] == '1';
+
+	return count;
+}
+
+CONFIGFS_ATTR_STRUCT(fsg_common);
+
+#define FSG_CONFIG_ATTR_RW(_name)					\
+static struct fsg_common_attribute fsg_common_##_name =			\
+	__CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, fsg_common_show_##_name,\
+			fsg_common_store_##_name)
+
+#define FSG_CONFIG_ATTR_RO(_name)					\
+static struct fsg_common_attribute fsg_common_##_name =			\
+	__CONFIGFS_ATTR(_name, S_IRUGO , fsg_common_show_##_name, NULL)
+
+FSG_CONFIG_ATTR_RW(luns);
+FSG_CONFIG_ATTR_RW(stall);
+
+static struct configfs_attribute *fsg_common_attrs[] = {
+	&fsg_common_luns.attr,
+	&fsg_common_stall.attr,
+	NULL,
+};
+
+static struct fsg_common *to_fsg_common(struct config_item *item)
+{
+	struct ufg_function_grp *ufg_function_grp;
+
+	ufg_function_grp =
+		item ? container_of(to_config_group(item),
+				    struct ufg_function_grp, group) : NULL;
+	return ufg_function_grp ? container_of(ufg_function_grp,
+					       struct fsg_common, group) : NULL;
+}
+
+CONFIGFS_ATTR_OPS(fsg_common);
+
+static void fsg_common_release_item(struct config_item *item)
+{
+	kfree(to_fsg_common(item));
+}
+
+static struct configfs_item_operations fsg_common_item_ops = {
+	.show_attribute		= fsg_common_attr_show,
+	.store_attribute	= fsg_common_attr_store,
+	.release		= fsg_common_release_item,
+};
+
+static struct config_item_type fsg_common_item_type = {
+	.ct_attrs	= fsg_common_attrs,
+	.ct_item_ops	= &fsg_common_item_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+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;
+	int i, rc;
 
 	rc = fsg_num_buffers_validate();
 	if (rc != 0)
 		return ERR_PTR(rc);
 
-	/* Find out how many LUNs there should be */
-	nluns = cfg->nluns;
-	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
-		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
+	/* TODO: move it somewhere else */
+	/*if (common->nluns < 1 || common->nluns > FSG_MAX_LUNS) {
+		printk("invalid number of LUNs: %u\n", nluns);
 		return ERR_PTR(-EINVAL);
-	}
-
-	/* Allocate? */
-	if (!common) {
-		common = kzalloc(sizeof *common, GFP_KERNEL);
-		if (!common)
-			return ERR_PTR(-ENOMEM);
-		common->free_storage_on_release = 1;
-	} else {
-		memset(common, 0, sizeof *common);
-		common->free_storage_on_release = 0;
-	}
+	}*/
 
 	common->buffhds = kcalloc(fsg_num_buffers,
 				  sizeof *(common->buffhds), GFP_KERNEL);
-	if (!common->buffhds) {
-		if (common->free_storage_on_release)
-			kfree(common);
+	if (!common->buffhds)
 		return ERR_PTR(-ENOMEM);
-	}
-
-	common->ops = cfg->ops;
-	common->private_data = cfg->private_data;
 
-	common->gadget = gadget;
-	common->ep0 = gadget->ep0;
-	common->ep0req = cdev->req;
-	common->cdev = cdev;
-
-	/* Maybe allocate device-global string IDs, and patch descriptors */
-	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
-		rc = usb_string_id(cdev);
-		if (unlikely(rc < 0))
-			goto error_release;
-		fsg_strings[FSG_STRING_INTERFACE].id = rc;
-		fsg_intf_desc.iInterface = rc;
-	}
-
-	/*
-	 * Create the LUNs, open their backing files, and register the
-	 * LUN devices in sysfs.
-	 */
-	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
-	if (unlikely(!curlun)) {
-		rc = -ENOMEM;
-		goto error_release;
-	}
-	common->luns = curlun;
+	common->ops = NULL;
+	common->private_data = NULL;
 
 	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->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;
-
-		if (lcfg->filename) {
-			rc = fsg_lun_open(curlun, lcfg->filename);
-			if (rc)
-				goto error_luns;
-		} else if (!curlun->removable) {
-			ERROR(common, "no file given for LUN%d\n", i);
-			rc = -EINVAL;
-			goto error_luns;
-		}
-	}
-	common->nluns = nluns;
-
 	/* Data buffers cyclic list */
 	bh = common->buffhds;
 	i = fsg_num_buffers;
@@ -2766,24 +2762,6 @@ buffhds_first_it:
 	} while (--i);
 	bh->next = common->buffhds;
 
-	/* Prepare inquiryString */
-	i = get_default_bcdDevice();
-	snprintf(common->inquiry_string, sizeof common->inquiry_string,
-		 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
-		 /* Assume product name dependent on the first LUN */
-		 cfg->product_name ?: (common->luns->cdrom
-				     ? "File-Stor Gadget"
-				     : "File-CD Gadget"),
-		 i);
-
-	/*
-	 * 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 = cfg->can_stall &&
-		!(gadget_is_at91(common->gadget));
-
 	spin_lock_init(&common->lock);
 	kref_init(&common->ref);
 
@@ -2798,49 +2776,100 @@ buffhds_first_it:
 	init_waitqueue_head(&common->fsg_wait);
 
 	/* Information */
-	INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
-	INFO(common, "Number of LUNs=%d\n", common->nluns);
-
-	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
-	for (i = 0, nluns = common->nluns, curlun = common->luns;
-	     i < nluns;
-	     ++curlun, ++i) {
-		char *p = "(no medium)";
-		if (fsg_lun_is_open(curlun)) {
-			p = "(error)";
-			if (pathbuf) {
-				p = d_path(&curlun->filp->f_path,
-					   pathbuf, PATH_MAX);
-				if (IS_ERR(p))
-					p = "(error)";
-			}
-		}
-		LINFO(curlun, "LUN: %s%s%sfile: %s\n",
-		      curlun->removable ? "removable " : "",
-		      curlun->ro ? "read only " : "",
-		      curlun->cdrom ? "CD-ROM " : "",
-		      p);
-	}
-	kfree(pathbuf);
+	pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+	pr_info("Number of LUNs=%d\n", common->nluns);
 
-	DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+	pr_info("I/O thread pid: %d\n", task_pid_nr(common->thread_task));
 
 	wake_up_process(common->thread_task);
 
 	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);
 	return ERR_PTR(rc);
 }
+EXPORT_SYMBOL(fsg_common_init);
+
+static struct fsg_common *fsg_common_init_cdev(struct fsg_common *common,
+					       struct usb_composite_dev *cdev)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+	int rc, i;
+
+	common->gadget = gadget;
+	common->ep0 = gadget->ep0;
+	common->ep0req = cdev->req;
+	common->cdev = cdev;
+
+	/* Maybe allocate device-global string IDs, and patch descriptors */
+	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+		rc = usb_string_id(cdev);
+		if (unlikely(rc < 0))
+			goto error_release;
+		fsg_strings[FSG_STRING_INTERFACE].id = rc;
+		fsg_intf_desc.iInterface = rc;
+	}
+
+	/* Prepare inquiryString */
+	i = get_default_bcdDevice();
+	snprintf(common->inquiry_string, sizeof(common->inquiry_string),
+		 "%-8s%-16s%04x", "Linux",
+		 /* Assume product name dependent on the first LUN */
+		 /* TODO: actually check first child's "cdrom" flag */
+			"USB mass storage", i);
+
+	/*
+	 * 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 = common->can_stall &&
+		!(gadget_is_at91(common->gadget));
+
+	return common;
+
+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);
+	return ERR_PTR(rc);
+}
+
+struct config_group *alloc_fsg_common(struct config_group *group,
+					     const char *n)
+{
+	struct config_item *item;
+	struct fsg_common *common, *ret;
+
+	list_for_each_entry(item, &group->cg_children, ci_entry)
+		if (!strcmp(n, item->ci_name))
+			return ERR_PTR(-EBUSY);
+
+	common = kzalloc(sizeof(*common), GFP_KERNEL);
+	if (!common)
+		return ERR_PTR(-ENOMEM);
+
+	ret = fsg_common_init(common);
+	if (IS_ERR(ret)) {
+		kfree(common);
+		return (struct config_group *)ret;
+	}
+	common->group.type = UFG_FUNCTION;
+
+	config_group_init_type_name(&common->group.group, n,
+				    &fsg_common_item_type);
+
+	return &common->group.group;
+}
+EXPORT_SYMBOL(alloc_fsg_common);
 
 static void fsg_common_release(struct kref *ref)
 {
 	struct fsg_common *common = container_of(ref, struct fsg_common, ref);
+	struct config_item *item;
 
 	/* If the thread isn't already dead, tell it to exit now */
 	if (common->state != FSG_STATE_TERMINATED) {
@@ -2848,28 +2877,10 @@ static void fsg_common_release(struct kref *ref)
 		wait_for_completion(&common->thread_notifier);
 	}
 
-	if (likely(common->luns)) {
-		struct fsg_lun *lun = common->luns;
-		unsigned i = common->nluns;
-
-		/* In error recovery common->nluns may be zero. */
-		for (; i; --i, ++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);
-			fsg_lun_close(lun);
-			device_unregister(&lun->dev);
-		}
-
-		kfree(common->luns);
+	list_for_each_entry(item, &common->group.group.cg_children, ci_entry) {
+		struct fsg_lun *lun = to_fsg_lun(item);
+		fsg_lun_close(lun);
 	}
-
 	{
 		struct fsg_buffhd *bh = common->buffhds;
 		unsigned i = fsg_num_buffers;
@@ -2879,11 +2890,8 @@ static void fsg_common_release(struct kref *ref)
 	}
 
 	kfree(common->buffhds);
-	if (common->free_storage_on_release)
-		kfree(common);
 }
 
-
 /*-------------------------------------------------------------------------*/
 
 static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
@@ -2899,9 +2907,14 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
 		wait_event(common->fsg_wait, common->fsg != fsg);
 	}
 
+	usb_free_all_descriptors(f);
 	fsg_common_put(common);
-	usb_free_all_descriptors(&fsg->function);
-	kfree(fsg);
+	usb_put_function(f);
+}
+
+static void fsg_free(struct usb_function *f)
+{
+	kfree(fsg_from_func(f));
 }
 
 static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
@@ -2965,22 +2978,61 @@ autoconf_fail:
 }
 
 /****************************** ADD FUNCTION ******************************/
+static void msg_cleanup(void)
+{
+	clear_bit(0, &msg_registered);
+}
+
+static int msg_thread_exits(struct fsg_common *common)
+{
+	msg_cleanup();
+	return 0;
+}
+
+static int fsg_add_function(struct usb_configuration *c, struct usb_function *f,
+		      struct config_item *item, void *data)
+{
+	static const struct fsg_operations ops = {
+		.thread_exits = msg_thread_exits,
+	};
+
+	struct fsg_common *common = to_fsg_common(item);
+	struct fsg_dev *fsg;
+	struct usb_composite_dev *cdev = data;
+	int status;
+
+	common->ops = &ops;
+	fsg_common_init_cdev(common, cdev);
+
+	fsg = container_of(f, struct fsg_dev, function);
+	fsg->common = common;
+
+	status = usb_add_function(c, f);
+	if (status) {
+		usb_put_function(f);
+		fsg_common_put(common);
+		return status;
+	}
+	fsg_common_get(common);
+	set_bit(0, &msg_registered);
+
+	return status;
+}
+
+/****************************** ALLOCATE FUNCTION *************************/
 
 static struct usb_gadget_strings *fsg_strings_array[] = {
 	&fsg_stringtab,
 	NULL,
 };
 
-static int fsg_bind_config(struct usb_composite_dev *cdev,
-			   struct usb_configuration *c,
-			   struct fsg_common *common)
+static struct usb_function *fsg_alloc(void)
 {
 	struct fsg_dev *fsg;
-	int rc;
 
-	fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+	fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
 	if (unlikely(!fsg))
-		return -ENOMEM;
+		return NULL;
 
 	fsg->function.name        = FSG_DRIVER_DESC;
 	fsg->function.strings     = fsg_strings_array;
@@ -2989,8 +3041,10 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
 	fsg->function.setup       = fsg_setup;
 	fsg->function.set_alt     = fsg_set_alt;
 	fsg->function.disable     = fsg_disable;
+	fsg->function.free_func	  = fsg_free;
+	fsg->function.make_group  = alloc_fsg_common;
+	fsg->function.add_function = fsg_add_function;
 
-	fsg->common               = common;
 	/*
 	 * Our caller holds a reference to common structure so we
 	 * don't have to be worry about it being freed until we return
@@ -2999,100 +3053,9 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
 	 * call to usb_add_function() was successful.
 	 */
 
-	rc = usb_add_function(c, &fsg->function);
-	if (unlikely(rc))
-		kfree(fsg);
-	else
-		fsg_common_get(fsg->common);
-	return rc;
+	return &fsg->function;
 }
 
-
-/************************* Module parameters *************************/
-
-struct fsg_module_parameters {
-	char		*file[FSG_MAX_LUNS];
-	bool		ro[FSG_MAX_LUNS];
-	bool		removable[FSG_MAX_LUNS];
-	bool		cdrom[FSG_MAX_LUNS];
-	bool		nofua[FSG_MAX_LUNS];
-
-	unsigned int	file_count, ro_count, removable_count, cdrom_count;
-	unsigned int	nofua_count;
-	unsigned int	luns;	/* nluns */
-	bool		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_ARRAY(prefix, params, nofua, bool,		\
-				"true to ignore SCSI WRITE(10,12) FUA bit"); \
-	_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;
-
-	/* Configure LUNs */
-	cfg->nluns =
-		min(params->luns ?: (params->file_count ?: 1u),
-		    (unsigned)FSG_MAX_LUNS);
-	for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
-		lun->ro = !!params->ro[i];
-		lun->cdrom = !!params->cdrom[i];
-		lun->removable = !!params->removable[i];
-		lun->filename =
-			params->file_count > i && params->file[i][0]
-			? params->file[i]
-			: 0;
-	}
-
-	/* Let MSF use defaults */
-	cfg->vendor_name = 0;
-	cfg->product_name = 0;
-
-	cfg->ops = NULL;
-	cfg->private_data = NULL;
-
-	/* 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);
-}
+DECLARE_USB_FUNCTION(MassStorage, fsg_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Nazarewicz");
diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h
new file mode 100644
index 0000000..fa583db
--- /dev/null
+++ b/drivers/usb/gadget/f_mass_storage.h
@@ -0,0 +1,99 @@
+#ifndef F_MASS_STORAGE_H
+#define F_MASS_STORAGE_H
+
+#include "storage_common.h"
+#include "usb_functions.h"
+
+#define LUN_NAME_MAX 16
+
+struct fsg_common;
+struct fsg_operations;
+struct usb_composite_dev;
+struct fsg_dev;
+struct fsg_lun;
+
+/* FSF callback functions */
+struct fsg_operations {
+	/*
+	 * Callback function to call when thread exits.  If no
+	 * callback is set or it returns value lower then zero MSF
+	 * will force eject all LUNs it operates on (including those
+	 * marked as non-removable or with prevent_medium_removal flag
+	 * set).
+	 */
+	int (*thread_exits)(struct fsg_common *common);
+};
+
+/* Data shared by all the FSG instances. */
+struct fsg_common {
+	struct ufg_function_grp	group;
+	enum ufg_hdr_type	type;
+
+	struct usb_gadget	*gadget;
+	struct usb_composite_dev *cdev;
+	struct fsg_dev		*fsg, *new_fsg;
+	wait_queue_head_t	fsg_wait;
+
+	/* filesem protects: backing files in use */
+	struct rw_semaphore	filesem;
+
+	/* lock protects: state, all the req_busy's */
+	spinlock_t		lock;
+
+	struct usb_ep		*ep0;		/* Copy of gadget->ep0 */
+	struct usb_request	*ep0req;	/* Copy of cdev->req */
+	unsigned int		ep0_req_tag;
+
+	struct fsg_buffhd	*next_buffhd_to_fill;
+	struct fsg_buffhd	*next_buffhd_to_drain;
+	struct fsg_buffhd	*buffhds;
+
+	int			cmnd_size;
+	u8			cmnd[MAX_COMMAND_SIZE];
+
+	unsigned int		nluns;
+	unsigned int		lun;
+	struct fsg_lun		*curlun;
+
+	unsigned int		bulk_out_maxpacket;
+	enum fsg_state		state;		/* For exception handling */
+	unsigned int		exception_req_tag;
+
+	enum data_direction	data_dir;
+	u32			data_size;
+	u32			data_size_from_cmnd;
+	u32			tag;
+	u32			residue;
+	u32			usb_amount_left;
+
+	unsigned int		can_stall:1;
+	unsigned int		free_storage_on_release:1;
+	unsigned int		phase_error:1;
+	unsigned int		short_packet_received:1;
+	unsigned int		bad_lun_okay:1;
+	unsigned int		running:1;
+
+	int			thread_wakeup_needed;
+	struct completion	thread_notifier;
+	struct task_struct	*thread_task;
+
+	/* Callback functions. */
+	const struct fsg_operations	*ops;
+	/* 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];
+
+	struct kref		ref;
+};
+
+struct fsg_common *fsg_common_init(struct fsg_common *common);
+
+void fsg_common_get(struct fsg_common *common);
+void fsg_common_put(struct fsg_common *common);
+
+#endif
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 0e3ae43..9e6136c 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -25,19 +25,12 @@
 
 
 #include <linux/usb/storage.h>
+#include <linux/configfs.h>
 #include <scsi/scsi.h>
 #include <asm/unaligned.h>
+#include "storage_common.h"
 
 
-/*
- * Thanks to NetChip Technologies for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-#define FSG_VENDOR_ID	0x0525	/* NetChip */
-#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -53,10 +46,9 @@
 #define VLDBG(lun, fmt, args...) do { } while (0)
 #endif /* VERBOSE_DEBUG */
 
-#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args)
-#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
-#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args)
-#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)
+#define LERROR(lun, fmt, args...)  pr_err(fmt, ## args)
+#define LDBG(lun, fmt, args...)   pr_debug(fmt, ## args)
+#define LINFO(lun, fmt, args...)  pr_info(fmt, ## args)
 
 
 #ifdef DUMP_MSGS
@@ -105,9 +97,6 @@ struct interrupt_data {
 #define USB_CBI_ADSC_REQUEST		0x00
 
 
-/* Length of a SCSI Command Data Block */
-#define MAX_COMMAND_SIZE	16
-
 /* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
 #define SS_NO_SENSE				0
 #define SS_COMMUNICATION_FAILURE		0x040800
@@ -152,7 +141,11 @@ struct fsg_lun {
 
 	unsigned int	blkbits;	/* Bits of logical block size of bound block device */
 	unsigned int	blksize;	/* logical block size of bound block device */
-	struct device	dev;
+
+	/* configfs-related section */
+	struct config_group	item;
+	struct rw_semaphore	*filesem;
+	unsigned int		n_lun;
 };
 
 static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
@@ -160,11 +153,63 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
 	return curlun->filp != NULL;
 }
 
-static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev)
+CONFIGFS_ATTR_STRUCT(fsg_lun);
+
+#define FSG_LUN_ATTR_RW(_name)						\
+static struct fsg_lun_attribute fsg_lun_##_name =			\
+	__CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, fsg_lun_show_##_name,	\
+			fsg_lun_store_##_name)
+
+static ssize_t fsg_lun_show_ro(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_show_nofua(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_show_file(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_store_ro(struct fsg_lun *curlun, const char *buf,
+				size_t count);
+static ssize_t fsg_lun_store_nofua(struct fsg_lun *curlun, const char *buf,
+				   size_t count);
+static ssize_t fsg_lun_store_file(struct fsg_lun *curlun, const char *buf,
+				  size_t count);
+static ssize_t fsg_lun_show_removable(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_store_removable(struct fsg_lun *curlun, const char *buf,
+				       size_t count);
+
+FSG_LUN_ATTR_RW(ro);
+FSG_LUN_ATTR_RW(nofua);
+FSG_LUN_ATTR_RW(file);
+FSG_LUN_ATTR_RW(removable);
+
+static struct configfs_attribute *fsg_lun_attrs[] = {
+	&fsg_lun_ro.attr,
+	&fsg_lun_nofua.attr,
+	&fsg_lun_file.attr,
+	&fsg_lun_removable.attr,
+	NULL,
+};
+
+static struct fsg_lun *to_fsg_lun(struct config_item *item)
+{
+	return item ? container_of(to_config_group(item), struct fsg_lun, item)
+		: NULL;
+}
+
+CONFIGFS_ATTR_OPS(fsg_lun);
+
+static void fsg_lun_item_release(struct config_item *item)
 {
-	return container_of(dev, struct fsg_lun, dev);
+	kfree(to_fsg_lun(item));
 }
 
+static struct configfs_item_operations fsg_lun_ops = {
+	.show_attribute		= fsg_lun_attr_show,
+	.store_attribute	= fsg_lun_attr_store,
+	.release		= fsg_lun_item_release,
+};
+
+static struct config_item_type fsg_lun_item_type = {
+	.ct_attrs	= fsg_lun_attrs,
+	.ct_item_ops	= &fsg_lun_ops,
+	.ct_owner	= THIS_MODULE,
+};
 
 /* Big enough to hold our biggest descriptor */
 #define EP0_BUFSIZE	256
@@ -199,9 +244,6 @@ static inline int fsg_num_buffers_validate(void)
 /* Default size of buffer length. */
 #define FSG_BUFLEN	((u32)16384)
 
-/* Maximal number of LUNs supported in mass storage function */
-#define FSG_MAX_LUNS	8
-
 enum fsg_buffer_state {
 	BUF_STATE_EMPTY = 0,
 	BUF_STATE_FULL,
@@ -226,29 +268,6 @@ struct fsg_buffhd {
 	int				outreq_busy;
 };
 
-enum fsg_state {
-	/* This one isn't used anywhere */
-	FSG_STATE_COMMAND_PHASE = -10,
-	FSG_STATE_DATA_PHASE,
-	FSG_STATE_STATUS_PHASE,
-
-	FSG_STATE_IDLE = 0,
-	FSG_STATE_ABORT_BULK_OUT,
-	FSG_STATE_RESET,
-	FSG_STATE_INTERFACE_CHANGE,
-	FSG_STATE_CONFIG_CHANGE,
-	FSG_STATE_DISCONNECT,
-	FSG_STATE_EXIT,
-	FSG_STATE_TERMINATED
-};
-
-enum data_direction {
-	DATA_DIR_UNKNOWN = 0,
-	DATA_DIR_FROM_HOST,
-	DATA_DIR_TO_HOST,
-	DATA_DIR_NONE
-};
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -468,6 +487,8 @@ static void fsg_lun_close(struct fsg_lun *curlun)
 		LDBG(curlun, "close backing file\n");
 		fput(curlun->filp);
 		curlun->filp = NULL;
+		configfs_undepend_item(curlun->item.cg_subsys,
+				       &curlun->item.cg_item);
 	}
 }
 
@@ -484,6 +505,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	unsigned int			blkbits;
 	unsigned int			blksize;
 
+	configfs_depend_item(curlun->item.cg_subsys, &curlun->item.cg_item);
+
 	/* R/W if we can, R/O if we must */
 	ro = curlun->initially_ro;
 	if (!ro) {
@@ -567,6 +590,9 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 
 out:
 	fput(filp);
+	if (rc)
+		configfs_undepend_item(curlun->item.cg_subsys,
+				       &curlun->item.cg_item);
 	return rc;
 }
 
@@ -608,29 +634,21 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
 /*-------------------------------------------------------------------------*/
 
 
-static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
-			   char *buf)
+static ssize_t fsg_lun_show_ro(struct fsg_lun *curlun, char *buf)
 {
-	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
-
 	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
 				  ? curlun->ro
 				  : curlun->initially_ro);
 }
 
-static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
-			      char *buf)
+static ssize_t fsg_lun_show_nofua(struct fsg_lun *curlun, char *buf)
 {
-	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
-
 	return sprintf(buf, "%u\n", curlun->nofua);
 }
 
-static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
-			     char *buf)
+static ssize_t fsg_lun_show_file(struct fsg_lun *curlun, char *buf)
 {
-	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
-	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
+	struct rw_semaphore	*filesem = curlun->filesem;
 	char		*p;
 	ssize_t		rc;
 
@@ -653,13 +671,11 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
 	return rc;
 }
 
-
-static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count)
+static ssize_t fsg_lun_store_ro(struct fsg_lun *curlun, const char *buf,
+				size_t count)
 {
 	ssize_t		rc;
-	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
-	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
+	struct rw_semaphore	*filesem = curlun->filesem;
 	unsigned	ro;
 
 	rc = kstrtouint(buf, 2, &ro);
@@ -684,11 +700,9 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
 	return rc;
 }
 
-static ssize_t fsg_store_nofua(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
+static ssize_t fsg_lun_store_nofua(struct fsg_lun *curlun, const char *buf,
+				   size_t count)
 {
-	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 	unsigned	nofua;
 	int		ret;
 
@@ -705,11 +719,10 @@ static ssize_t fsg_store_nofua(struct device *dev,
 	return count;
 }
 
-static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
-			      const char *buf, size_t count)
+static ssize_t fsg_lun_store_file(struct fsg_lun *curlun, const char *buf,
+				  size_t count)
 {
-	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
-	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
+	struct rw_semaphore	*filesem = curlun->filesem;
 	int		rc = 0;
 
 	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
@@ -736,3 +749,25 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
 	up_write(filesem);
 	return (rc < 0 ? rc : count);
 }
+
+static ssize_t fsg_lun_show_removable(struct fsg_lun *curlun, char *buf)
+{
+	return sprintf(buf, "%d\n", curlun->removable);
+}
+
+static ssize_t fsg_lun_store_removable(struct fsg_lun *curlun, const char *buf,
+				       size_t count)
+{
+	if (fsg_lun_is_open(curlun)) {
+		LDBG(curlun, "media type change prevented\n");
+		return -EBUSY;
+	}
+
+	if (buf[0] != '0' && buf[0] != '1')
+		return -EINVAL;
+
+	curlun->removable = buf[0] == '1';
+
+	return count;
+}
+
diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h
new file mode 100644
index 0000000..52528f2
--- /dev/null
+++ b/drivers/usb/gadget/storage_common.h
@@ -0,0 +1,43 @@
+#ifndef STORAGE_COMMON_H
+#define STORAGE_COMMON_H
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define FSG_VENDOR_ID	0x0525	/* NetChip */
+#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
+
+/* Maximal number of LUNs supported in mass storage function */
+#define FSG_MAX_LUNS	8
+
+/* Length of a SCSI Command Data Block */
+#define MAX_COMMAND_SIZE	16
+
+enum fsg_state {
+	/* This one isn't used anywhere */
+	FSG_STATE_COMMAND_PHASE = -10,
+	FSG_STATE_DATA_PHASE,
+	FSG_STATE_STATUS_PHASE,
+
+	FSG_STATE_IDLE = 0,
+	FSG_STATE_ABORT_BULK_OUT,
+	FSG_STATE_RESET,
+	FSG_STATE_INTERFACE_CHANGE,
+	FSG_STATE_CONFIG_CHANGE,
+	FSG_STATE_DISCONNECT,
+	FSG_STATE_EXIT,
+	FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+	DATA_DIR_UNKNOWN = 0,
+	DATA_DIR_FROM_HOST,
+	DATA_DIR_TO_HOST,
+	DATA_DIR_NONE
+};
+
+
+#endif
-- 
1.7.0.4

--
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