diff mbox series

[v2] usb: gadget: webcam: Make g_webcam loadable again

Message ID 20231208131342.65671-1-andrzej.p@collabora.com (mailing list archive)
State Superseded
Headers show
Series [v2] usb: gadget: webcam: Make g_webcam loadable again | expand

Commit Message

Andrzej Pietrasiewicz Dec. 8, 2023, 1:13 p.m. UTC
commit 588b9e85609b ("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: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
Fixes: 588b9e85609b ("usb: gadget: uvc: add v4l2 enumeration api calls")
---
v1..v2:
- fixed a typo (missing character) in one of uvcg_frame_mjpeg_720p's members

 drivers/usb/gadget/function/f_uvc.c |  45 +++---
 drivers/usb/gadget/function/u_uvc.h |   6 +
 drivers/usb/gadget/legacy/webcam.c  | 232 ++++++++++++++++++++++------
 3 files changed, 215 insertions(+), 68 deletions(-)


base-commit: 33cc938e65a98f1d29d0a18403dbbee050dcad9a

Comments

kernel test robot Dec. 8, 2023, 11:56 p.m. UTC | #1
Hi Andrzej,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 33cc938e65a98f1d29d0a18403dbbee050dcad9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Andrzej-Pietrasiewicz/usb-gadget-webcam-Make-g_webcam-loadable-again/20231208-211513
base:   33cc938e65a98f1d29d0a18403dbbee050dcad9a
patch link:    https://lore.kernel.org/r/20231208131342.65671-1-andrzej.p%40collabora.com
patch subject: [PATCH v2] usb: gadget: webcam: Make g_webcam loadable again
config: i386-buildonly-randconfig-002-20231209 (https://download.01.org/0day-ci/archive/20231209/202312090717.dUYTE5cM-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231209/202312090717.dUYTE5cM-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312090717.dUYTE5cM-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/usb/gadget/legacy/webcam.c:368:32: warning: 'uvcg_frame_mjpeg_720p' defined but not used [-Wunused-const-variable=]
     368 | static const struct uvcg_frame uvcg_frame_mjpeg_720p = {
         |                                ^~~~~~~~~~~~~~~~~~~~~


vim +/uvcg_frame_mjpeg_720p +368 drivers/usb/gadget/legacy/webcam.c

   367	
 > 368	static const struct uvcg_frame uvcg_frame_mjpeg_720p = {
   369		.fmt_type		= UVCG_MJPEG,
   370		.frame = {
   371			.b_length			= uvc_frame_mjpg_720p.bLength,
   372			.b_descriptor_type		= uvc_frame_mjpg_720p.bDescriptorType,
   373			.b_descriptor_subtype		= uvc_frame_mjpg_720p.bDescriptorSubType,
   374			.b_frame_index			= uvc_frame_mjpg_720p.bFrameIndex,
   375			.bm_capabilities		= uvc_frame_mjpg_720p.bmCapabilities,
   376			.w_width			= uvc_frame_mjpg_720p.wWidth,
   377			.w_height			= uvc_frame_mjpg_720p.wHeight,
   378			.dw_min_bit_rate		= uvc_frame_mjpg_720p.dwMinBitRate,
   379			.dw_max_bit_rate		= uvc_frame_mjpg_720p.dwMaxBitRate,
   380			.dw_max_video_frame_buffer_size	= uvc_frame_mjpg_720p.dwMaxVideoFrameBufferSize,
   381			.dw_default_frame_interval	= uvc_frame_mjpg_720p.dwDefaultFrameInterval,
   382			.b_frame_interval_type		= uvc_frame_mjpg_720p.bFrameIntervalType,
   383		},
   384		.dw_frame_interval	= (u32 *)uvc_frame_mjpg_720p.dwFrameInterval,
   385	};
   386
kernel test robot Dec. 9, 2023, 10:20 a.m. UTC | #2
Hi Andrzej,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 33cc938e65a98f1d29d0a18403dbbee050dcad9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Andrzej-Pietrasiewicz/usb-gadget-webcam-Make-g_webcam-loadable-again/20231208-211513
base:   33cc938e65a98f1d29d0a18403dbbee050dcad9a
patch link:    https://lore.kernel.org/r/20231208131342.65671-1-andrzej.p%40collabora.com
patch subject: [PATCH v2] usb: gadget: webcam: Make g_webcam loadable again
config: m68k-randconfig-r132-20231209 (https://download.01.org/0day-ci/archive/20231209/202312091817.u3BjKBcF-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20231209/202312091817.u3BjKBcF-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312091817.u3BjKBcF-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/usb/gadget/legacy/webcam.c:229:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_width @@     got restricted __le16 static const [toplevel] [usertype] wWidth @@
   drivers/usb/gadget/legacy/webcam.c:229:69: sparse:     expected unsigned short [usertype] w_width
   drivers/usb/gadget/legacy/webcam.c:229:69: sparse:     got restricted __le16 static const [toplevel] [usertype] wWidth
>> drivers/usb/gadget/legacy/webcam.c:230:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_height @@     got restricted __le16 static const [toplevel] [usertype] wHeight @@
   drivers/usb/gadget/legacy/webcam.c:230:69: sparse:     expected unsigned short [usertype] w_height
   drivers/usb/gadget/legacy/webcam.c:230:69: sparse:     got restricted __le16 static const [toplevel] [usertype] wHeight
>> drivers/usb/gadget/legacy/webcam.c:231:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_min_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate @@
   drivers/usb/gadget/legacy/webcam.c:231:69: sparse:     expected unsigned int [usertype] dw_min_bit_rate
   drivers/usb/gadget/legacy/webcam.c:231:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate
>> drivers/usb/gadget/legacy/webcam.c:232:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate @@
   drivers/usb/gadget/legacy/webcam.c:232:69: sparse:     expected unsigned int [usertype] dw_max_bit_rate
   drivers/usb/gadget/legacy/webcam.c:232:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate
>> drivers/usb/gadget/legacy/webcam.c:233:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_video_frame_buffer_size @@     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize @@
   drivers/usb/gadget/legacy/webcam.c:233:69: sparse:     expected unsigned int [usertype] dw_max_video_frame_buffer_size
   drivers/usb/gadget/legacy/webcam.c:233:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize
>> drivers/usb/gadget/legacy/webcam.c:234:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_default_frame_interval @@     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval @@
   drivers/usb/gadget/legacy/webcam.c:234:69: sparse:     expected unsigned int [usertype] dw_default_frame_interval
   drivers/usb/gadget/legacy/webcam.c:234:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval
   drivers/usb/gadget/legacy/webcam.c:268:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_width @@     got restricted __le16 static const [toplevel] [usertype] wWidth @@
   drivers/usb/gadget/legacy/webcam.c:268:69: sparse:     expected unsigned short [usertype] w_width
   drivers/usb/gadget/legacy/webcam.c:268:69: sparse:     got restricted __le16 static const [toplevel] [usertype] wWidth
   drivers/usb/gadget/legacy/webcam.c:269:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_height @@     got restricted __le16 static const [toplevel] [usertype] wHeight @@
   drivers/usb/gadget/legacy/webcam.c:269:69: sparse:     expected unsigned short [usertype] w_height
   drivers/usb/gadget/legacy/webcam.c:269:69: sparse:     got restricted __le16 static const [toplevel] [usertype] wHeight
   drivers/usb/gadget/legacy/webcam.c:270:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_min_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate @@
   drivers/usb/gadget/legacy/webcam.c:270:69: sparse:     expected unsigned int [usertype] dw_min_bit_rate
   drivers/usb/gadget/legacy/webcam.c:270:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate
   drivers/usb/gadget/legacy/webcam.c:271:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate @@
   drivers/usb/gadget/legacy/webcam.c:271:69: sparse:     expected unsigned int [usertype] dw_max_bit_rate
   drivers/usb/gadget/legacy/webcam.c:271:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate
   drivers/usb/gadget/legacy/webcam.c:272:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_video_frame_buffer_size @@     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize @@
   drivers/usb/gadget/legacy/webcam.c:272:69: sparse:     expected unsigned int [usertype] dw_max_video_frame_buffer_size
   drivers/usb/gadget/legacy/webcam.c:272:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize
   drivers/usb/gadget/legacy/webcam.c:273:69: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_default_frame_interval @@     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval @@
   drivers/usb/gadget/legacy/webcam.c:273:69: sparse:     expected unsigned int [usertype] dw_default_frame_interval
   drivers/usb/gadget/legacy/webcam.c:273:69: sparse:     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval
   drivers/usb/gadget/legacy/webcam.c:337:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_width @@     got restricted __le16 static const [toplevel] [usertype] wWidth @@
   drivers/usb/gadget/legacy/webcam.c:337:70: sparse:     expected unsigned short [usertype] w_width
   drivers/usb/gadget/legacy/webcam.c:337:70: sparse:     got restricted __le16 static const [toplevel] [usertype] wWidth
   drivers/usb/gadget/legacy/webcam.c:338:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_height @@     got restricted __le16 static const [toplevel] [usertype] wHeight @@
   drivers/usb/gadget/legacy/webcam.c:338:70: sparse:     expected unsigned short [usertype] w_height
   drivers/usb/gadget/legacy/webcam.c:338:70: sparse:     got restricted __le16 static const [toplevel] [usertype] wHeight
   drivers/usb/gadget/legacy/webcam.c:339:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_min_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate @@
   drivers/usb/gadget/legacy/webcam.c:339:70: sparse:     expected unsigned int [usertype] dw_min_bit_rate
   drivers/usb/gadget/legacy/webcam.c:339:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate
   drivers/usb/gadget/legacy/webcam.c:340:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate @@
   drivers/usb/gadget/legacy/webcam.c:340:70: sparse:     expected unsigned int [usertype] dw_max_bit_rate
   drivers/usb/gadget/legacy/webcam.c:340:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate
   drivers/usb/gadget/legacy/webcam.c:341:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_video_frame_buffer_size @@     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize @@
   drivers/usb/gadget/legacy/webcam.c:341:70: sparse:     expected unsigned int [usertype] dw_max_video_frame_buffer_size
   drivers/usb/gadget/legacy/webcam.c:341:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize
   drivers/usb/gadget/legacy/webcam.c:342:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_default_frame_interval @@     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval @@
   drivers/usb/gadget/legacy/webcam.c:342:70: sparse:     expected unsigned int [usertype] dw_default_frame_interval
   drivers/usb/gadget/legacy/webcam.c:342:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval
   drivers/usb/gadget/legacy/webcam.c:376:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_width @@     got restricted __le16 static const [toplevel] [usertype] wWidth @@
   drivers/usb/gadget/legacy/webcam.c:376:70: sparse:     expected unsigned short [usertype] w_width
   drivers/usb/gadget/legacy/webcam.c:376:70: sparse:     got restricted __le16 static const [toplevel] [usertype] wWidth
   drivers/usb/gadget/legacy/webcam.c:377:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned short [usertype] w_height @@     got restricted __le16 static const [toplevel] [usertype] wHeight @@
   drivers/usb/gadget/legacy/webcam.c:377:70: sparse:     expected unsigned short [usertype] w_height
   drivers/usb/gadget/legacy/webcam.c:377:70: sparse:     got restricted __le16 static const [toplevel] [usertype] wHeight
   drivers/usb/gadget/legacy/webcam.c:378:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_min_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate @@
   drivers/usb/gadget/legacy/webcam.c:378:70: sparse:     expected unsigned int [usertype] dw_min_bit_rate
   drivers/usb/gadget/legacy/webcam.c:378:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMinBitRate
   drivers/usb/gadget/legacy/webcam.c:379:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_bit_rate @@     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate @@
   drivers/usb/gadget/legacy/webcam.c:379:70: sparse:     expected unsigned int [usertype] dw_max_bit_rate
   drivers/usb/gadget/legacy/webcam.c:379:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxBitRate
   drivers/usb/gadget/legacy/webcam.c:380:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_max_video_frame_buffer_size @@     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize @@
   drivers/usb/gadget/legacy/webcam.c:380:70: sparse:     expected unsigned int [usertype] dw_max_video_frame_buffer_size
   drivers/usb/gadget/legacy/webcam.c:380:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwMaxVideoFrameBufferSize
   drivers/usb/gadget/legacy/webcam.c:381:70: sparse: sparse: incorrect type in initializer (different base types) @@     expected unsigned int [usertype] dw_default_frame_interval @@     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval @@
   drivers/usb/gadget/legacy/webcam.c:381:70: sparse:     expected unsigned int [usertype] dw_default_frame_interval
   drivers/usb/gadget/legacy/webcam.c:381:70: sparse:     got restricted __le32 static const [toplevel] [usertype] dwDefaultFrameInterval
   drivers/usb/gadget/legacy/webcam.c: note: in included file (through include/linux/rculist.h, include/linux/pid.h, include/linux/sched.h, ...):
   include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true
   include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true
   include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true
   include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true
   include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true
   include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true

vim +229 drivers/usb/gadget/legacy/webcam.c

   220	
   221	static const struct uvcg_frame uvcg_frame_yuv_360p = {
   222		.fmt_type		= UVCG_UNCOMPRESSED,
   223		.frame = {
   224			.b_length			= uvc_frame_yuv_360p.bLength,
   225			.b_descriptor_type		= uvc_frame_yuv_360p.bDescriptorType,
   226			.b_descriptor_subtype		= uvc_frame_yuv_360p.bDescriptorSubType,
   227			.b_frame_index			= uvc_frame_yuv_360p.bFrameIndex,
   228			.bm_capabilities		= uvc_frame_yuv_360p.bmCapabilities,
 > 229			.w_width			= uvc_frame_yuv_360p.wWidth,
 > 230			.w_height			= uvc_frame_yuv_360p.wHeight,
 > 231			.dw_min_bit_rate		= uvc_frame_yuv_360p.dwMinBitRate,
 > 232			.dw_max_bit_rate		= uvc_frame_yuv_360p.dwMaxBitRate,
 > 233			.dw_max_video_frame_buffer_size	= uvc_frame_yuv_360p.dwMaxVideoFrameBufferSize,
 > 234			.dw_default_frame_interval	= uvc_frame_yuv_360p.dwDefaultFrameInterval,
   235			.b_frame_interval_type		= uvc_frame_yuv_360p.bFrameIntervalType,
   236		},
   237		.dw_frame_interval	= (u32 *)uvc_frame_yuv_360p.dwFrameInterval,
   238	};
   239
kernel test robot Dec. 9, 2023, 10:41 a.m. UTC | #3
Hi Andrzej,

kernel test robot noticed the following build errors:

[auto build test ERROR on 33cc938e65a98f1d29d0a18403dbbee050dcad9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Andrzej-Pietrasiewicz/usb-gadget-webcam-Make-g_webcam-loadable-again/20231208-211513
base:   33cc938e65a98f1d29d0a18403dbbee050dcad9a
patch link:    https://lore.kernel.org/r/20231208131342.65671-1-andrzej.p%40collabora.com
patch subject: [PATCH v2] usb: gadget: webcam: Make g_webcam loadable again
config: x86_64-randconfig-r111-20231209 (https://download.01.org/0day-ci/archive/20231209/202312091825.1MSZeBRA-lkp@intel.com/config)
compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231209/202312091825.1MSZeBRA-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312091825.1MSZeBRA-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/usb/gadget/legacy/webcam.c:224:17: error: initializer element is not constant
      .b_length   = uvc_frame_yuv_360p.bLength,
                    ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:224:17: note: (near initialization for 'uvcg_frame_yuv_360p.frame.b_length')
   drivers/usb/gadget/legacy/webcam.c:225:25: error: initializer element is not constant
      .b_descriptor_type  = uvc_frame_yuv_360p.bDescriptorType,
                            ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:225:25: note: (near initialization for 'uvcg_frame_yuv_360p.frame.b_descriptor_type')
   drivers/usb/gadget/legacy/webcam.c:226:28: error: initializer element is not constant
      .b_descriptor_subtype  = uvc_frame_yuv_360p.bDescriptorSubType,
                               ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:226:28: note: (near initialization for 'uvcg_frame_yuv_360p.frame.b_descriptor_subtype')
   drivers/usb/gadget/legacy/webcam.c:227:22: error: initializer element is not constant
      .b_frame_index   = uvc_frame_yuv_360p.bFrameIndex,
                         ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:227:22: note: (near initialization for 'uvcg_frame_yuv_360p.frame.b_frame_index')
   drivers/usb/gadget/legacy/webcam.c:228:23: error: initializer element is not constant
      .bm_capabilities  = uvc_frame_yuv_360p.bmCapabilities,
                          ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:228:23: note: (near initialization for 'uvcg_frame_yuv_360p.frame.bm_capabilities')
   drivers/usb/gadget/legacy/webcam.c:229:16: error: initializer element is not constant
      .w_width   = uvc_frame_yuv_360p.wWidth,
                   ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:229:16: note: (near initialization for 'uvcg_frame_yuv_360p.frame.w_width')
   drivers/usb/gadget/legacy/webcam.c:230:17: error: initializer element is not constant
      .w_height   = uvc_frame_yuv_360p.wHeight,
                    ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:230:17: note: (near initialization for 'uvcg_frame_yuv_360p.frame.w_height')
   drivers/usb/gadget/legacy/webcam.c:231:23: error: initializer element is not constant
      .dw_min_bit_rate  = uvc_frame_yuv_360p.dwMinBitRate,
                          ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:231:23: note: (near initialization for 'uvcg_frame_yuv_360p.frame.dw_min_bit_rate')
   drivers/usb/gadget/legacy/webcam.c:232:23: error: initializer element is not constant
      .dw_max_bit_rate  = uvc_frame_yuv_360p.dwMaxBitRate,
                          ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:232:23: note: (near initialization for 'uvcg_frame_yuv_360p.frame.dw_max_bit_rate')
   drivers/usb/gadget/legacy/webcam.c:233:37: error: initializer element is not constant
      .dw_max_video_frame_buffer_size = uvc_frame_yuv_360p.dwMaxVideoFrameBufferSize,
                                        ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:233:37: note: (near initialization for 'uvcg_frame_yuv_360p.frame.dw_max_video_frame_buffer_size')
   drivers/usb/gadget/legacy/webcam.c:234:32: error: initializer element is not constant
      .dw_default_frame_interval = uvc_frame_yuv_360p.dwDefaultFrameInterval,
                                   ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:234:32: note: (near initialization for 'uvcg_frame_yuv_360p.frame.dw_default_frame_interval')
   drivers/usb/gadget/legacy/webcam.c:235:29: error: initializer element is not constant
      .b_frame_interval_type  = uvc_frame_yuv_360p.bFrameIntervalType,
                                ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:235:29: note: (near initialization for 'uvcg_frame_yuv_360p.frame.b_frame_interval_type')
   drivers/usb/gadget/legacy/webcam.c:263:17: error: initializer element is not constant
      .b_length   = uvc_frame_yuv_720p.bLength,
                    ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:263:17: note: (near initialization for 'uvcg_frame_yuv_720p.frame.b_length')
   drivers/usb/gadget/legacy/webcam.c:264:25: error: initializer element is not constant
      .b_descriptor_type  = uvc_frame_yuv_720p.bDescriptorType,
                            ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:264:25: note: (near initialization for 'uvcg_frame_yuv_720p.frame.b_descriptor_type')
   drivers/usb/gadget/legacy/webcam.c:265:28: error: initializer element is not constant
      .b_descriptor_subtype  = uvc_frame_yuv_720p.bDescriptorSubType,
                               ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:265:28: note: (near initialization for 'uvcg_frame_yuv_720p.frame.b_descriptor_subtype')
   drivers/usb/gadget/legacy/webcam.c:266:22: error: initializer element is not constant
      .b_frame_index   = uvc_frame_yuv_720p.bFrameIndex,
                         ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:266:22: note: (near initialization for 'uvcg_frame_yuv_720p.frame.b_frame_index')
   drivers/usb/gadget/legacy/webcam.c:267:23: error: initializer element is not constant
      .bm_capabilities  = uvc_frame_yuv_720p.bmCapabilities,
                          ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:267:23: note: (near initialization for 'uvcg_frame_yuv_720p.frame.bm_capabilities')
   drivers/usb/gadget/legacy/webcam.c:268:16: error: initializer element is not constant
      .w_width   = uvc_frame_yuv_720p.wWidth,
                   ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:268:16: note: (near initialization for 'uvcg_frame_yuv_720p.frame.w_width')
   drivers/usb/gadget/legacy/webcam.c:269:17: error: initializer element is not constant
      .w_height   = uvc_frame_yuv_720p.wHeight,
                    ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:269:17: note: (near initialization for 'uvcg_frame_yuv_720p.frame.w_height')
   drivers/usb/gadget/legacy/webcam.c:270:23: error: initializer element is not constant
      .dw_min_bit_rate  = uvc_frame_yuv_720p.dwMinBitRate,
                          ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:270:23: note: (near initialization for 'uvcg_frame_yuv_720p.frame.dw_min_bit_rate')
   drivers/usb/gadget/legacy/webcam.c:271:23: error: initializer element is not constant
      .dw_max_bit_rate  = uvc_frame_yuv_720p.dwMaxBitRate,
                          ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:271:23: note: (near initialization for 'uvcg_frame_yuv_720p.frame.dw_max_bit_rate')
   drivers/usb/gadget/legacy/webcam.c:272:37: error: initializer element is not constant
      .dw_max_video_frame_buffer_size = uvc_frame_yuv_720p.dwMaxVideoFrameBufferSize,
                                        ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:272:37: note: (near initialization for 'uvcg_frame_yuv_720p.frame.dw_max_video_frame_buffer_size')
   drivers/usb/gadget/legacy/webcam.c:273:32: error: initializer element is not constant
      .dw_default_frame_interval = uvc_frame_yuv_720p.dwDefaultFrameInterval,
                                   ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:273:32: note: (near initialization for 'uvcg_frame_yuv_720p.frame.dw_default_frame_interval')
   drivers/usb/gadget/legacy/webcam.c:274:29: error: initializer element is not constant
      .b_frame_interval_type  = uvc_frame_yuv_720p.bFrameIntervalType,
                                ^~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:274:29: note: (near initialization for 'uvcg_frame_yuv_720p.frame.b_frame_interval_type')
   drivers/usb/gadget/legacy/webcam.c:332:17: error: initializer element is not constant
      .b_length   = uvc_frame_mjpg_360p.bLength,
                    ^~~~~~~~~~~~~~~~~~~
   drivers/usb/gadget/legacy/webcam.c:332:17: note: (near initialization for 'uvcg_frame_mjpeg_360p.frame.b_length')
   drivers/usb/gadget/legacy/webcam.c:333:25: error: initializer element is not constant


vim +224 drivers/usb/gadget/legacy/webcam.c

   220	
   221	static const struct uvcg_frame uvcg_frame_yuv_360p = {
   222		.fmt_type		= UVCG_UNCOMPRESSED,
   223		.frame = {
 > 224			.b_length			= uvc_frame_yuv_360p.bLength,
   225			.b_descriptor_type		= uvc_frame_yuv_360p.bDescriptorType,
   226			.b_descriptor_subtype		= uvc_frame_yuv_360p.bDescriptorSubType,
   227			.b_frame_index			= uvc_frame_yuv_360p.bFrameIndex,
   228			.bm_capabilities		= uvc_frame_yuv_360p.bmCapabilities,
   229			.w_width			= uvc_frame_yuv_360p.wWidth,
   230			.w_height			= uvc_frame_yuv_360p.wHeight,
   231			.dw_min_bit_rate		= uvc_frame_yuv_360p.dwMinBitRate,
   232			.dw_max_bit_rate		= uvc_frame_yuv_360p.dwMaxBitRate,
   233			.dw_max_video_frame_buffer_size	= uvc_frame_yuv_360p.dwMaxVideoFrameBufferSize,
   234			.dw_default_frame_interval	= uvc_frame_yuv_360p.dwDefaultFrameInterval,
   235			.b_frame_interval_type		= uvc_frame_yuv_360p.bFrameIntervalType,
   236		},
   237		.dw_frame_interval	= (u32 *)uvc_frame_yuv_360p.dwFrameInterval,
   238	};
   239
kernel test robot Dec. 9, 2023, 10:17 p.m. UTC | #4
Hi Andrzej,

kernel test robot noticed the following build errors:

[auto build test ERROR on 33cc938e65a98f1d29d0a18403dbbee050dcad9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Andrzej-Pietrasiewicz/usb-gadget-webcam-Make-g_webcam-loadable-again/20231208-211513
base:   33cc938e65a98f1d29d0a18403dbbee050dcad9a
patch link:    https://lore.kernel.org/r/20231208131342.65671-1-andrzej.p%40collabora.com
patch subject: [PATCH v2] usb: gadget: webcam: Make g_webcam loadable again
config: arm64-allyesconfig (https://download.01.org/0day-ci/archive/20231210/202312100602.sdYTHOg1-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231210/202312100602.sdYTHOg1-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312100602.sdYTHOg1-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/usb/gadget/legacy/webcam.c:224:36: error: initializer element is not a compile-time constant
     224 |                 .b_length                       = uvc_frame_yuv_360p.bLength,
         |                                                   ~~~~~~~~~~~~~~~~~~~^~~~~~~
   drivers/usb/gadget/legacy/webcam.c:263:36: error: initializer element is not a compile-time constant
     263 |                 .b_length                       = uvc_frame_yuv_720p.bLength,
         |                                                   ~~~~~~~~~~~~~~~~~~~^~~~~~~
   drivers/usb/gadget/legacy/webcam.c:332:37: error: initializer element is not a compile-time constant
     332 |                 .b_length                       = uvc_frame_mjpg_360p.bLength,
         |                                                   ~~~~~~~~~~~~~~~~~~~~^~~~~~~
   drivers/usb/gadget/legacy/webcam.c:371:37: error: initializer element is not a compile-time constant
     371 |                 .b_length                       = uvc_frame_mjpg_720p.bLength,
         |                                                   ~~~~~~~~~~~~~~~~~~~~^~~~~~~
   4 errors generated.


vim +224 drivers/usb/gadget/legacy/webcam.c

   220	
   221	static const struct uvcg_frame uvcg_frame_yuv_360p = {
   222		.fmt_type		= UVCG_UNCOMPRESSED,
   223		.frame = {
 > 224			.b_length			= uvc_frame_yuv_360p.bLength,
   225			.b_descriptor_type		= uvc_frame_yuv_360p.bDescriptorType,
   226			.b_descriptor_subtype		= uvc_frame_yuv_360p.bDescriptorSubType,
   227			.b_frame_index			= uvc_frame_yuv_360p.bFrameIndex,
   228			.bm_capabilities		= uvc_frame_yuv_360p.bmCapabilities,
   229			.w_width			= uvc_frame_yuv_360p.wWidth,
   230			.w_height			= uvc_frame_yuv_360p.wHeight,
   231			.dw_min_bit_rate		= uvc_frame_yuv_360p.dwMinBitRate,
   232			.dw_max_bit_rate		= uvc_frame_yuv_360p.dwMaxBitRate,
   233			.dw_max_video_frame_buffer_size	= uvc_frame_yuv_360p.dwMaxVideoFrameBufferSize,
   234			.dw_default_frame_interval	= uvc_frame_yuv_360p.dwDefaultFrameInterval,
   235			.b_frame_interval_type		= uvc_frame_yuv_360p.bFrameIntervalType,
   236		},
   237		.dw_frame_interval	= (u32 *)uvc_frame_yuv_360p.dwFrameInterval,
   238	};
   239
diff mbox series

Patch

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 786379f1b7b7..3b46de85ca01 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -960,7 +960,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);
 }
@@ -1052,25 +1053,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;
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 1ce58f61253c..3ac392cbb779 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -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 */
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index c06dd1af7a0c..4658de9369e2 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -12,6 +12,7 @@ 
 #include <linux/usb/video.h>
 
 #include "u_uvc.h"
+#include "uvc_configfs.h"
 
 USB_GADGET_COMPOSITE_OPTIONS();
 
@@ -84,8 +85,6 @@  static struct usb_device_descriptor webcam_device_descriptor = {
 	.bNumConfigurations	= 0, /* dynamic */
 };
 
-DECLARE_UVC_HEADER_DESCRIPTOR(1);
-
 static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
 	.bLength		= UVC_DT_HEADER_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
@@ -158,21 +157,44 @@  static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
 	.bmaControls[1][0]	= 4,
 };
 
-static const struct uvc_format_uncompressed uvc_format_yuv = {
-	.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 const struct uvcg_color_matching uvcg_color_matching = {
+	.desc = {
+		.bLength		= UVC_DT_COLOR_MATCHING_SIZE,
+		.bDescriptorType	= USB_DT_CS_INTERFACE,
+		.bDescriptorSubType	= UVC_VS_COLORFORMAT,
+		.bColorPrimaries	= 1,
+		.bTransferCharacteristics	= 1,
+		.bMatrixCoefficients	= 4,
+	},
+};
+
+static struct uvcg_uncompressed uvcg_format_yuv = {
+	.fmt = {
+		.type			= UVCG_UNCOMPRESSED,
+		/* 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);
@@ -196,6 +218,29 @@  static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
 	.dwFrameInterval[2]	= cpu_to_le32(5000000),
 };
 
+static const struct uvcg_frame uvcg_frame_yuv_360p = {
+	.fmt_type		= UVCG_UNCOMPRESSED,
+	.frame = {
+		.b_length			= uvc_frame_yuv_360p.bLength,
+		.b_descriptor_type		= uvc_frame_yuv_360p.bDescriptorType,
+		.b_descriptor_subtype		= uvc_frame_yuv_360p.bDescriptorSubType,
+		.b_frame_index			= uvc_frame_yuv_360p.bFrameIndex,
+		.bm_capabilities		= uvc_frame_yuv_360p.bmCapabilities,
+		.w_width			= uvc_frame_yuv_360p.wWidth,
+		.w_height			= uvc_frame_yuv_360p.wHeight,
+		.dw_min_bit_rate		= uvc_frame_yuv_360p.dwMinBitRate,
+		.dw_max_bit_rate		= uvc_frame_yuv_360p.dwMaxBitRate,
+		.dw_max_video_frame_buffer_size	= uvc_frame_yuv_360p.dwMaxVideoFrameBufferSize,
+		.dw_default_frame_interval	= uvc_frame_yuv_360p.dwDefaultFrameInterval,
+		.b_frame_interval_type		= uvc_frame_yuv_360p.bFrameIntervalType,
+	},
+	.dw_frame_interval	= (u32 *)uvc_frame_yuv_360p.dwFrameInterval,
+};
+
+static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_360p = {
+	.frm = (struct uvcg_frame *)&uvcg_frame_yuv_360p,
+};
+
 static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
 	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
@@ -212,18 +257,52 @@  static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
 	.dwFrameInterval[0]	= cpu_to_le32(5000000),
 };
 
-static const struct uvc_format_mjpeg uvc_format_mjpg = {
-	.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 const struct uvcg_frame uvcg_frame_yuv_720p = {
+	.fmt_type		= UVCG_UNCOMPRESSED,
+	.frame = {
+		.b_length			= uvc_frame_yuv_720p.bLength,
+		.b_descriptor_type		= uvc_frame_yuv_720p.bDescriptorType,
+		.b_descriptor_subtype		= uvc_frame_yuv_720p.bDescriptorSubType,
+		.b_frame_index			= uvc_frame_yuv_720p.bFrameIndex,
+		.bm_capabilities		= uvc_frame_yuv_720p.bmCapabilities,
+		.w_width			= uvc_frame_yuv_720p.wWidth,
+		.w_height			= uvc_frame_yuv_720p.wHeight,
+		.dw_min_bit_rate		= uvc_frame_yuv_720p.dwMinBitRate,
+		.dw_max_bit_rate		= uvc_frame_yuv_720p.dwMaxBitRate,
+		.dw_max_video_frame_buffer_size	= uvc_frame_yuv_720p.dwMaxVideoFrameBufferSize,
+		.dw_default_frame_interval	= uvc_frame_yuv_720p.dwDefaultFrameInterval,
+		.b_frame_interval_type		= uvc_frame_yuv_720p.bFrameIntervalType,
+	},
+	.dw_frame_interval	= (u32 *)uvc_frame_yuv_720p.dwFrameInterval,
+};
+
+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);
@@ -247,6 +326,29 @@  static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
 	.dwFrameInterval[2]	= cpu_to_le32(5000000),
 };
 
+static const struct uvcg_frame uvcg_frame_mjpeg_360p = {
+	.fmt_type		= UVCG_MJPEG,
+	.frame = {
+		.b_length			= uvc_frame_mjpg_360p.bLength,
+		.b_descriptor_type		= uvc_frame_mjpg_360p.bDescriptorType,
+		.b_descriptor_subtype		= uvc_frame_mjpg_360p.bDescriptorSubType,
+		.b_frame_index			= uvc_frame_mjpg_360p.bFrameIndex,
+		.bm_capabilities		= uvc_frame_mjpg_360p.bmCapabilities,
+		.w_width			= uvc_frame_mjpg_360p.wWidth,
+		.w_height			= uvc_frame_mjpg_360p.wHeight,
+		.dw_min_bit_rate		= uvc_frame_mjpg_360p.dwMinBitRate,
+		.dw_max_bit_rate		= uvc_frame_mjpg_360p.dwMaxBitRate,
+		.dw_max_video_frame_buffer_size	= uvc_frame_mjpg_360p.dwMaxVideoFrameBufferSize,
+		.dw_default_frame_interval	= uvc_frame_mjpg_360p.dwDefaultFrameInterval,
+		.b_frame_interval_type		= uvc_frame_mjpg_360p.bFrameIntervalType,
+	},
+	.dw_frame_interval	= (u32 *)uvc_frame_mjpg_360p.dwFrameInterval,
+};
+
+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 = {
 	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
@@ -263,13 +365,30 @@  static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
 	.dwFrameInterval[0]	= cpu_to_le32(5000000),
 };
 
-static const struct uvc_color_matching_descriptor uvc_color_matching = {
-	.bLength		= UVC_DT_COLOR_MATCHING_SIZE,
-	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_VS_COLORFORMAT,
-	.bColorPrimaries	= 1,
-	.bTransferCharacteristics	= 1,
-	.bMatrixCoefficients	= 4,
+static const struct uvcg_frame uvcg_frame_mjpeg_720p = {
+	.fmt_type		= UVCG_MJPEG,
+	.frame = {
+		.b_length			= uvc_frame_mjpg_720p.bLength,
+		.b_descriptor_type		= uvc_frame_mjpg_720p.bDescriptorType,
+		.b_descriptor_subtype		= uvc_frame_mjpg_720p.bDescriptorSubType,
+		.b_frame_index			= uvc_frame_mjpg_720p.bFrameIndex,
+		.bm_capabilities		= uvc_frame_mjpg_720p.bmCapabilities,
+		.w_width			= uvc_frame_mjpg_720p.wWidth,
+		.w_height			= uvc_frame_mjpg_720p.wHeight,
+		.dw_min_bit_rate		= uvc_frame_mjpg_720p.dwMinBitRate,
+		.dw_max_bit_rate		= uvc_frame_mjpg_720p.dwMaxBitRate,
+		.dw_max_video_frame_buffer_size	= uvc_frame_mjpg_720p.dwMaxVideoFrameBufferSize,
+		.dw_default_frame_interval	= uvc_frame_mjpg_720p.dwDefaultFrameInterval,
+		.b_frame_interval_type		= uvc_frame_mjpg_720p.bFrameIntervalType,
+	},
+	.dw_frame_interval	= (u32 *)uvc_frame_mjpg_720p.dwFrameInterval,
+};
+
+static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_720p = {
+	.frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_360p,
+};
+
+static struct uvcg_streaming_header uvcg_streaming_header = {
 };
 
 static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
@@ -290,40 +409,40 @@  static const struct uvc_descriptor_header * const uvc_ss_control_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_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_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
-	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+	(const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
+	(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_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
+	(const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
 	NULL,
 };
 
 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_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_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
-	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+	(const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
+	(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_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
+	(const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
 	NULL,
 };
 
 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_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_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
-	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+	(const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
+	(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_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
+	(const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
 	NULL,
 };
 
@@ -387,6 +506,23 @@  webcam_bind(struct usb_composite_dev *cdev)
 	uvc_opts->hs_streaming = uvc_hs_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
 	 * can be overridden by the composite_dev glue.
 	 */