summaryrefslogtreecommitdiff
path: root/patches.tizen/1140-usb-gadget-f_mass_storage-add-configfs-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches.tizen/1140-usb-gadget-f_mass_storage-add-configfs-support.patch')
-rw-r--r--patches.tizen/1140-usb-gadget-f_mass_storage-add-configfs-support.patch526
1 files changed, 526 insertions, 0 deletions
diff --git a/patches.tizen/1140-usb-gadget-f_mass_storage-add-configfs-support.patch b/patches.tizen/1140-usb-gadget-f_mass_storage-add-configfs-support.patch
new file mode 100644
index 00000000000..ef55e17d6f7
--- /dev/null
+++ b/patches.tizen/1140-usb-gadget-f_mass_storage-add-configfs-support.patch
@@ -0,0 +1,526 @@
+From 8fc023846b2c3d6d8c779ebd9ed354e518d42b1d Mon Sep 17 00:00:00 2001
+From: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+Date: Wed, 9 Oct 2013 10:06:05 +0200
+Subject: [PATCH 1140/1302] usb: gadget: f_mass_storage: add configfs support
+
+From this commit on f_mass_storage is available through configfs.
+
+Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
+Signed-off-by: Felipe Balbi <balbi@ti.com>
+Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
+---
+ .../ABI/testing/configfs-usb-gadget-mass-storage | 31 ++
+ drivers/usb/gadget/Kconfig | 11 +
+ drivers/usb/gadget/f_mass_storage.c | 360 +++++++++++++++++++++
+ drivers/usb/gadget/f_mass_storage.h | 17 +
+ 4 files changed, 419 insertions(+)
+ create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-mass-storage
+
+diff --git a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage
+new file mode 100644
+index 0000000..ad72a37
+--- /dev/null
++++ b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage
+@@ -0,0 +1,31 @@
++What: /config/usb-gadget/gadget/functions/mass_storage.name
++Date: Oct 2013
++KenelVersion: 3.13
++Description:
++ The attributes:
++
++ stall - Set to permit function to halt bulk endpoints.
++ Disabled on some USB devices known not to work
++ correctly. You should set it to true.
++ num_buffers - Number of pipeline buffers. Valid numbers
++ are 2..4. Available only if
++ CONFIG_USB_GADGET_DEBUG_FILES is set.
++
++What: /config/usb-gadget/gadget/functions/mass_storage.name/lun.name
++Date: Oct 2013
++KenelVersion: 3.13
++Description:
++ The attributes:
++
++ file - The path to the backing file for the LUN.
++ Required if LUN is not marked as removable.
++ ro - Flag specifying access to the LUN shall be
++ read-only. This is implied if CD-ROM emulation
++ is enabled as well as when it was impossible
++ to open "filename" in R/W mode.
++ removable - Flag specifying that LUN shall be indicated as
++ being removable.
++ cdrom - Flag specifying that LUN shall be reported as
++ being a CD-ROM.
++ nofua - Flag specifying that FUA flag
++ in SCSI WRITE(10,12)
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 6214b79..bef6e86 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -680,6 +680,17 @@ config USB_CONFIGFS_PHONET
+ help
+ The Phonet protocol implementation for USB device.
+
++config USB_CONFIGFS_MASS_STORAGE
++ boolean "Mass storage"
++ depends on USB_CONFIGFS
++ select USB_U_MS
++ select USB_F_MASS_STORAGE
++ help
++ The Mass Storage Gadget acts as a USB Mass Storage disk drive.
++ As its storage repository it can use a regular file or a block
++ device (in much the same way as the "loop" device driver),
++ specified as a module parameter or sysfs option.
++
+ config USB_ZERO
+ tristate "Gadget Zero (DEVELOPMENT)"
+ select USB_LIBCOMPOSITE
+diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
+index d80be5f..00d3687 100644
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -220,6 +220,7 @@
+ #include <linux/usb/composite.h>
+
+ #include "gadget_chips.h"
++#include "configfs.h"
+
+
+ /*------------------------------------------------------------------------*/
+@@ -3295,6 +3296,342 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
+
+ #else
+
++static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item)
++{
++ return container_of(to_config_group(item), struct fsg_lun_opts, group);
++}
++
++static inline struct fsg_opts *to_fsg_opts(struct config_item *item)
++{
++ return container_of(to_config_group(item), struct fsg_opts,
++ func_inst.group);
++}
++
++CONFIGFS_ATTR_STRUCT(fsg_lun_opts);
++CONFIGFS_ATTR_OPS(fsg_lun_opts);
++
++static void fsg_lun_attr_release(struct config_item *item)
++{
++ struct fsg_lun_opts *lun_opts;
++
++ lun_opts = to_fsg_lun_opts(item);
++ kfree(lun_opts);
++}
++
++static struct configfs_item_operations fsg_lun_item_ops = {
++ .release = fsg_lun_attr_release,
++ .show_attribute = fsg_lun_opts_attr_show,
++ .store_attribute = fsg_lun_opts_attr_store,
++};
++
++static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page)
++{
++ struct fsg_opts *fsg_opts;
++
++ fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
++
++ return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page);
++}
++
++static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts,
++ const char *page, size_t len)
++{
++ struct fsg_opts *fsg_opts;
++
++ fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
++
++ return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len);
++}
++
++static struct fsg_lun_opts_attribute fsg_lun_opts_file =
++ __CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show,
++ fsg_lun_opts_file_store);
++
++static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page)
++{
++ return fsg_show_ro(opts->lun, page);
++}
++
++static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts,
++ const char *page, size_t len)
++{
++ struct fsg_opts *fsg_opts;
++
++ fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
++
++ return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len);
++}
++
++static struct fsg_lun_opts_attribute fsg_lun_opts_ro =
++ __CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show,
++ fsg_lun_opts_ro_store);
++
++static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts,
++ char *page)
++{
++ return fsg_show_removable(opts->lun, page);
++}
++
++static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts,
++ const char *page, size_t len)
++{
++ return fsg_store_removable(opts->lun, page, len);
++}
++
++static struct fsg_lun_opts_attribute fsg_lun_opts_removable =
++ __CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR,
++ fsg_lun_opts_removable_show,
++ fsg_lun_opts_removable_store);
++
++static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page)
++{
++ return fsg_show_cdrom(opts->lun, page);
++}
++
++static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts,
++ const char *page, size_t len)
++{
++ return fsg_store_cdrom(opts->lun, page, len);
++}
++
++static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom =
++ __CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show,
++ fsg_lun_opts_cdrom_store);
++
++static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page)
++{
++ return fsg_show_nofua(opts->lun, page);
++}
++
++static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts,
++ const char *page, size_t len)
++{
++ return fsg_store_nofua(opts->lun, page, len);
++}
++
++static struct fsg_lun_opts_attribute fsg_lun_opts_nofua =
++ __CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show,
++ fsg_lun_opts_nofua_store);
++
++static struct configfs_attribute *fsg_lun_attrs[] = {
++ &fsg_lun_opts_file.attr,
++ &fsg_lun_opts_ro.attr,
++ &fsg_lun_opts_removable.attr,
++ &fsg_lun_opts_cdrom.attr,
++ &fsg_lun_opts_nofua.attr,
++ NULL,
++};
++
++static struct config_item_type fsg_lun_type = {
++ .ct_item_ops = &fsg_lun_item_ops,
++ .ct_attrs = fsg_lun_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++#define MAX_NAME_LEN 40
++
++static struct config_group *fsg_lun_make(struct config_group *group,
++ const char *name)
++{
++ struct fsg_lun_opts *opts;
++ struct fsg_opts *fsg_opts;
++ struct fsg_lun_config config;
++ char *num_str;
++ u8 num;
++ int ret;
++
++ num_str = strchr(name, '.');
++ if (!num_str) {
++ pr_err("Unable to locate . in LUN.NUMBER\n");
++ return ERR_PTR(-EINVAL);
++ }
++ num_str++;
++
++ ret = kstrtou8(num_str, 0, &num);
++ if (ret)
++ return ERR_PTR(ret);
++
++ fsg_opts = to_fsg_opts(&group->cg_item);
++ if (num >= FSG_MAX_LUNS)
++ return ERR_PTR(-ENODEV);
++ mutex_lock(&fsg_opts->lock);
++ if (fsg_opts->refcnt || fsg_opts->common->luns[num]) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
++ if (!opts) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ memset(&config, 0, sizeof(config));
++ config.removable = true;
++
++
++ ret = fsg_common_create_lun(fsg_opts->common, &config, num, name,
++ (const char **)&group->cg_item.ci_name);
++ if (ret) {
++ kfree(opts);
++ goto out;
++ }
++ opts->lun = fsg_opts->common->luns[num];
++ opts->lun_id = num;
++ mutex_unlock(&fsg_opts->lock);
++
++ config_group_init_type_name(&opts->group, name, &fsg_lun_type);
++
++ return &opts->group;
++out:
++ mutex_unlock(&fsg_opts->lock);
++ return ERR_PTR(ret);
++}
++
++static void fsg_lun_drop(struct config_group *group, struct config_item *item)
++{
++ struct fsg_lun_opts *lun_opts;
++ struct fsg_opts *fsg_opts;
++
++ lun_opts = to_fsg_lun_opts(item);
++ fsg_opts = to_fsg_opts(&group->cg_item);
++
++ mutex_lock(&fsg_opts->lock);
++ if (fsg_opts->refcnt) {
++ struct config_item *gadget;
++
++ gadget = group->cg_item.ci_parent->ci_parent;
++ unregister_gadget_item(gadget);
++ }
++
++ fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs);
++ fsg_opts->common->luns[lun_opts->lun_id] = NULL;
++ lun_opts->lun_id = 0;
++ mutex_unlock(&fsg_opts->lock);
++
++ config_item_put(item);
++}
++
++CONFIGFS_ATTR_STRUCT(fsg_opts);
++CONFIGFS_ATTR_OPS(fsg_opts);
++
++static void fsg_attr_release(struct config_item *item)
++{
++ struct fsg_opts *opts = to_fsg_opts(item);
++
++ usb_put_function_instance(&opts->func_inst);
++}
++
++static struct configfs_item_operations fsg_item_ops = {
++ .release = fsg_attr_release,
++ .show_attribute = fsg_opts_attr_show,
++ .store_attribute = fsg_opts_attr_store,
++};
++
++static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page)
++{
++ int result;
++
++ mutex_lock(&opts->lock);
++ result = sprintf(page, "%d", opts->common->can_stall);
++ mutex_unlock(&opts->lock);
++
++ return result;
++}
++
++static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page,
++ size_t len)
++{
++ int ret;
++ u8 num;
++
++ mutex_lock(&opts->lock);
++ if (opts->refcnt) {
++ ret = -EBUSY;
++ goto end;
++ }
++ ret = kstrtou8(page, 0, &num);
++ if (ret)
++ goto end;
++
++ opts->common->can_stall = num != 0;
++ ret = len;
++
++end:
++ mutex_unlock(&opts->lock);
++ return ret;
++}
++
++static struct fsg_opts_attribute fsg_opts_stall =
++ __CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show,
++ fsg_opts_stall_store);
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FILES
++static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page)
++{
++ int result;
++
++ mutex_lock(&opts->lock);
++ result = sprintf(page, "%d", opts->common->fsg_num_buffers);
++ mutex_unlock(&opts->lock);
++
++ return result;
++}
++
++static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts,
++ const char *page, size_t len)
++{
++ int ret;
++ u8 num;
++
++ mutex_lock(&opts->lock);
++ if (opts->refcnt) {
++ ret = -EBUSY;
++ goto end;
++ }
++ ret = kstrtou8(page, 0, &num);
++ if (ret)
++ goto end;
++
++ ret = fsg_num_buffers_validate(num);
++ if (ret)
++ goto end;
++
++ fsg_common_set_num_buffers(opts->common, num);
++ ret = len;
++
++end:
++ mutex_unlock(&opts->lock);
++ return ret;
++}
++
++static struct fsg_opts_attribute fsg_opts_num_buffers =
++ __CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR,
++ fsg_opts_num_buffers_show,
++ fsg_opts_num_buffers_store);
++
++#endif
++
++static struct configfs_attribute *fsg_attrs[] = {
++ &fsg_opts_stall.attr,
++#ifdef CONFIG_USB_GADGET_DEBUG_FILES
++ &fsg_opts_num_buffers.attr,
++#endif
++ NULL,
++};
++
++static struct configfs_group_operations fsg_group_ops = {
++ .make_group = fsg_lun_make,
++ .drop_item = fsg_lun_drop,
++};
++
++static struct config_item_type fsg_func_type = {
++ .ct_item_ops = &fsg_item_ops,
++ .ct_group_ops = &fsg_group_ops,
++ .ct_attrs = fsg_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
+ static void fsg_free_inst(struct usb_function_instance *fi)
+ {
+ struct fsg_opts *opts;
+@@ -3307,11 +3644,13 @@ static void fsg_free_inst(struct usb_function_instance *fi)
+ static struct usb_function_instance *fsg_alloc_inst(void)
+ {
+ struct fsg_opts *opts;
++ struct fsg_lun_config config;
+ int rc;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
++ mutex_init(&opts->lock);
+ opts->func_inst.free_func_inst = fsg_free_inst;
+ opts->common = fsg_common_setup(opts->common, false);
+ if (IS_ERR(opts->common)) {
+@@ -3329,6 +3668,18 @@ static struct usb_function_instance *fsg_alloc_inst(void)
+
+ pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+
++ memset(&config, 0, sizeof(config));
++ config.removable = true;
++ rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0",
++ (const char **)&opts->func_inst.group.cg_item.ci_name);
++ opts->lun0.lun = opts->common->luns[0];
++ opts->lun0.lun_id = 0;
++ config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
++ opts->default_groups[0] = &opts->lun0.group;
++ opts->func_inst.group.default_groups = opts->default_groups;
++
++ config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type);
++
+ return &opts->func_inst;
+
+ release_luns:
+@@ -3341,8 +3692,14 @@ release_opts:
+ static void fsg_free(struct usb_function *f)
+ {
+ struct fsg_dev *fsg;
++ struct fsg_opts *opts;
+
+ fsg = container_of(f, struct fsg_dev, function);
++ opts = container_of(f->fi, struct fsg_opts, func_inst);
++
++ mutex_lock(&opts->lock);
++ opts->refcnt--;
++ mutex_unlock(&opts->lock);
+
+ kfree(fsg);
+ }
+@@ -3357,6 +3714,9 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
+ if (unlikely(!fsg))
+ return ERR_PTR(-ENOMEM);
+
++ mutex_lock(&opts->lock);
++ opts->refcnt++;
++ mutex_unlock(&opts->lock);
+ fsg->function.name = FSG_DRIVER_DESC;
+ fsg->function.bind = fsg_bind;
+ fsg->function.unbind = fsg_unbind;
+diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h
+index b53cf8c..7d421d2 100644
+--- a/drivers/usb/gadget/f_mass_storage.h
++++ b/drivers/usb/gadget/f_mass_storage.h
+@@ -71,10 +71,27 @@ struct fsg_operations {
+ int (*thread_exits)(struct fsg_common *common);
+ };
+
++struct fsg_lun_opts {
++ struct config_group group;
++ struct fsg_lun *lun;
++ int lun_id;
++};
++
+ struct fsg_opts {
+ struct fsg_common *common;
+ struct usb_function_instance func_inst;
++ struct fsg_lun_opts lun0;
++ struct config_group *default_groups[2];
+ bool no_configfs; /* for legacy gadgets */
++
++ /*
++ * Read/write access to configfs attributes is handled by configfs.
++ *
++ * This is to protect the data from concurrent access by read/write
++ * and create symlink/remove symlink.
++ */
++ struct mutex lock;
++ int refcnt;
+ };
+
+ struct fsg_lun_config {
+--
+1.8.3.2
+