18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	webcam.c -- USB webcam gadget driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *	Copyright (C) 2009-2010
68c2ecf20Sopenharmony_ci *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/device.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/usb/video.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "u_uvc.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciUSB_GADGET_COMPOSITE_OPTIONS();
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* module parameters specific to the Video streaming endpoint */
218c2ecf20Sopenharmony_cistatic unsigned int streaming_interval = 1;
228c2ecf20Sopenharmony_cimodule_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(streaming_interval, "1 - 16");
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic unsigned int streaming_maxpacket = 1024;
268c2ecf20Sopenharmony_cimodule_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic unsigned int streaming_maxburst;
308c2ecf20Sopenharmony_cimodule_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------------
348c2ecf20Sopenharmony_ci * Device descriptor
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define WEBCAM_VENDOR_ID		0x1d6b	/* Linux Foundation */
388c2ecf20Sopenharmony_ci#define WEBCAM_PRODUCT_ID		0x0102	/* Webcam A/V gadget */
398c2ecf20Sopenharmony_ci#define WEBCAM_DEVICE_BCD		0x0010	/* 0.10 */
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic char webcam_vendor_label[] = "Linux Foundation";
428c2ecf20Sopenharmony_cistatic char webcam_product_label[] = "Webcam gadget";
438c2ecf20Sopenharmony_cistatic char webcam_config_label[] = "Video";
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* string IDs are assigned dynamically */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic struct usb_string webcam_strings[] = {
508c2ecf20Sopenharmony_ci	[USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
518c2ecf20Sopenharmony_ci	[USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
528c2ecf20Sopenharmony_ci	[USB_GADGET_SERIAL_IDX].s = "",
538c2ecf20Sopenharmony_ci	[STRING_DESCRIPTION_IDX].s = webcam_config_label,
548c2ecf20Sopenharmony_ci	{  }
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic struct usb_gadget_strings webcam_stringtab = {
588c2ecf20Sopenharmony_ci	.language = 0x0409,	/* en-us */
598c2ecf20Sopenharmony_ci	.strings = webcam_strings,
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct usb_gadget_strings *webcam_device_strings[] = {
638c2ecf20Sopenharmony_ci	&webcam_stringtab,
648c2ecf20Sopenharmony_ci	NULL,
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_uvc;
688c2ecf20Sopenharmony_cistatic struct usb_function *f_uvc;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic struct usb_device_descriptor webcam_device_descriptor = {
718c2ecf20Sopenharmony_ci	.bLength		= USB_DT_DEVICE_SIZE,
728c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_DEVICE,
738c2ecf20Sopenharmony_ci	/* .bcdUSB = DYNAMIC */
748c2ecf20Sopenharmony_ci	.bDeviceClass		= USB_CLASS_MISC,
758c2ecf20Sopenharmony_ci	.bDeviceSubClass	= 0x02,
768c2ecf20Sopenharmony_ci	.bDeviceProtocol	= 0x01,
778c2ecf20Sopenharmony_ci	.bMaxPacketSize0	= 0, /* dynamic */
788c2ecf20Sopenharmony_ci	.idVendor		= cpu_to_le16(WEBCAM_VENDOR_ID),
798c2ecf20Sopenharmony_ci	.idProduct		= cpu_to_le16(WEBCAM_PRODUCT_ID),
808c2ecf20Sopenharmony_ci	.bcdDevice		= cpu_to_le16(WEBCAM_DEVICE_BCD),
818c2ecf20Sopenharmony_ci	.iManufacturer		= 0, /* dynamic */
828c2ecf20Sopenharmony_ci	.iProduct		= 0, /* dynamic */
838c2ecf20Sopenharmony_ci	.iSerialNumber		= 0, /* dynamic */
848c2ecf20Sopenharmony_ci	.bNumConfigurations	= 0, /* dynamic */
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ciDECLARE_UVC_HEADER_DESCRIPTOR(1);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
908c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_HEADER_SIZE(1),
918c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
928c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VC_HEADER,
938c2ecf20Sopenharmony_ci	.bcdUVC			= cpu_to_le16(0x0100),
948c2ecf20Sopenharmony_ci	.wTotalLength		= 0, /* dynamic */
958c2ecf20Sopenharmony_ci	.dwClockFrequency	= cpu_to_le32(48000000),
968c2ecf20Sopenharmony_ci	.bInCollection		= 0, /* dynamic */
978c2ecf20Sopenharmony_ci	.baInterfaceNr[0]	= 0, /* dynamic */
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
1018c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_CAMERA_TERMINAL_SIZE(3),
1028c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
1038c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VC_INPUT_TERMINAL,
1048c2ecf20Sopenharmony_ci	.bTerminalID		= 1,
1058c2ecf20Sopenharmony_ci	.wTerminalType		= cpu_to_le16(0x0201),
1068c2ecf20Sopenharmony_ci	.bAssocTerminal		= 0,
1078c2ecf20Sopenharmony_ci	.iTerminal		= 0,
1088c2ecf20Sopenharmony_ci	.wObjectiveFocalLengthMin	= cpu_to_le16(0),
1098c2ecf20Sopenharmony_ci	.wObjectiveFocalLengthMax	= cpu_to_le16(0),
1108c2ecf20Sopenharmony_ci	.wOcularFocalLength		= cpu_to_le16(0),
1118c2ecf20Sopenharmony_ci	.bControlSize		= 3,
1128c2ecf20Sopenharmony_ci	.bmControls[0]		= 2,
1138c2ecf20Sopenharmony_ci	.bmControls[1]		= 0,
1148c2ecf20Sopenharmony_ci	.bmControls[2]		= 0,
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic const struct uvc_processing_unit_descriptor uvc_processing = {
1188c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_PROCESSING_UNIT_SIZE(2),
1198c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
1208c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VC_PROCESSING_UNIT,
1218c2ecf20Sopenharmony_ci	.bUnitID		= 2,
1228c2ecf20Sopenharmony_ci	.bSourceID		= 1,
1238c2ecf20Sopenharmony_ci	.wMaxMultiplier		= cpu_to_le16(16*1024),
1248c2ecf20Sopenharmony_ci	.bControlSize		= 2,
1258c2ecf20Sopenharmony_ci	.bmControls[0]		= 1,
1268c2ecf20Sopenharmony_ci	.bmControls[1]		= 0,
1278c2ecf20Sopenharmony_ci	.iProcessing		= 0,
1288c2ecf20Sopenharmony_ci	.bmVideoStandards	= 0,
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic const struct uvc_output_terminal_descriptor uvc_output_terminal = {
1328c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_OUTPUT_TERMINAL_SIZE,
1338c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
1348c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VC_OUTPUT_TERMINAL,
1358c2ecf20Sopenharmony_ci	.bTerminalID		= 3,
1368c2ecf20Sopenharmony_ci	.wTerminalType		= cpu_to_le16(0x0101),
1378c2ecf20Sopenharmony_ci	.bAssocTerminal		= 0,
1388c2ecf20Sopenharmony_ci	.bSourceID		= 2,
1398c2ecf20Sopenharmony_ci	.iTerminal		= 0,
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciDECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
1458c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_INPUT_HEADER_SIZE(1, 2),
1468c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
1478c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_INPUT_HEADER,
1488c2ecf20Sopenharmony_ci	.bNumFormats		= 2,
1498c2ecf20Sopenharmony_ci	.wTotalLength		= 0, /* dynamic */
1508c2ecf20Sopenharmony_ci	.bEndpointAddress	= 0, /* dynamic */
1518c2ecf20Sopenharmony_ci	.bmInfo			= 0,
1528c2ecf20Sopenharmony_ci	.bTerminalLink		= 3,
1538c2ecf20Sopenharmony_ci	.bStillCaptureMethod	= 0,
1548c2ecf20Sopenharmony_ci	.bTriggerSupport	= 0,
1558c2ecf20Sopenharmony_ci	.bTriggerUsage		= 0,
1568c2ecf20Sopenharmony_ci	.bControlSize		= 1,
1578c2ecf20Sopenharmony_ci	.bmaControls[0][0]	= 0,
1588c2ecf20Sopenharmony_ci	.bmaControls[1][0]	= 4,
1598c2ecf20Sopenharmony_ci};
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic const struct uvc_format_uncompressed uvc_format_yuv = {
1628c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
1638c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
1648c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_FORMAT_UNCOMPRESSED,
1658c2ecf20Sopenharmony_ci	.bFormatIndex		= 1,
1668c2ecf20Sopenharmony_ci	.bNumFrameDescriptors	= 2,
1678c2ecf20Sopenharmony_ci	.guidFormat		=
1688c2ecf20Sopenharmony_ci		{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
1698c2ecf20Sopenharmony_ci		 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
1708c2ecf20Sopenharmony_ci	.bBitsPerPixel		= 16,
1718c2ecf20Sopenharmony_ci	.bDefaultFrameIndex	= 1,
1728c2ecf20Sopenharmony_ci	.bAspectRatioX		= 0,
1738c2ecf20Sopenharmony_ci	.bAspectRatioY		= 0,
1748c2ecf20Sopenharmony_ci	.bmInterfaceFlags	= 0,
1758c2ecf20Sopenharmony_ci	.bCopyProtect		= 0,
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ciDECLARE_UVC_FRAME_UNCOMPRESSED(1);
1798c2ecf20Sopenharmony_ciDECLARE_UVC_FRAME_UNCOMPRESSED(3);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
1828c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
1838c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
1848c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
1858c2ecf20Sopenharmony_ci	.bFrameIndex		= 1,
1868c2ecf20Sopenharmony_ci	.bmCapabilities		= 0,
1878c2ecf20Sopenharmony_ci	.wWidth			= cpu_to_le16(640),
1888c2ecf20Sopenharmony_ci	.wHeight		= cpu_to_le16(360),
1898c2ecf20Sopenharmony_ci	.dwMinBitRate		= cpu_to_le32(18432000),
1908c2ecf20Sopenharmony_ci	.dwMaxBitRate		= cpu_to_le32(55296000),
1918c2ecf20Sopenharmony_ci	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
1928c2ecf20Sopenharmony_ci	.dwDefaultFrameInterval	= cpu_to_le32(666666),
1938c2ecf20Sopenharmony_ci	.bFrameIntervalType	= 3,
1948c2ecf20Sopenharmony_ci	.dwFrameInterval[0]	= cpu_to_le32(666666),
1958c2ecf20Sopenharmony_ci	.dwFrameInterval[1]	= cpu_to_le32(1000000),
1968c2ecf20Sopenharmony_ci	.dwFrameInterval[2]	= cpu_to_le32(5000000),
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
2008c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
2018c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
2028c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
2038c2ecf20Sopenharmony_ci	.bFrameIndex		= 2,
2048c2ecf20Sopenharmony_ci	.bmCapabilities		= 0,
2058c2ecf20Sopenharmony_ci	.wWidth			= cpu_to_le16(1280),
2068c2ecf20Sopenharmony_ci	.wHeight		= cpu_to_le16(720),
2078c2ecf20Sopenharmony_ci	.dwMinBitRate		= cpu_to_le32(29491200),
2088c2ecf20Sopenharmony_ci	.dwMaxBitRate		= cpu_to_le32(29491200),
2098c2ecf20Sopenharmony_ci	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
2108c2ecf20Sopenharmony_ci	.dwDefaultFrameInterval	= cpu_to_le32(5000000),
2118c2ecf20Sopenharmony_ci	.bFrameIntervalType	= 1,
2128c2ecf20Sopenharmony_ci	.dwFrameInterval[0]	= cpu_to_le32(5000000),
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic const struct uvc_format_mjpeg uvc_format_mjpg = {
2168c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_FORMAT_MJPEG_SIZE,
2178c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
2188c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_FORMAT_MJPEG,
2198c2ecf20Sopenharmony_ci	.bFormatIndex		= 2,
2208c2ecf20Sopenharmony_ci	.bNumFrameDescriptors	= 2,
2218c2ecf20Sopenharmony_ci	.bmFlags		= 0,
2228c2ecf20Sopenharmony_ci	.bDefaultFrameIndex	= 1,
2238c2ecf20Sopenharmony_ci	.bAspectRatioX		= 0,
2248c2ecf20Sopenharmony_ci	.bAspectRatioY		= 0,
2258c2ecf20Sopenharmony_ci	.bmInterfaceFlags	= 0,
2268c2ecf20Sopenharmony_ci	.bCopyProtect		= 0,
2278c2ecf20Sopenharmony_ci};
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ciDECLARE_UVC_FRAME_MJPEG(1);
2308c2ecf20Sopenharmony_ciDECLARE_UVC_FRAME_MJPEG(3);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
2338c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(3),
2348c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
2358c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
2368c2ecf20Sopenharmony_ci	.bFrameIndex		= 1,
2378c2ecf20Sopenharmony_ci	.bmCapabilities		= 0,
2388c2ecf20Sopenharmony_ci	.wWidth			= cpu_to_le16(640),
2398c2ecf20Sopenharmony_ci	.wHeight		= cpu_to_le16(360),
2408c2ecf20Sopenharmony_ci	.dwMinBitRate		= cpu_to_le32(18432000),
2418c2ecf20Sopenharmony_ci	.dwMaxBitRate		= cpu_to_le32(55296000),
2428c2ecf20Sopenharmony_ci	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
2438c2ecf20Sopenharmony_ci	.dwDefaultFrameInterval	= cpu_to_le32(666666),
2448c2ecf20Sopenharmony_ci	.bFrameIntervalType	= 3,
2458c2ecf20Sopenharmony_ci	.dwFrameInterval[0]	= cpu_to_le32(666666),
2468c2ecf20Sopenharmony_ci	.dwFrameInterval[1]	= cpu_to_le32(1000000),
2478c2ecf20Sopenharmony_ci	.dwFrameInterval[2]	= cpu_to_le32(5000000),
2488c2ecf20Sopenharmony_ci};
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
2518c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
2528c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
2538c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
2548c2ecf20Sopenharmony_ci	.bFrameIndex		= 2,
2558c2ecf20Sopenharmony_ci	.bmCapabilities		= 0,
2568c2ecf20Sopenharmony_ci	.wWidth			= cpu_to_le16(1280),
2578c2ecf20Sopenharmony_ci	.wHeight		= cpu_to_le16(720),
2588c2ecf20Sopenharmony_ci	.dwMinBitRate		= cpu_to_le32(29491200),
2598c2ecf20Sopenharmony_ci	.dwMaxBitRate		= cpu_to_le32(29491200),
2608c2ecf20Sopenharmony_ci	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
2618c2ecf20Sopenharmony_ci	.dwDefaultFrameInterval	= cpu_to_le32(5000000),
2628c2ecf20Sopenharmony_ci	.bFrameIntervalType	= 1,
2638c2ecf20Sopenharmony_ci	.dwFrameInterval[0]	= cpu_to_le32(5000000),
2648c2ecf20Sopenharmony_ci};
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic const struct uvc_color_matching_descriptor uvc_color_matching = {
2678c2ecf20Sopenharmony_ci	.bLength		= UVC_DT_COLOR_MATCHING_SIZE,
2688c2ecf20Sopenharmony_ci	.bDescriptorType	= USB_DT_CS_INTERFACE,
2698c2ecf20Sopenharmony_ci	.bDescriptorSubType	= UVC_VS_COLORFORMAT,
2708c2ecf20Sopenharmony_ci	.bColorPrimaries	= 1,
2718c2ecf20Sopenharmony_ci	.bTransferCharacteristics	= 1,
2728c2ecf20Sopenharmony_ci	.bMatrixCoefficients	= 4,
2738c2ecf20Sopenharmony_ci};
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
2768c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_control_header,
2778c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
2788c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_processing,
2798c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_output_terminal,
2808c2ecf20Sopenharmony_ci	NULL,
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
2848c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_control_header,
2858c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
2868c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_processing,
2878c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_output_terminal,
2888c2ecf20Sopenharmony_ci	NULL,
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
2928c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_input_header,
2938c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_format_yuv,
2948c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
2958c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
2968c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_color_matching,
2978c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
2988c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
2998c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
3008c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_color_matching,
3018c2ecf20Sopenharmony_ci	NULL,
3028c2ecf20Sopenharmony_ci};
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
3058c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_input_header,
3068c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_format_yuv,
3078c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
3088c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
3098c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_color_matching,
3108c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
3118c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
3128c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
3138c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_color_matching,
3148c2ecf20Sopenharmony_ci	NULL,
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
3188c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_input_header,
3198c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_format_yuv,
3208c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
3218c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
3228c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_color_matching,
3238c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
3248c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
3258c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
3268c2ecf20Sopenharmony_ci	(const struct uvc_descriptor_header *) &uvc_color_matching,
3278c2ecf20Sopenharmony_ci	NULL,
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------------
3318c2ecf20Sopenharmony_ci * USB configuration
3328c2ecf20Sopenharmony_ci */
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int
3358c2ecf20Sopenharmony_ciwebcam_config_bind(struct usb_configuration *c)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int status = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	f_uvc = usb_get_function(fi_uvc);
3408c2ecf20Sopenharmony_ci	if (IS_ERR(f_uvc))
3418c2ecf20Sopenharmony_ci		return PTR_ERR(f_uvc);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	status = usb_add_function(c, f_uvc);
3448c2ecf20Sopenharmony_ci	if (status < 0)
3458c2ecf20Sopenharmony_ci		usb_put_function(f_uvc);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	return status;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic struct usb_configuration webcam_config_driver = {
3518c2ecf20Sopenharmony_ci	.label			= webcam_config_label,
3528c2ecf20Sopenharmony_ci	.bConfigurationValue	= 1,
3538c2ecf20Sopenharmony_ci	.iConfiguration		= 0, /* dynamic */
3548c2ecf20Sopenharmony_ci	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
3558c2ecf20Sopenharmony_ci	.MaxPower		= CONFIG_USB_GADGET_VBUS_DRAW,
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int
3598c2ecf20Sopenharmony_ciwebcam_unbind(struct usb_composite_dev *cdev)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(f_uvc))
3628c2ecf20Sopenharmony_ci		usb_put_function(f_uvc);
3638c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(fi_uvc))
3648c2ecf20Sopenharmony_ci		usb_put_function_instance(fi_uvc);
3658c2ecf20Sopenharmony_ci	return 0;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic int
3698c2ecf20Sopenharmony_ciwebcam_bind(struct usb_composite_dev *cdev)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct f_uvc_opts *uvc_opts;
3728c2ecf20Sopenharmony_ci	int ret;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	fi_uvc = usb_get_function_instance("uvc");
3758c2ecf20Sopenharmony_ci	if (IS_ERR(fi_uvc))
3768c2ecf20Sopenharmony_ci		return PTR_ERR(fi_uvc);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	uvc_opts = container_of(fi_uvc, struct f_uvc_opts, func_inst);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	uvc_opts->streaming_interval = streaming_interval;
3818c2ecf20Sopenharmony_ci	uvc_opts->streaming_maxpacket = streaming_maxpacket;
3828c2ecf20Sopenharmony_ci	uvc_opts->streaming_maxburst = streaming_maxburst;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	uvc_opts->fs_control = uvc_fs_control_cls;
3858c2ecf20Sopenharmony_ci	uvc_opts->ss_control = uvc_ss_control_cls;
3868c2ecf20Sopenharmony_ci	uvc_opts->fs_streaming = uvc_fs_streaming_cls;
3878c2ecf20Sopenharmony_ci	uvc_opts->hs_streaming = uvc_hs_streaming_cls;
3888c2ecf20Sopenharmony_ci	uvc_opts->ss_streaming = uvc_ss_streaming_cls;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* Allocate string descriptor numbers ... note that string contents
3918c2ecf20Sopenharmony_ci	 * can be overridden by the composite_dev glue.
3928c2ecf20Sopenharmony_ci	 */
3938c2ecf20Sopenharmony_ci	ret = usb_string_ids_tab(cdev, webcam_strings);
3948c2ecf20Sopenharmony_ci	if (ret < 0)
3958c2ecf20Sopenharmony_ci		goto error;
3968c2ecf20Sopenharmony_ci	webcam_device_descriptor.iManufacturer =
3978c2ecf20Sopenharmony_ci		webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
3988c2ecf20Sopenharmony_ci	webcam_device_descriptor.iProduct =
3998c2ecf20Sopenharmony_ci		webcam_strings[USB_GADGET_PRODUCT_IDX].id;
4008c2ecf20Sopenharmony_ci	webcam_config_driver.iConfiguration =
4018c2ecf20Sopenharmony_ci		webcam_strings[STRING_DESCRIPTION_IDX].id;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Register our configuration. */
4048c2ecf20Sopenharmony_ci	if ((ret = usb_add_config(cdev, &webcam_config_driver,
4058c2ecf20Sopenharmony_ci					webcam_config_bind)) < 0)
4068c2ecf20Sopenharmony_ci		goto error;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	usb_composite_overwrite_options(cdev, &coverwrite);
4098c2ecf20Sopenharmony_ci	INFO(cdev, "Webcam Video Gadget\n");
4108c2ecf20Sopenharmony_ci	return 0;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cierror:
4138c2ecf20Sopenharmony_ci	usb_put_function_instance(fi_uvc);
4148c2ecf20Sopenharmony_ci	return ret;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------------
4188c2ecf20Sopenharmony_ci * Driver
4198c2ecf20Sopenharmony_ci */
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic struct usb_composite_driver webcam_driver = {
4228c2ecf20Sopenharmony_ci	.name		= "g_webcam",
4238c2ecf20Sopenharmony_ci	.dev		= &webcam_device_descriptor,
4248c2ecf20Sopenharmony_ci	.strings	= webcam_device_strings,
4258c2ecf20Sopenharmony_ci	.max_speed	= USB_SPEED_SUPER,
4268c2ecf20Sopenharmony_ci	.bind		= webcam_bind,
4278c2ecf20Sopenharmony_ci	.unbind		= webcam_unbind,
4288c2ecf20Sopenharmony_ci};
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cimodule_usb_composite_driver(webcam_driver);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laurent Pinchart");
4338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Webcam Video Gadget");
4348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4358c2ecf20Sopenharmony_ci
436