diff --git a/Documentation/ABI/testing/configfs-usb-gadget-tcm b/Documentation/ABI/testing/configfs-usb-gadget-tcm new file mode 100644 index 0000000000000000000000000000000000000000..a29ed2dd6173dcab8f2335b0eeb65d9be31f3541 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-tcm @@ -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. diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5bf50db692cd6b7476c20062a81cdf8854e8b71c..0527308334ac4d2eaadec7f65f1ea1c85dc87b24 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 4a004634dafed307ac67e65a67be6b5cb38a4df1..ec8287a3a9da231fd042214274c5b07d1290a61c 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 @@ static struct se_portal_group *usbg_make_tpg( 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; }