summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2015-12-11 16:06:26 +0100
committerNicholas Bellinger <nab@linux-iscsi.org>2015-12-20 19:40:45 -0800
commit4bb8548df632187d5db50878e71804af5f7c51ad (patch)
treebece45a2277b6ae37cdc7dd873166b7334a80ae7 /drivers/usb/gadget
parent9beab5d4f2ef6f5b8f26506d94ed68deb42af882 (diff)
usb: gadget: f_tcm: add configfs support
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>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig14
-rw-r--r--drivers/usb/gadget/function/f_tcm.c72
2 files changed, 82 insertions, 4 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5bf50db692cd..0527308334ac 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -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
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 4a004634dafe..ec8287a3a9da 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -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;
}