[RFCv4 PATCH 11/13] usb: gadget: example port of mass storage to UFG: f_mass_storage: add configfs type

[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/f_mass_storage.c |  225 +++++++++++++++++++++++++++++++++++
 1 files changed, 225 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index b244ddc..c9b9d06 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2521,6 +2521,205 @@ void fsg_common_put(struct fsg_common *common)
 }
 EXPORT_SYMBOL(fsg_common_put);
 
+static struct config_item *alloc_fsg_lun(struct config_group *group,
+					 const char *name)
+{
+	struct fsg_common *common;
+	struct fsg_lun *lun;
+	struct config_item *item;
+	unsigned int tmp;
+	unsigned int leading_zeros;
+	int len;
+	const char *p;
+
+	common = group ? container_of(group, struct fsg_common, group) : NULL;
+	if (!common)
+		return ERR_PTR(-ENOMEM);
+
+	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);
+
+	list_for_each_entry(item, &common->group.cg_children, ci_entry) {
+		lun = to_fsg_lun(item);
+		if (tmp == lun->n_lun)
+			return ERR_PTR(-EBUSY);
+	}
+
+	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, 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->item;
+}
+
+static ssize_t fsg_common_show_luns(struct fsg_common *common, char *buf)
+{
+	return sprintf(buf, "%d\n", common->nluns);
+}
+
+static ssize_t fsg_common_store_luns(struct fsg_common *common, const char *buf,
+				     size_t count)
+{
+	struct config_item *function, *config, *gadget;
+	struct dentry *parent, *new;
+	char n[UFG_STR_LEN];
+	u16 tmp;
+	char *p = (char *)buf;
+	int rc;
+
+	function = common->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;
+	parent = common->group.cg_item.ci_dentry;
+	for (tmp = 0; tmp < common->nluns; tmp++) {
+		struct qstr name;
+
+		sprintf(n, "lun%d", tmp);
+		name.name = n;
+		name.len = strlen(name.name);
+		name.hash = full_name_hash(name.name, name.len);
+
+		new = d_alloc(parent, &name);
+		if (IS_ERR_OR_NULL(new)) {
+			rc = -ENOMEM;
+			goto rollback;
+		}
+		d_add(new, NULL);
+		rc = ufg_mkdir(parent, new);
+		if (rc) {
+			d_drop(new);
+			dput(new);
+
+			goto rollback;
+		}
+		dput(new); /* make the refcount 1 */
+	}
+
+	return count;
+
+rollback:
+	while (tmp--) {
+		struct config_item *child;
+
+		sprintf(n, "lun%d", tmp);
+		child = config_group_find_item(&common->group, n);
+		if (child)
+			ufg_rmdir(parent, child->ci_dentry);
+		
+	}
+	return rc;
+}
+
+static ssize_t fsg_common_show_stall(struct fsg_common *common, char *buf)
+{
+	return sprintf(buf, "%d\n", common->can_stall);
+}
+
+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)
+{
+	return item ? container_of(to_config_group(item),
+				   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 configfs_group_operations fsg_common_group_ops = {
+	.make_item	= alloc_fsg_lun,
+};
+
+static struct config_item_type fsg_common_item_type = {
+	.ct_attrs	= fsg_common_attrs,
+	.ct_item_ops	= &fsg_common_item_ops,
+	.ct_group_ops	= &fsg_common_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
 struct fsg_common *fsg_common_init(struct fsg_common *common)
 {
 	struct fsg_buffhd *bh;
@@ -2638,6 +2837,32 @@ error_release:
 	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;
+	}
+
+	config_group_init_type_name(&common->group, n, &fsg_common_item_type);
+
+	return &common->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);
-- 
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