Commit f1fd91a0 authored by Andrzej Pietrasiewicz's avatar Andrzej Pietrasiewicz Committed by Greg Kroah-Hartman

usb: gadget: webcam: Make g_webcam loadable again

commit 588b9e85 ("usb: gadget: uvc: add v4l2 enumeration api calls")
has rendered the precomposed (aka legacy) webcam gadget unloadable.

uvc_alloc() since then has depended on certain config groups being
available in configfs tree related to the UVC function. However, legacy
gadgets do not create anything in configfs, so uvc_alloc() must fail
with -ENOENT no matter what.

This patch mimics the required configfs hierarchy to satisfy the code which
inspects formats and frames found in uvcg_streaming_header.

This has been tested with guvcview on the host side, using vivid as a
source of video stream on the device side and using the userspace program
found at https://gitlab.freedesktop.org/camera/uvc-gadget.git.
Signed-off-by: default avatarAndrzej Pietrasiewicz <andrzej.p@collabora.com>
Fixes: 588b9e85 ("usb: gadget: uvc: add v4l2 enumeration api calls")
Link: https://lore.kernel.org/r/20231215131614.29132-1-andrzej.p@collabora.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c51ffe92
...@@ -959,7 +959,8 @@ static void uvc_free(struct usb_function *f) ...@@ -959,7 +959,8 @@ static void uvc_free(struct usb_function *f)
struct uvc_device *uvc = to_uvc(f); struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts, struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
func_inst); func_inst);
config_item_put(&uvc->header->item); if (!opts->header)
config_item_put(&uvc->header->item);
--opts->refcnt; --opts->refcnt;
kfree(uvc); kfree(uvc);
} }
...@@ -1051,25 +1052,29 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) ...@@ -1051,25 +1052,29 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
uvc->desc.hs_streaming = opts->hs_streaming; uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming; uvc->desc.ss_streaming = opts->ss_streaming;
streaming = config_group_find_item(&opts->func_inst.group, "streaming"); if (opts->header) {
if (!streaming) uvc->header = opts->header;
goto err_config; } else {
streaming = config_group_find_item(&opts->func_inst.group, "streaming");
header = config_group_find_item(to_config_group(streaming), "header"); if (!streaming)
config_item_put(streaming); goto err_config;
if (!header)
goto err_config; header = config_group_find_item(to_config_group(streaming), "header");
config_item_put(streaming);
h = config_group_find_item(to_config_group(header), "h"); if (!header)
config_item_put(header); goto err_config;
if (!h)
goto err_config; h = config_group_find_item(to_config_group(header), "h");
config_item_put(header);
uvc->header = to_uvcg_streaming_header(h); if (!h)
if (!uvc->header->linked) { goto err_config;
mutex_unlock(&opts->lock);
kfree(uvc); uvc->header = to_uvcg_streaming_header(h);
return ERR_PTR(-EBUSY); if (!uvc->header->linked) {
mutex_unlock(&opts->lock);
kfree(uvc);
return ERR_PTR(-EBUSY);
}
} }
uvc->desc.extension_units = &opts->extension_units; uvc->desc.extension_units = &opts->extension_units;
......
...@@ -98,6 +98,12 @@ struct f_uvc_opts { ...@@ -98,6 +98,12 @@ struct f_uvc_opts {
*/ */
struct mutex lock; struct mutex lock;
int refcnt; int refcnt;
/*
* Only for legacy gadget. Shall be NULL for configfs-composed gadgets,
* which is guaranteed by alloc_inst implementation of f_uvc doing kzalloc.
*/
struct uvcg_streaming_header *header;
}; };
#endif /* U_UVC_H */ #endif /* U_UVC_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment