usb: gadget: f_tcm: add configfs support
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Fri, 11 Dec 2015 15:06:26 +0000 (16:06 +0100)
committerNicholas Bellinger <nab@linux-iscsi.org>
Mon, 21 Dec 2015 03:40:45 +0000 (19:40 -0800)
Allow using the tcm function as a component of a gadget composed with
ConfigFS.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Documentation/ABI/testing/configfs-usb-gadget-tcm [new file with mode: 0644]
drivers/usb/gadget/Kconfig
drivers/usb/gadget/function/f_tcm.c

diff --git a/Documentation/ABI/testing/configfs-usb-gadget-tcm b/Documentation/ABI/testing/configfs-usb-gadget-tcm
new file mode 100644 (file)
index 0000000..a29ed2d
--- /dev/null
@@ -0,0 +1,6 @@
+What:          /config/usb-gadget/gadget/functions/tcm.name
+Date:          Dec 2015
+KernelVersion: 4.5
+Description:
+               There are no attributes because all the configuration
+               is performed in the "target" subsystem of configfs.
index 5bf50db692cd6b7476c20062a81cdf8854e8b71c..0527308334ac4d2eaadec7f65f1ea1c85dc87b24 100644 (file)
@@ -454,6 +454,20 @@ config USB_CONFIGFS_F_PRINTER
          For more information, see Documentation/usb/gadget_printer.txt
          which includes sample code for accessing the device file.
 
+config USB_CONFIGFS_F_TCM
+       bool "USB Gadget Target Fabric"
+       depends on TARGET_CORE
+       depends on USB_CONFIGFS
+       select USB_LIBCOMPOSITE
+       select USB_F_TCM
+       help
+         This fabric is a USB gadget component. Two USB protocols are
+         supported that is BBB or BOT (Bulk Only Transport) and UAS
+         (USB Attached SCSI). BOT is advertised on alternative
+         interface 0 (primary) and UAS is on alternative interface 1.
+         Both protocols can work on USB2.0 and USB3.0.
+         UAS utilizes the USB 3.0 feature called streams support.
+
 source "drivers/usb/gadget/legacy/Kconfig"
 
 endchoice
index 4a004634dafed307ac67e65a67be6b5cb38a4df1..ec8287a3a9da231fd042214274c5b07d1290a61c 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "tcm.h"
 #include "u_tcm.h"
+#include "configfs.h"
 
 #define TPG_INSTANCES          1
 
@@ -1402,8 +1403,16 @@ static struct se_portal_group *usbg_make_tpg(
        if (!opts->ready)
                goto unlock_dep;
 
-       if (opts->has_dep && !try_module_get(opts->dependent))
-               goto unlock_dep;
+       if (opts->has_dep) {
+               if (!try_module_get(opts->dependent))
+                       goto unlock_dep;
+       } else {
+               ret = configfs_depend_item_unlocked(
+                       group->cg_subsys,
+                       &opts->func_inst.group.cg_item);
+               if (ret)
+                       goto unlock_dep;
+       }
 
        tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
        ret = -ENOMEM;
@@ -1437,7 +1446,10 @@ free_workqueue:
 free_tpg:
        kfree(tpg);
 unref_dep:
-       module_put(opts->dependent);
+       if (opts->has_dep)
+               module_put(opts->dependent);
+       else
+               configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
 unlock_dep:
        mutex_unlock(&opts->dep_lock);
 unlock_inst:
@@ -1468,7 +1480,10 @@ static void usbg_drop_tpg(struct se_portal_group *se_tpg)
        opts = container_of(tpg_instances[i].func_inst,
                struct f_tcm_opts, func_inst);
        mutex_lock(&opts->dep_lock);
-       module_put(opts->dependent);
+       if (opts->has_dep)
+               module_put(opts->dependent);
+       else
+               configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
        mutex_unlock(&opts->dep_lock);
        mutex_unlock(&tpg_instances_lock);
 
@@ -2175,6 +2190,28 @@ static int tcm_setup(struct usb_function *f,
        return usbg_bot_setup(f, ctrl);
 }
 
+static inline struct f_tcm_opts *to_f_tcm_opts(struct config_item *item)
+{
+       return container_of(to_config_group(item), struct f_tcm_opts,
+               func_inst.group);
+}
+
+static void tcm_attr_release(struct config_item *item)
+{
+       struct f_tcm_opts *opts = to_f_tcm_opts(item);
+
+       usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations tcm_item_ops = {
+       .release                = tcm_attr_release,
+};
+
+static struct config_item_type tcm_func_type = {
+       .ct_item_ops    = &tcm_item_ops,
+       .ct_owner       = THIS_MODULE,
+};
+
 static void tcm_free_inst(struct usb_function_instance *f)
 {
        struct f_tcm_opts *opts;
@@ -2193,6 +2230,28 @@ static void tcm_free_inst(struct usb_function_instance *f)
        kfree(opts);
 }
 
+static int tcm_register_callback(struct usb_function_instance *f)
+{
+       struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+       mutex_lock(&opts->dep_lock);
+       opts->can_attach = true;
+       mutex_unlock(&opts->dep_lock);
+
+       return 0;
+}
+
+static void tcm_unregister_callback(struct usb_function_instance *f)
+{
+       struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+       mutex_lock(&opts->dep_lock);
+       unregister_gadget_item(opts->
+               func_inst.group.cg_item.ci_parent->ci_parent);
+       opts->can_attach = false;
+       mutex_unlock(&opts->dep_lock);
+}
+
 static int usbg_attach(struct usbg_tpg *tpg)
 {
        struct usb_function_instance *f = tpg->fi;
@@ -2252,6 +2311,11 @@ static struct usb_function_instance *tcm_alloc_inst(void)
        mutex_init(&opts->dep_lock);
        opts->func_inst.set_inst_name = tcm_set_name;
        opts->func_inst.free_func_inst = tcm_free_inst;
+       opts->tcm_register_callback = tcm_register_callback;
+       opts->tcm_unregister_callback = tcm_unregister_callback;
+
+       config_group_init_type_name(&opts->func_inst.group, "",
+                       &tcm_func_type);
 
        return &opts->func_inst;
 }