mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
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>
This commit is contained in:
parent
9beab5d4f2
commit
4bb8548df6
6
Documentation/ABI/testing/configfs-usb-gadget-tcm
Normal file
6
Documentation/ABI/testing/configfs-usb-gadget-tcm
Normal file
|
|
@ -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.
|
||||||
|
|
@ -454,6 +454,20 @@ config USB_CONFIGFS_F_PRINTER
|
||||||
For more information, see Documentation/usb/gadget_printer.txt
|
For more information, see Documentation/usb/gadget_printer.txt
|
||||||
which includes sample code for accessing the device file.
|
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"
|
source "drivers/usb/gadget/legacy/Kconfig"
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "tcm.h"
|
#include "tcm.h"
|
||||||
#include "u_tcm.h"
|
#include "u_tcm.h"
|
||||||
|
#include "configfs.h"
|
||||||
|
|
||||||
#define TPG_INSTANCES 1
|
#define TPG_INSTANCES 1
|
||||||
|
|
||||||
|
|
@ -1402,8 +1403,16 @@ static struct se_portal_group *usbg_make_tpg(
|
||||||
if (!opts->ready)
|
if (!opts->ready)
|
||||||
goto unlock_dep;
|
goto unlock_dep;
|
||||||
|
|
||||||
if (opts->has_dep && !try_module_get(opts->dependent))
|
if (opts->has_dep) {
|
||||||
goto unlock_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);
|
tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
|
@ -1437,7 +1446,10 @@ static struct se_portal_group *usbg_make_tpg(
|
||||||
free_tpg:
|
free_tpg:
|
||||||
kfree(tpg);
|
kfree(tpg);
|
||||||
unref_dep:
|
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:
|
unlock_dep:
|
||||||
mutex_unlock(&opts->dep_lock);
|
mutex_unlock(&opts->dep_lock);
|
||||||
unlock_inst:
|
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,
|
opts = container_of(tpg_instances[i].func_inst,
|
||||||
struct f_tcm_opts, func_inst);
|
struct f_tcm_opts, func_inst);
|
||||||
mutex_lock(&opts->dep_lock);
|
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(&opts->dep_lock);
|
||||||
mutex_unlock(&tpg_instances_lock);
|
mutex_unlock(&tpg_instances_lock);
|
||||||
|
|
||||||
|
|
@ -2175,6 +2190,28 @@ static int tcm_setup(struct usb_function *f,
|
||||||
return usbg_bot_setup(f, ctrl);
|
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)
|
static void tcm_free_inst(struct usb_function_instance *f)
|
||||||
{
|
{
|
||||||
struct f_tcm_opts *opts;
|
struct f_tcm_opts *opts;
|
||||||
|
|
@ -2193,6 +2230,28 @@ static void tcm_free_inst(struct usb_function_instance *f)
|
||||||
kfree(opts);
|
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)
|
static int usbg_attach(struct usbg_tpg *tpg)
|
||||||
{
|
{
|
||||||
struct usb_function_instance *f = tpg->fi;
|
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);
|
mutex_init(&opts->dep_lock);
|
||||||
opts->func_inst.set_inst_name = tcm_set_name;
|
opts->func_inst.set_inst_name = tcm_set_name;
|
||||||
opts->func_inst.free_func_inst = tcm_free_inst;
|
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;
|
return &opts->func_inst;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user