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 */
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/usb/video.h> #include <linux/usb/video.h>
#include "u_uvc.h" #include "u_uvc.h"
#include "uvc_configfs.h"
USB_GADGET_COMPOSITE_OPTIONS(); USB_GADGET_COMPOSITE_OPTIONS();
...@@ -84,8 +85,6 @@ static struct usb_device_descriptor webcam_device_descriptor = { ...@@ -84,8 +85,6 @@ static struct usb_device_descriptor webcam_device_descriptor = {
.bNumConfigurations = 0, /* dynamic */ .bNumConfigurations = 0, /* dynamic */
}; };
DECLARE_UVC_HEADER_DESCRIPTOR(1);
static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
.bLength = UVC_DT_HEADER_SIZE(1), .bLength = UVC_DT_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
...@@ -158,43 +157,112 @@ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = { ...@@ -158,43 +157,112 @@ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
.bmaControls[1][0] = 4, .bmaControls[1][0] = 4,
}; };
static const struct uvc_format_uncompressed uvc_format_yuv = { static const struct uvcg_color_matching uvcg_color_matching = {
.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, .desc = {
.bDescriptorType = USB_DT_CS_INTERFACE, .bLength = UVC_DT_COLOR_MATCHING_SIZE,
.bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, .bDescriptorType = USB_DT_CS_INTERFACE,
.bFormatIndex = 1, .bDescriptorSubType = UVC_VS_COLORFORMAT,
.bNumFrameDescriptors = 2, .bColorPrimaries = 1,
.guidFormat = .bTransferCharacteristics = 1,
{ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, .bMatrixCoefficients = 4,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}, },
.bBitsPerPixel = 16, };
.bDefaultFrameIndex = 1,
.bAspectRatioX = 0, static struct uvcg_uncompressed uvcg_format_yuv = {
.bAspectRatioY = 0, .fmt = {
.bmInterlaceFlags = 0, .type = UVCG_UNCOMPRESSED,
.bCopyProtect = 0, /* add to .frames and fill .num_frames at runtime */
.color_matching = (struct uvcg_color_matching *)&uvcg_color_matching,
},
.desc = {
.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
.bFormatIndex = 1,
.bNumFrameDescriptors = 2,
.guidFormat = {
'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
},
.bBitsPerPixel = 16,
.bDefaultFrameIndex = 1,
.bAspectRatioX = 0,
.bAspectRatioY = 0,
.bmInterlaceFlags = 0,
.bCopyProtect = 0,
},
};
static struct uvcg_format_ptr uvcg_format_ptr_yuv = {
.fmt = &uvcg_format_yuv.fmt,
}; };
DECLARE_UVC_FRAME_UNCOMPRESSED(1); DECLARE_UVC_FRAME_UNCOMPRESSED(1);
DECLARE_UVC_FRAME_UNCOMPRESSED(3); DECLARE_UVC_FRAME_UNCOMPRESSED(3);
#define UVCG_WIDTH_360P 640
#define UVCG_HEIGHT_360P 360
#define UVCG_MIN_BITRATE_360P 18432000
#define UVCG_MAX_BITRATE_360P 55296000
#define UVCG_MAX_VIDEO_FB_SZ_360P 460800
#define UVCG_FRM_INTERV_0_360P 666666
#define UVCG_FRM_INTERV_1_360P 1000000
#define UVCG_FRM_INTERV_2_360P 5000000
#define UVCG_DEFAULT_FRM_INTERV_360P UVCG_FRM_INTERV_0_360P
static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = { static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3), .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
.bFrameIndex = 1, .bFrameIndex = 1,
.bmCapabilities = 0, .bmCapabilities = 0,
.wWidth = cpu_to_le16(640), .wWidth = cpu_to_le16(UVCG_WIDTH_360P),
.wHeight = cpu_to_le16(360), .wHeight = cpu_to_le16(UVCG_HEIGHT_360P),
.dwMinBitRate = cpu_to_le32(18432000), .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P),
.dwMaxBitRate = cpu_to_le32(55296000), .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P),
.dwMaxVideoFrameBufferSize = cpu_to_le32(460800), .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P),
.dwDefaultFrameInterval = cpu_to_le32(666666), .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P),
.bFrameIntervalType = 3, .bFrameIntervalType = 3,
.dwFrameInterval[0] = cpu_to_le32(666666), .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P),
.dwFrameInterval[1] = cpu_to_le32(1000000), .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P),
.dwFrameInterval[2] = cpu_to_le32(5000000), .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P),
};
static u32 uvcg_frame_yuv_360p_dw_frame_interval[] = {
[0] = UVCG_FRM_INTERV_0_360P,
[1] = UVCG_FRM_INTERV_1_360P,
[2] = UVCG_FRM_INTERV_2_360P,
};
static const struct uvcg_frame uvcg_frame_yuv_360p = {
.fmt_type = UVCG_UNCOMPRESSED,
.frame = {
.b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
.b_descriptor_type = USB_DT_CS_INTERFACE,
.b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED,
.b_frame_index = 1,
.bm_capabilities = 0,
.w_width = UVCG_WIDTH_360P,
.w_height = UVCG_HEIGHT_360P,
.dw_min_bit_rate = UVCG_MIN_BITRATE_360P,
.dw_max_bit_rate = UVCG_MAX_BITRATE_360P,
.dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P,
.dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P,
.b_frame_interval_type = 3,
},
.dw_frame_interval = uvcg_frame_yuv_360p_dw_frame_interval,
};
static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_360p = {
.frm = (struct uvcg_frame *)&uvcg_frame_yuv_360p,
}; };
#define UVCG_WIDTH_720P 1280
#define UVCG_HEIGHT_720P 720
#define UVCG_MIN_BITRATE_720P 29491200
#define UVCG_MAX_BITRATE_720P 29491200
#define UVCG_MAX_VIDEO_FB_SZ_720P 1843200
#define UVCG_FRM_INTERV_0_720P 5000000
#define UVCG_DEFAULT_FRM_INTERV_720P UVCG_FRM_INTERV_0_720P
static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = { static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
...@@ -202,28 +270,66 @@ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = { ...@@ -202,28 +270,66 @@ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
.bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
.bFrameIndex = 2, .bFrameIndex = 2,
.bmCapabilities = 0, .bmCapabilities = 0,
.wWidth = cpu_to_le16(1280), .wWidth = cpu_to_le16(UVCG_WIDTH_720P),
.wHeight = cpu_to_le16(720), .wHeight = cpu_to_le16(UVCG_HEIGHT_720P),
.dwMinBitRate = cpu_to_le32(29491200), .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P),
.dwMaxBitRate = cpu_to_le32(29491200), .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P),
.dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P),
.dwDefaultFrameInterval = cpu_to_le32(5000000), .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P),
.bFrameIntervalType = 1, .bFrameIntervalType = 1,
.dwFrameInterval[0] = cpu_to_le32(5000000), .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P),
}; };
static const struct uvc_format_mjpeg uvc_format_mjpg = { static u32 uvcg_frame_yuv_720p_dw_frame_interval[] = {
.bLength = UVC_DT_FORMAT_MJPEG_SIZE, [0] = UVCG_FRM_INTERV_0_720P,
.bDescriptorType = USB_DT_CS_INTERFACE, };
.bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
.bFormatIndex = 2, static const struct uvcg_frame uvcg_frame_yuv_720p = {
.bNumFrameDescriptors = 2, .fmt_type = UVCG_UNCOMPRESSED,
.bmFlags = 0, .frame = {
.bDefaultFrameIndex = 1, .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
.bAspectRatioX = 0, .b_descriptor_type = USB_DT_CS_INTERFACE,
.bAspectRatioY = 0, .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED,
.bmInterlaceFlags = 0, .b_frame_index = 2,
.bCopyProtect = 0, .bm_capabilities = 0,
.w_width = UVCG_WIDTH_720P,
.w_height = UVCG_HEIGHT_720P,
.dw_min_bit_rate = UVCG_MIN_BITRATE_720P,
.dw_max_bit_rate = UVCG_MAX_BITRATE_720P,
.dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P,
.dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P,
.b_frame_interval_type = 1,
},
.dw_frame_interval = uvcg_frame_yuv_720p_dw_frame_interval,
};
static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_720p = {
.frm = (struct uvcg_frame *)&uvcg_frame_yuv_720p,
};
static struct uvcg_mjpeg uvcg_format_mjpeg = {
.fmt = {
.type = UVCG_MJPEG,
/* add to .frames and fill .num_frames at runtime */
.color_matching = (struct uvcg_color_matching *)&uvcg_color_matching,
},
.desc = {
.bLength = UVC_DT_FORMAT_MJPEG_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
.bFormatIndex = 2,
.bNumFrameDescriptors = 2,
.bmFlags = 0,
.bDefaultFrameIndex = 1,
.bAspectRatioX = 0,
.bAspectRatioY = 0,
.bmInterlaceFlags = 0,
.bCopyProtect = 0,
},
};
static struct uvcg_format_ptr uvcg_format_ptr_mjpeg = {
.fmt = &uvcg_format_mjpeg.fmt,
}; };
DECLARE_UVC_FRAME_MJPEG(1); DECLARE_UVC_FRAME_MJPEG(1);
...@@ -235,16 +341,45 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = { ...@@ -235,16 +341,45 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
.bDescriptorSubType = UVC_VS_FRAME_MJPEG, .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
.bFrameIndex = 1, .bFrameIndex = 1,
.bmCapabilities = 0, .bmCapabilities = 0,
.wWidth = cpu_to_le16(640), .wWidth = cpu_to_le16(UVCG_WIDTH_360P),
.wHeight = cpu_to_le16(360), .wHeight = cpu_to_le16(UVCG_HEIGHT_360P),
.dwMinBitRate = cpu_to_le32(18432000), .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P),
.dwMaxBitRate = cpu_to_le32(55296000), .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P),
.dwMaxVideoFrameBufferSize = cpu_to_le32(460800), .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P),
.dwDefaultFrameInterval = cpu_to_le32(666666), .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P),
.bFrameIntervalType = 3, .bFrameIntervalType = 3,
.dwFrameInterval[0] = cpu_to_le32(666666), .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P),
.dwFrameInterval[1] = cpu_to_le32(1000000), .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P),
.dwFrameInterval[2] = cpu_to_le32(5000000), .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P),
};
static u32 uvcg_frame_mjpeg_360p_dw_frame_interval[] = {
[0] = UVCG_FRM_INTERV_0_360P,
[1] = UVCG_FRM_INTERV_1_360P,
[2] = UVCG_FRM_INTERV_2_360P,
};
static const struct uvcg_frame uvcg_frame_mjpeg_360p = {
.fmt_type = UVCG_MJPEG,
.frame = {
.b_length = UVC_DT_FRAME_MJPEG_SIZE(3),
.b_descriptor_type = USB_DT_CS_INTERFACE,
.b_descriptor_subtype = UVC_VS_FRAME_MJPEG,
.b_frame_index = 1,
.bm_capabilities = 0,
.w_width = UVCG_WIDTH_360P,
.w_height = UVCG_HEIGHT_360P,
.dw_min_bit_rate = UVCG_MIN_BITRATE_360P,
.dw_max_bit_rate = UVCG_MAX_BITRATE_360P,
.dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P,
.dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P,
.b_frame_interval_type = 3,
},
.dw_frame_interval = uvcg_frame_mjpeg_360p_dw_frame_interval,
};
static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_360p = {
.frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_360p,
}; };
static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
...@@ -253,23 +388,44 @@ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { ...@@ -253,23 +388,44 @@ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
.bDescriptorSubType = UVC_VS_FRAME_MJPEG, .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
.bFrameIndex = 2, .bFrameIndex = 2,
.bmCapabilities = 0, .bmCapabilities = 0,
.wWidth = cpu_to_le16(1280), .wWidth = cpu_to_le16(UVCG_WIDTH_720P),
.wHeight = cpu_to_le16(720), .wHeight = cpu_to_le16(UVCG_HEIGHT_720P),
.dwMinBitRate = cpu_to_le32(29491200), .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P),
.dwMaxBitRate = cpu_to_le32(29491200), .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P),
.dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P),
.dwDefaultFrameInterval = cpu_to_le32(5000000), .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P),
.bFrameIntervalType = 1, .bFrameIntervalType = 1,
.dwFrameInterval[0] = cpu_to_le32(5000000), .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P),
}; };
static const struct uvc_color_matching_descriptor uvc_color_matching = { static u32 uvcg_frame_mjpeg_720p_dw_frame_interval[] = {
.bLength = UVC_DT_COLOR_MATCHING_SIZE, [0] = UVCG_FRM_INTERV_0_720P,
.bDescriptorType = USB_DT_CS_INTERFACE, };
.bDescriptorSubType = UVC_VS_COLORFORMAT,
.bColorPrimaries = 1, static const struct uvcg_frame uvcg_frame_mjpeg_720p = {
.bTransferCharacteristics = 1, .fmt_type = UVCG_MJPEG,
.bMatrixCoefficients = 4, .frame = {
.b_length = UVC_DT_FRAME_MJPEG_SIZE(1),
.b_descriptor_type = USB_DT_CS_INTERFACE,
.b_descriptor_subtype = UVC_VS_FRAME_MJPEG,
.b_frame_index = 2,
.bm_capabilities = 0,
.w_width = UVCG_WIDTH_720P,
.w_height = UVCG_HEIGHT_720P,
.dw_min_bit_rate = UVCG_MIN_BITRATE_720P,
.dw_max_bit_rate = UVCG_MAX_BITRATE_720P,
.dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P,
.dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P,
.b_frame_interval_type = 1,
},
.dw_frame_interval = uvcg_frame_mjpeg_720p_dw_frame_interval,
};
static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_720p = {
.frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_720p,
};
static struct uvcg_streaming_header uvcg_streaming_header = {
}; };
static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = { static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
...@@ -290,40 +446,40 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = { ...@@ -290,40 +446,40 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header, (const struct uvc_descriptor_header *) &uvc_input_header,
(const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
(const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
NULL, NULL,
}; };
static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header, (const struct uvc_descriptor_header *) &uvc_input_header,
(const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
(const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
NULL, NULL,
}; };
static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header, (const struct uvc_descriptor_header *) &uvc_input_header,
(const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
(const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
NULL, NULL,
}; };
...@@ -387,6 +543,23 @@ webcam_bind(struct usb_composite_dev *cdev) ...@@ -387,6 +543,23 @@ webcam_bind(struct usb_composite_dev *cdev)
uvc_opts->hs_streaming = uvc_hs_streaming_cls; uvc_opts->hs_streaming = uvc_hs_streaming_cls;
uvc_opts->ss_streaming = uvc_ss_streaming_cls; uvc_opts->ss_streaming = uvc_ss_streaming_cls;
INIT_LIST_HEAD(&uvcg_format_yuv.fmt.frames);
list_add_tail(&uvcg_frame_ptr_yuv_360p.entry, &uvcg_format_yuv.fmt.frames);
list_add_tail(&uvcg_frame_ptr_yuv_720p.entry, &uvcg_format_yuv.fmt.frames);
uvcg_format_yuv.fmt.num_frames = 2;
INIT_LIST_HEAD(&uvcg_format_mjpeg.fmt.frames);
list_add_tail(&uvcg_frame_ptr_mjpeg_360p.entry, &uvcg_format_mjpeg.fmt.frames);
list_add_tail(&uvcg_frame_ptr_mjpeg_720p.entry, &uvcg_format_mjpeg.fmt.frames);
uvcg_format_mjpeg.fmt.num_frames = 2;
INIT_LIST_HEAD(&uvcg_streaming_header.formats);
list_add_tail(&uvcg_format_ptr_yuv.entry, &uvcg_streaming_header.formats);
list_add_tail(&uvcg_format_ptr_mjpeg.entry, &uvcg_streaming_header.formats);
uvcg_streaming_header.num_fmt = 2;
uvc_opts->header = &uvcg_streaming_header;
/* Allocate string descriptor numbers ... note that string contents /* Allocate string descriptor numbers ... note that string contents
* can be overridden by the composite_dev glue. * can be overridden by the composite_dev glue.
*/ */
......
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