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)
struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
func_inst);
config_item_put(&uvc->header->item);
if (!opts->header)
config_item_put(&uvc->header->item);
--opts->refcnt;
kfree(uvc);
}
......@@ -1051,25 +1052,29 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
streaming = config_group_find_item(&opts->func_inst.group, "streaming");
if (!streaming)
goto err_config;
header = config_group_find_item(to_config_group(streaming), "header");
config_item_put(streaming);
if (!header)
goto err_config;
h = config_group_find_item(to_config_group(header), "h");
config_item_put(header);
if (!h)
goto err_config;
uvc->header = to_uvcg_streaming_header(h);
if (!uvc->header->linked) {
mutex_unlock(&opts->lock);
kfree(uvc);
return ERR_PTR(-EBUSY);
if (opts->header) {
uvc->header = opts->header;
} else {
streaming = config_group_find_item(&opts->func_inst.group, "streaming");
if (!streaming)
goto err_config;
header = config_group_find_item(to_config_group(streaming), "header");
config_item_put(streaming);
if (!header)
goto err_config;
h = config_group_find_item(to_config_group(header), "h");
config_item_put(header);
if (!h)
goto err_config;
uvc->header = to_uvcg_streaming_header(h);
if (!uvc->header->linked) {
mutex_unlock(&opts->lock);
kfree(uvc);
return ERR_PTR(-EBUSY);
}
}
uvc->desc.extension_units = &opts->extension_units;
......
......@@ -98,6 +98,12 @@ struct f_uvc_opts {
*/
struct mutex lock;
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 */
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