1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * webcam.c -- USB webcam gadget driver
4 *
5 * Copyright (C) 2009-2010
6 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 */
8
9#include <linux/kernel.h>
10#include <linux/device.h>
11#include <linux/module.h>
12#include <linux/usb/video.h>
13
14#include "u_uvc.h"
15#include "uvc_configfs.h"
16
17USB_GADGET_COMPOSITE_OPTIONS();
18
19/*-------------------------------------------------------------------------*/
20
21/* module parameters specific to the Video streaming endpoint */
22static unsigned int streaming_interval = 1;
23module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
24MODULE_PARM_DESC(streaming_interval, "1 - 16");
25
26static unsigned int streaming_maxpacket = 1024;
27module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
28MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
29
30static unsigned int streaming_maxburst;
31module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
32MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
33
34/* --------------------------------------------------------------------------
35 * Device descriptor
36 */
37
38#define WEBCAM_VENDOR_ID 0x1d6b /* Linux Foundation */
39#define WEBCAM_PRODUCT_ID 0x0102 /* Webcam A/V gadget */
40#define WEBCAM_DEVICE_BCD 0x0010 /* 0.10 */
41
42static char webcam_vendor_label[] = "Linux Foundation";
43static char webcam_product_label[] = "Webcam gadget";
44static char webcam_config_label[] = "Video";
45
46/* string IDs are assigned dynamically */
47
48#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
49
50static struct usb_string webcam_strings[] = {
51 [USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
52 [USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
53 [USB_GADGET_SERIAL_IDX].s = "",
54 [STRING_DESCRIPTION_IDX].s = webcam_config_label,
55 { }
56};
57
58static struct usb_gadget_strings webcam_stringtab = {
59 .language = 0x0409, /* en-us */
60 .strings = webcam_strings,
61};
62
63static struct usb_gadget_strings *webcam_device_strings[] = {
64 &webcam_stringtab,
65 NULL,
66};
67
68static struct usb_function_instance *fi_uvc;
69static struct usb_function *f_uvc;
70
71static struct usb_device_descriptor webcam_device_descriptor = {
72 .bLength = USB_DT_DEVICE_SIZE,
73 .bDescriptorType = USB_DT_DEVICE,
74 /* .bcdUSB = DYNAMIC */
75 .bDeviceClass = USB_CLASS_MISC,
76 .bDeviceSubClass = 0x02,
77 .bDeviceProtocol = 0x01,
78 .bMaxPacketSize0 = 0, /* dynamic */
79 .idVendor = cpu_to_le16(WEBCAM_VENDOR_ID),
80 .idProduct = cpu_to_le16(WEBCAM_PRODUCT_ID),
81 .bcdDevice = cpu_to_le16(WEBCAM_DEVICE_BCD),
82 .iManufacturer = 0, /* dynamic */
83 .iProduct = 0, /* dynamic */
84 .iSerialNumber = 0, /* dynamic */
85 .bNumConfigurations = 0, /* dynamic */
86};
87
88static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
89 .bLength = UVC_DT_HEADER_SIZE(1),
90 .bDescriptorType = USB_DT_CS_INTERFACE,
91 .bDescriptorSubType = UVC_VC_HEADER,
92 .bcdUVC = cpu_to_le16(0x0110),
93 .wTotalLength = 0, /* dynamic */
94 .dwClockFrequency = cpu_to_le32(48000000),
95 .bInCollection = 0, /* dynamic */
96 .baInterfaceNr[0] = 0, /* dynamic */
97};
98
99static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
100 .bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3),
101 .bDescriptorType = USB_DT_CS_INTERFACE,
102 .bDescriptorSubType = UVC_VC_INPUT_TERMINAL,
103 .bTerminalID = 1,
104 .wTerminalType = cpu_to_le16(0x0201),
105 .bAssocTerminal = 0,
106 .iTerminal = 0,
107 .wObjectiveFocalLengthMin = cpu_to_le16(0),
108 .wObjectiveFocalLengthMax = cpu_to_le16(0),
109 .wOcularFocalLength = cpu_to_le16(0),
110 .bControlSize = 3,
111 .bmControls[0] = 2,
112 .bmControls[1] = 0,
113 .bmControls[2] = 0,
114};
115
116static const struct uvc_processing_unit_descriptor uvc_processing = {
117 .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
118 .bDescriptorType = USB_DT_CS_INTERFACE,
119 .bDescriptorSubType = UVC_VC_PROCESSING_UNIT,
120 .bUnitID = 2,
121 .bSourceID = 1,
122 .wMaxMultiplier = cpu_to_le16(16*1024),
123 .bControlSize = 2,
124 .bmControls[0] = 1,
125 .bmControls[1] = 0,
126 .iProcessing = 0,
127 .bmVideoStandards = 0,
128};
129
130static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
131 .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE,
132 .bDescriptorType = USB_DT_CS_INTERFACE,
133 .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL,
134 .bTerminalID = 3,
135 .wTerminalType = cpu_to_le16(0x0101),
136 .bAssocTerminal = 0,
137 .bSourceID = 2,
138 .iTerminal = 0,
139};
140
141DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
142
143static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
144 .bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2),
145 .bDescriptorType = USB_DT_CS_INTERFACE,
146 .bDescriptorSubType = UVC_VS_INPUT_HEADER,
147 .bNumFormats = 2,
148 .wTotalLength = 0, /* dynamic */
149 .bEndpointAddress = 0, /* dynamic */
150 .bmInfo = 0,
151 .bTerminalLink = 3,
152 .bStillCaptureMethod = 0,
153 .bTriggerSupport = 0,
154 .bTriggerUsage = 0,
155 .bControlSize = 1,
156 .bmaControls[0][0] = 0,
157 .bmaControls[1][0] = 4,
158};
159
160static const struct uvcg_color_matching uvcg_color_matching = {
161 .desc = {
162 .bLength = UVC_DT_COLOR_MATCHING_SIZE,
163 .bDescriptorType = USB_DT_CS_INTERFACE,
164 .bDescriptorSubType = UVC_VS_COLORFORMAT,
165 .bColorPrimaries = 1,
166 .bTransferCharacteristics = 1,
167 .bMatrixCoefficients = 4,
168 },
169};
170
171static struct uvcg_uncompressed uvcg_format_yuv = {
172 .fmt = {
173 .type = UVCG_UNCOMPRESSED,
174 /* add to .frames and fill .num_frames at runtime */
175 .color_matching = (struct uvcg_color_matching *)&uvcg_color_matching,
176 },
177 .desc = {
178 .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
179 .bDescriptorType = USB_DT_CS_INTERFACE,
180 .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
181 .bFormatIndex = 1,
182 .bNumFrameDescriptors = 2,
183 .guidFormat = {
184 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
185 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
186 },
187 .bBitsPerPixel = 16,
188 .bDefaultFrameIndex = 1,
189 .bAspectRatioX = 0,
190 .bAspectRatioY = 0,
191 .bmInterlaceFlags = 0,
192 .bCopyProtect = 0,
193 },
194};
195
196static struct uvcg_format_ptr uvcg_format_ptr_yuv = {
197 .fmt = &uvcg_format_yuv.fmt,
198};
199
200DECLARE_UVC_FRAME_UNCOMPRESSED(1);
201DECLARE_UVC_FRAME_UNCOMPRESSED(3);
202
203#define UVCG_WIDTH_360P 640
204#define UVCG_HEIGHT_360P 360
205#define UVCG_MIN_BITRATE_360P 18432000
206#define UVCG_MAX_BITRATE_360P 55296000
207#define UVCG_MAX_VIDEO_FB_SZ_360P 460800
208#define UVCG_FRM_INTERV_0_360P 666666
209#define UVCG_FRM_INTERV_1_360P 1000000
210#define UVCG_FRM_INTERV_2_360P 5000000
211#define UVCG_DEFAULT_FRM_INTERV_360P UVCG_FRM_INTERV_0_360P
212
213static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
214 .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
215 .bDescriptorType = USB_DT_CS_INTERFACE,
216 .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
217 .bFrameIndex = 1,
218 .bmCapabilities = 0,
219 .wWidth = cpu_to_le16(UVCG_WIDTH_360P),
220 .wHeight = cpu_to_le16(UVCG_HEIGHT_360P),
221 .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P),
222 .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P),
223 .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P),
224 .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P),
225 .bFrameIntervalType = 3,
226 .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P),
227 .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P),
228 .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P),
229};
230
231static u32 uvcg_frame_yuv_360p_dw_frame_interval[] = {
232 [0] = UVCG_FRM_INTERV_0_360P,
233 [1] = UVCG_FRM_INTERV_1_360P,
234 [2] = UVCG_FRM_INTERV_2_360P,
235};
236
237static const struct uvcg_frame uvcg_frame_yuv_360p = {
238 .fmt_type = UVCG_UNCOMPRESSED,
239 .frame = {
240 .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
241 .b_descriptor_type = USB_DT_CS_INTERFACE,
242 .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED,
243 .b_frame_index = 1,
244 .bm_capabilities = 0,
245 .w_width = UVCG_WIDTH_360P,
246 .w_height = UVCG_HEIGHT_360P,
247 .dw_min_bit_rate = UVCG_MIN_BITRATE_360P,
248 .dw_max_bit_rate = UVCG_MAX_BITRATE_360P,
249 .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P,
250 .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P,
251 .b_frame_interval_type = 3,
252 },
253 .dw_frame_interval = uvcg_frame_yuv_360p_dw_frame_interval,
254};
255
256static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_360p = {
257 .frm = (struct uvcg_frame *)&uvcg_frame_yuv_360p,
258};
259#define UVCG_WIDTH_720P 1280
260#define UVCG_HEIGHT_720P 720
261#define UVCG_MIN_BITRATE_720P 29491200
262#define UVCG_MAX_BITRATE_720P 29491200
263#define UVCG_MAX_VIDEO_FB_SZ_720P 1843200
264#define UVCG_FRM_INTERV_0_720P 5000000
265#define UVCG_DEFAULT_FRM_INTERV_720P UVCG_FRM_INTERV_0_720P
266
267static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
268 .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
269 .bDescriptorType = USB_DT_CS_INTERFACE,
270 .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
271 .bFrameIndex = 2,
272 .bmCapabilities = 0,
273 .wWidth = cpu_to_le16(UVCG_WIDTH_720P),
274 .wHeight = cpu_to_le16(UVCG_HEIGHT_720P),
275 .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P),
276 .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P),
277 .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P),
278 .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P),
279 .bFrameIntervalType = 1,
280 .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P),
281};
282
283static u32 uvcg_frame_yuv_720p_dw_frame_interval[] = {
284 [0] = UVCG_FRM_INTERV_0_720P,
285};
286
287static const struct uvcg_frame uvcg_frame_yuv_720p = {
288 .fmt_type = UVCG_UNCOMPRESSED,
289 .frame = {
290 .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
291 .b_descriptor_type = USB_DT_CS_INTERFACE,
292 .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED,
293 .b_frame_index = 2,
294 .bm_capabilities = 0,
295 .w_width = UVCG_WIDTH_720P,
296 .w_height = UVCG_HEIGHT_720P,
297 .dw_min_bit_rate = UVCG_MIN_BITRATE_720P,
298 .dw_max_bit_rate = UVCG_MAX_BITRATE_720P,
299 .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P,
300 .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P,
301 .b_frame_interval_type = 1,
302 },
303 .dw_frame_interval = uvcg_frame_yuv_720p_dw_frame_interval,
304};
305
306static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_720p = {
307 .frm = (struct uvcg_frame *)&uvcg_frame_yuv_720p,
308};
309
310static struct uvcg_mjpeg uvcg_format_mjpeg = {
311 .fmt = {
312 .type = UVCG_MJPEG,
313 /* add to .frames and fill .num_frames at runtime */
314 .color_matching = (struct uvcg_color_matching *)&uvcg_color_matching,
315 },
316 .desc = {
317 .bLength = UVC_DT_FORMAT_MJPEG_SIZE,
318 .bDescriptorType = USB_DT_CS_INTERFACE,
319 .bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
320 .bFormatIndex = 2,
321 .bNumFrameDescriptors = 2,
322 .bmFlags = 0,
323 .bDefaultFrameIndex = 1,
324 .bAspectRatioX = 0,
325 .bAspectRatioY = 0,
326 .bmInterlaceFlags = 0,
327 .bCopyProtect = 0,
328 },
329};
330
331static struct uvcg_format_ptr uvcg_format_ptr_mjpeg = {
332 .fmt = &uvcg_format_mjpeg.fmt,
333};
334
335DECLARE_UVC_FRAME_MJPEG(1);
336DECLARE_UVC_FRAME_MJPEG(3);
337
338static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
339 .bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
340 .bDescriptorType = USB_DT_CS_INTERFACE,
341 .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
342 .bFrameIndex = 1,
343 .bmCapabilities = 0,
344 .wWidth = cpu_to_le16(UVCG_WIDTH_360P),
345 .wHeight = cpu_to_le16(UVCG_HEIGHT_360P),
346 .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P),
347 .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P),
348 .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P),
349 .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P),
350 .bFrameIntervalType = 3,
351 .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P),
352 .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P),
353 .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P),
354};
355
356static u32 uvcg_frame_mjpeg_360p_dw_frame_interval[] = {
357 [0] = UVCG_FRM_INTERV_0_360P,
358 [1] = UVCG_FRM_INTERV_1_360P,
359 [2] = UVCG_FRM_INTERV_2_360P,
360};
361
362static const struct uvcg_frame uvcg_frame_mjpeg_360p = {
363 .fmt_type = UVCG_MJPEG,
364 .frame = {
365 .b_length = UVC_DT_FRAME_MJPEG_SIZE(3),
366 .b_descriptor_type = USB_DT_CS_INTERFACE,
367 .b_descriptor_subtype = UVC_VS_FRAME_MJPEG,
368 .b_frame_index = 1,
369 .bm_capabilities = 0,
370 .w_width = UVCG_WIDTH_360P,
371 .w_height = UVCG_HEIGHT_360P,
372 .dw_min_bit_rate = UVCG_MIN_BITRATE_360P,
373 .dw_max_bit_rate = UVCG_MAX_BITRATE_360P,
374 .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P,
375 .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P,
376 .b_frame_interval_type = 3,
377 },
378 .dw_frame_interval = uvcg_frame_mjpeg_360p_dw_frame_interval,
379};
380
381static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_360p = {
382 .frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_360p,
383};
384
385static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
386 .bLength = UVC_DT_FRAME_MJPEG_SIZE(1),
387 .bDescriptorType = USB_DT_CS_INTERFACE,
388 .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
389 .bFrameIndex = 2,
390 .bmCapabilities = 0,
391 .wWidth = cpu_to_le16(UVCG_WIDTH_720P),
392 .wHeight = cpu_to_le16(UVCG_HEIGHT_720P),
393 .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P),
394 .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P),
395 .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P),
396 .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P),
397 .bFrameIntervalType = 1,
398 .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P),
399};
400
401static u32 uvcg_frame_mjpeg_720p_dw_frame_interval[] = {
402 [0] = UVCG_FRM_INTERV_0_720P,
403};
404
405static const struct uvcg_frame uvcg_frame_mjpeg_720p = {
406 .fmt_type = UVCG_MJPEG,
407 .frame = {
408 .b_length = UVC_DT_FRAME_MJPEG_SIZE(1),
409 .b_descriptor_type = USB_DT_CS_INTERFACE,
410 .b_descriptor_subtype = UVC_VS_FRAME_MJPEG,
411 .b_frame_index = 2,
412 .bm_capabilities = 0,
413 .w_width = UVCG_WIDTH_720P,
414 .w_height = UVCG_HEIGHT_720P,
415 .dw_min_bit_rate = UVCG_MIN_BITRATE_720P,
416 .dw_max_bit_rate = UVCG_MAX_BITRATE_720P,
417 .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P,
418 .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P,
419 .b_frame_interval_type = 1,
420 },
421 .dw_frame_interval = uvcg_frame_mjpeg_720p_dw_frame_interval,
422};
423
424static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_720p = {
425 .frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_720p,
426};
427
428static struct uvcg_streaming_header uvcg_streaming_header = {
429};
430
431static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
432 (const struct uvc_descriptor_header *) &uvc_control_header,
433 (const struct uvc_descriptor_header *) &uvc_camera_terminal,
434 (const struct uvc_descriptor_header *) &uvc_processing,
435 (const struct uvc_descriptor_header *) &uvc_output_terminal,
436 NULL,
437};
438
439static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
440 (const struct uvc_descriptor_header *) &uvc_control_header,
441 (const struct uvc_descriptor_header *) &uvc_camera_terminal,
442 (const struct uvc_descriptor_header *) &uvc_processing,
443 (const struct uvc_descriptor_header *) &uvc_output_terminal,
444 NULL,
445};
446
447static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
448 (const struct uvc_descriptor_header *) &uvc_input_header,
449 (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
450 (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
451 (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
452 (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
453 (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
454 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
455 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
456 (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
457 NULL,
458};
459
460static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
461 (const struct uvc_descriptor_header *) &uvc_input_header,
462 (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
463 (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
464 (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
465 (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
466 (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
467 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
468 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
469 (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
470 NULL,
471};
472
473static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
474 (const struct uvc_descriptor_header *) &uvc_input_header,
475 (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
476 (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
477 (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
478 (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
479 (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
480 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
481 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
482 (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
483 NULL,
484};
485
486/* --------------------------------------------------------------------------
487 * USB configuration
488 */
489
490static int
491webcam_config_bind(struct usb_configuration *c)
492{
493 int status = 0;
494
495 f_uvc = usb_get_function(fi: fi_uvc);
496 if (IS_ERR(ptr: f_uvc))
497 return PTR_ERR(ptr: f_uvc);
498
499 status = usb_add_function(c, f_uvc);
500 if (status < 0)
501 usb_put_function(f: f_uvc);
502
503 return status;
504}
505
506static struct usb_configuration webcam_config_driver = {
507 .label = webcam_config_label,
508 .bConfigurationValue = 1,
509 .iConfiguration = 0, /* dynamic */
510 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
511 .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW,
512};
513
514static int
515webcam_unbind(struct usb_composite_dev *cdev)
516{
517 if (!IS_ERR_OR_NULL(ptr: f_uvc))
518 usb_put_function(f: f_uvc);
519 if (!IS_ERR_OR_NULL(ptr: fi_uvc))
520 usb_put_function_instance(fi: fi_uvc);
521 return 0;
522}
523
524static int
525webcam_bind(struct usb_composite_dev *cdev)
526{
527 struct f_uvc_opts *uvc_opts;
528 int ret;
529
530 fi_uvc = usb_get_function_instance(name: "uvc");
531 if (IS_ERR(ptr: fi_uvc))
532 return PTR_ERR(ptr: fi_uvc);
533
534 uvc_opts = container_of(fi_uvc, struct f_uvc_opts, func_inst);
535
536 uvc_opts->streaming_interval = streaming_interval;
537 uvc_opts->streaming_maxpacket = streaming_maxpacket;
538 uvc_opts->streaming_maxburst = streaming_maxburst;
539
540 uvc_opts->fs_control = uvc_fs_control_cls;
541 uvc_opts->ss_control = uvc_ss_control_cls;
542 uvc_opts->fs_streaming = uvc_fs_streaming_cls;
543 uvc_opts->hs_streaming = uvc_hs_streaming_cls;
544 uvc_opts->ss_streaming = uvc_ss_streaming_cls;
545
546 INIT_LIST_HEAD(list: &uvcg_format_yuv.fmt.frames);
547 list_add_tail(new: &uvcg_frame_ptr_yuv_360p.entry, head: &uvcg_format_yuv.fmt.frames);
548 list_add_tail(new: &uvcg_frame_ptr_yuv_720p.entry, head: &uvcg_format_yuv.fmt.frames);
549 uvcg_format_yuv.fmt.num_frames = 2;
550
551 INIT_LIST_HEAD(list: &uvcg_format_mjpeg.fmt.frames);
552 list_add_tail(new: &uvcg_frame_ptr_mjpeg_360p.entry, head: &uvcg_format_mjpeg.fmt.frames);
553 list_add_tail(new: &uvcg_frame_ptr_mjpeg_720p.entry, head: &uvcg_format_mjpeg.fmt.frames);
554 uvcg_format_mjpeg.fmt.num_frames = 2;
555
556 INIT_LIST_HEAD(list: &uvcg_streaming_header.formats);
557 list_add_tail(new: &uvcg_format_ptr_yuv.entry, head: &uvcg_streaming_header.formats);
558 list_add_tail(new: &uvcg_format_ptr_mjpeg.entry, head: &uvcg_streaming_header.formats);
559 uvcg_streaming_header.num_fmt = 2;
560
561 uvc_opts->header = &uvcg_streaming_header;
562
563 /* Allocate string descriptor numbers ... note that string contents
564 * can be overridden by the composite_dev glue.
565 */
566 ret = usb_string_ids_tab(c: cdev, str: webcam_strings);
567 if (ret < 0)
568 goto error;
569 webcam_device_descriptor.iManufacturer =
570 webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
571 webcam_device_descriptor.iProduct =
572 webcam_strings[USB_GADGET_PRODUCT_IDX].id;
573 webcam_config_driver.iConfiguration =
574 webcam_strings[STRING_DESCRIPTION_IDX].id;
575
576 /* Register our configuration. */
577 if ((ret = usb_add_config(cdev, &webcam_config_driver,
578 webcam_config_bind)) < 0)
579 goto error;
580
581 usb_composite_overwrite_options(cdev, covr: &coverwrite);
582 INFO(cdev, "Webcam Video Gadget\n");
583 return 0;
584
585error:
586 usb_put_function_instance(fi: fi_uvc);
587 return ret;
588}
589
590/* --------------------------------------------------------------------------
591 * Driver
592 */
593
594static struct usb_composite_driver webcam_driver = {
595 .name = "g_webcam",
596 .dev = &webcam_device_descriptor,
597 .strings = webcam_device_strings,
598 .max_speed = USB_SPEED_SUPER,
599 .bind = webcam_bind,
600 .unbind = webcam_unbind,
601};
602
603module_usb_composite_driver(webcam_driver);
604
605MODULE_AUTHOR("Laurent Pinchart");
606MODULE_DESCRIPTION("Webcam Video Gadget");
607MODULE_LICENSE("GPL");
608
609

source code of linux/drivers/usb/gadget/legacy/webcam.c