webcam.c (13537B)
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 16USB_GADGET_COMPOSITE_OPTIONS(); 17 18/*-------------------------------------------------------------------------*/ 19 20/* module parameters specific to the Video streaming endpoint */ 21static unsigned int streaming_interval = 1; 22module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); 23MODULE_PARM_DESC(streaming_interval, "1 - 16"); 24 25static unsigned int streaming_maxpacket = 1024; 26module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); 27MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)"); 28 29static unsigned int streaming_maxburst; 30module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); 31MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)"); 32 33/* -------------------------------------------------------------------------- 34 * Device descriptor 35 */ 36 37#define WEBCAM_VENDOR_ID 0x1d6b /* Linux Foundation */ 38#define WEBCAM_PRODUCT_ID 0x0102 /* Webcam A/V gadget */ 39#define WEBCAM_DEVICE_BCD 0x0010 /* 0.10 */ 40 41static char webcam_vendor_label[] = "Linux Foundation"; 42static char webcam_product_label[] = "Webcam gadget"; 43static char webcam_config_label[] = "Video"; 44 45/* string IDs are assigned dynamically */ 46 47#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX 48 49static struct usb_string webcam_strings[] = { 50 [USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label, 51 [USB_GADGET_PRODUCT_IDX].s = webcam_product_label, 52 [USB_GADGET_SERIAL_IDX].s = "", 53 [STRING_DESCRIPTION_IDX].s = webcam_config_label, 54 { } 55}; 56 57static struct usb_gadget_strings webcam_stringtab = { 58 .language = 0x0409, /* en-us */ 59 .strings = webcam_strings, 60}; 61 62static struct usb_gadget_strings *webcam_device_strings[] = { 63 &webcam_stringtab, 64 NULL, 65}; 66 67static struct usb_function_instance *fi_uvc; 68static struct usb_function *f_uvc; 69 70static struct usb_device_descriptor webcam_device_descriptor = { 71 .bLength = USB_DT_DEVICE_SIZE, 72 .bDescriptorType = USB_DT_DEVICE, 73 /* .bcdUSB = DYNAMIC */ 74 .bDeviceClass = USB_CLASS_MISC, 75 .bDeviceSubClass = 0x02, 76 .bDeviceProtocol = 0x01, 77 .bMaxPacketSize0 = 0, /* dynamic */ 78 .idVendor = cpu_to_le16(WEBCAM_VENDOR_ID), 79 .idProduct = cpu_to_le16(WEBCAM_PRODUCT_ID), 80 .bcdDevice = cpu_to_le16(WEBCAM_DEVICE_BCD), 81 .iManufacturer = 0, /* dynamic */ 82 .iProduct = 0, /* dynamic */ 83 .iSerialNumber = 0, /* dynamic */ 84 .bNumConfigurations = 0, /* dynamic */ 85}; 86 87DECLARE_UVC_HEADER_DESCRIPTOR(1); 88 89static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { 90 .bLength = UVC_DT_HEADER_SIZE(1), 91 .bDescriptorType = USB_DT_CS_INTERFACE, 92 .bDescriptorSubType = UVC_VC_HEADER, 93 .bcdUVC = cpu_to_le16(0x0110), 94 .wTotalLength = 0, /* dynamic */ 95 .dwClockFrequency = cpu_to_le32(48000000), 96 .bInCollection = 0, /* dynamic */ 97 .baInterfaceNr[0] = 0, /* dynamic */ 98}; 99 100static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = { 101 .bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3), 102 .bDescriptorType = USB_DT_CS_INTERFACE, 103 .bDescriptorSubType = UVC_VC_INPUT_TERMINAL, 104 .bTerminalID = 1, 105 .wTerminalType = cpu_to_le16(0x0201), 106 .bAssocTerminal = 0, 107 .iTerminal = 0, 108 .wObjectiveFocalLengthMin = cpu_to_le16(0), 109 .wObjectiveFocalLengthMax = cpu_to_le16(0), 110 .wOcularFocalLength = cpu_to_le16(0), 111 .bControlSize = 3, 112 .bmControls[0] = 2, 113 .bmControls[1] = 0, 114 .bmControls[2] = 0, 115}; 116 117static const struct uvc_processing_unit_descriptor uvc_processing = { 118 .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2), 119 .bDescriptorType = USB_DT_CS_INTERFACE, 120 .bDescriptorSubType = UVC_VC_PROCESSING_UNIT, 121 .bUnitID = 2, 122 .bSourceID = 1, 123 .wMaxMultiplier = cpu_to_le16(16*1024), 124 .bControlSize = 2, 125 .bmControls[0] = 1, 126 .bmControls[1] = 0, 127 .iProcessing = 0, 128 .bmVideoStandards = 0, 129}; 130 131static const struct uvc_output_terminal_descriptor uvc_output_terminal = { 132 .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE, 133 .bDescriptorType = USB_DT_CS_INTERFACE, 134 .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL, 135 .bTerminalID = 3, 136 .wTerminalType = cpu_to_le16(0x0101), 137 .bAssocTerminal = 0, 138 .bSourceID = 2, 139 .iTerminal = 0, 140}; 141 142DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2); 143 144static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = { 145 .bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2), 146 .bDescriptorType = USB_DT_CS_INTERFACE, 147 .bDescriptorSubType = UVC_VS_INPUT_HEADER, 148 .bNumFormats = 2, 149 .wTotalLength = 0, /* dynamic */ 150 .bEndpointAddress = 0, /* dynamic */ 151 .bmInfo = 0, 152 .bTerminalLink = 3, 153 .bStillCaptureMethod = 0, 154 .bTriggerSupport = 0, 155 .bTriggerUsage = 0, 156 .bControlSize = 1, 157 .bmaControls[0][0] = 0, 158 .bmaControls[1][0] = 4, 159}; 160 161static const struct uvc_format_uncompressed uvc_format_yuv = { 162 .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, 163 .bDescriptorType = USB_DT_CS_INTERFACE, 164 .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, 165 .bFormatIndex = 1, 166 .bNumFrameDescriptors = 2, 167 .guidFormat = 168 { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, 169 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}, 170 .bBitsPerPixel = 16, 171 .bDefaultFrameIndex = 1, 172 .bAspectRatioX = 0, 173 .bAspectRatioY = 0, 174 .bmInterfaceFlags = 0, 175 .bCopyProtect = 0, 176}; 177 178DECLARE_UVC_FRAME_UNCOMPRESSED(1); 179DECLARE_UVC_FRAME_UNCOMPRESSED(3); 180 181static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = { 182 .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3), 183 .bDescriptorType = USB_DT_CS_INTERFACE, 184 .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, 185 .bFrameIndex = 1, 186 .bmCapabilities = 0, 187 .wWidth = cpu_to_le16(640), 188 .wHeight = cpu_to_le16(360), 189 .dwMinBitRate = cpu_to_le32(18432000), 190 .dwMaxBitRate = cpu_to_le32(55296000), 191 .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), 192 .dwDefaultFrameInterval = cpu_to_le32(666666), 193 .bFrameIntervalType = 3, 194 .dwFrameInterval[0] = cpu_to_le32(666666), 195 .dwFrameInterval[1] = cpu_to_le32(1000000), 196 .dwFrameInterval[2] = cpu_to_le32(5000000), 197}; 198 199static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = { 200 .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), 201 .bDescriptorType = USB_DT_CS_INTERFACE, 202 .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, 203 .bFrameIndex = 2, 204 .bmCapabilities = 0, 205 .wWidth = cpu_to_le16(1280), 206 .wHeight = cpu_to_le16(720), 207 .dwMinBitRate = cpu_to_le32(29491200), 208 .dwMaxBitRate = cpu_to_le32(29491200), 209 .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), 210 .dwDefaultFrameInterval = cpu_to_le32(5000000), 211 .bFrameIntervalType = 1, 212 .dwFrameInterval[0] = cpu_to_le32(5000000), 213}; 214 215static const struct uvc_format_mjpeg uvc_format_mjpg = { 216 .bLength = UVC_DT_FORMAT_MJPEG_SIZE, 217 .bDescriptorType = USB_DT_CS_INTERFACE, 218 .bDescriptorSubType = UVC_VS_FORMAT_MJPEG, 219 .bFormatIndex = 2, 220 .bNumFrameDescriptors = 2, 221 .bmFlags = 0, 222 .bDefaultFrameIndex = 1, 223 .bAspectRatioX = 0, 224 .bAspectRatioY = 0, 225 .bmInterfaceFlags = 0, 226 .bCopyProtect = 0, 227}; 228 229DECLARE_UVC_FRAME_MJPEG(1); 230DECLARE_UVC_FRAME_MJPEG(3); 231 232static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = { 233 .bLength = UVC_DT_FRAME_MJPEG_SIZE(3), 234 .bDescriptorType = USB_DT_CS_INTERFACE, 235 .bDescriptorSubType = UVC_VS_FRAME_MJPEG, 236 .bFrameIndex = 1, 237 .bmCapabilities = 0, 238 .wWidth = cpu_to_le16(640), 239 .wHeight = cpu_to_le16(360), 240 .dwMinBitRate = cpu_to_le32(18432000), 241 .dwMaxBitRate = cpu_to_le32(55296000), 242 .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), 243 .dwDefaultFrameInterval = cpu_to_le32(666666), 244 .bFrameIntervalType = 3, 245 .dwFrameInterval[0] = cpu_to_le32(666666), 246 .dwFrameInterval[1] = cpu_to_le32(1000000), 247 .dwFrameInterval[2] = cpu_to_le32(5000000), 248}; 249 250static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { 251 .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), 252 .bDescriptorType = USB_DT_CS_INTERFACE, 253 .bDescriptorSubType = UVC_VS_FRAME_MJPEG, 254 .bFrameIndex = 2, 255 .bmCapabilities = 0, 256 .wWidth = cpu_to_le16(1280), 257 .wHeight = cpu_to_le16(720), 258 .dwMinBitRate = cpu_to_le32(29491200), 259 .dwMaxBitRate = cpu_to_le32(29491200), 260 .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), 261 .dwDefaultFrameInterval = cpu_to_le32(5000000), 262 .bFrameIntervalType = 1, 263 .dwFrameInterval[0] = cpu_to_le32(5000000), 264}; 265 266static const struct uvc_color_matching_descriptor uvc_color_matching = { 267 .bLength = UVC_DT_COLOR_MATCHING_SIZE, 268 .bDescriptorType = USB_DT_CS_INTERFACE, 269 .bDescriptorSubType = UVC_VS_COLORFORMAT, 270 .bColorPrimaries = 1, 271 .bTransferCharacteristics = 1, 272 .bMatrixCoefficients = 4, 273}; 274 275static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = { 276 (const struct uvc_descriptor_header *) &uvc_control_header, 277 (const struct uvc_descriptor_header *) &uvc_camera_terminal, 278 (const struct uvc_descriptor_header *) &uvc_processing, 279 (const struct uvc_descriptor_header *) &uvc_output_terminal, 280 NULL, 281}; 282 283static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = { 284 (const struct uvc_descriptor_header *) &uvc_control_header, 285 (const struct uvc_descriptor_header *) &uvc_camera_terminal, 286 (const struct uvc_descriptor_header *) &uvc_processing, 287 (const struct uvc_descriptor_header *) &uvc_output_terminal, 288 NULL, 289}; 290 291static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { 292 (const struct uvc_descriptor_header *) &uvc_input_header, 293 (const struct uvc_descriptor_header *) &uvc_format_yuv, 294 (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, 295 (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, 296 (const struct uvc_descriptor_header *) &uvc_format_mjpg, 297 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, 298 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, 299 (const struct uvc_descriptor_header *) &uvc_color_matching, 300 NULL, 301}; 302 303static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { 304 (const struct uvc_descriptor_header *) &uvc_input_header, 305 (const struct uvc_descriptor_header *) &uvc_format_yuv, 306 (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, 307 (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, 308 (const struct uvc_descriptor_header *) &uvc_format_mjpg, 309 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, 310 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, 311 (const struct uvc_descriptor_header *) &uvc_color_matching, 312 NULL, 313}; 314 315static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { 316 (const struct uvc_descriptor_header *) &uvc_input_header, 317 (const struct uvc_descriptor_header *) &uvc_format_yuv, 318 (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, 319 (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, 320 (const struct uvc_descriptor_header *) &uvc_format_mjpg, 321 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, 322 (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, 323 (const struct uvc_descriptor_header *) &uvc_color_matching, 324 NULL, 325}; 326 327/* -------------------------------------------------------------------------- 328 * USB configuration 329 */ 330 331static int 332webcam_config_bind(struct usb_configuration *c) 333{ 334 int status = 0; 335 336 f_uvc = usb_get_function(fi_uvc); 337 if (IS_ERR(f_uvc)) 338 return PTR_ERR(f_uvc); 339 340 status = usb_add_function(c, f_uvc); 341 if (status < 0) 342 usb_put_function(f_uvc); 343 344 return status; 345} 346 347static struct usb_configuration webcam_config_driver = { 348 .label = webcam_config_label, 349 .bConfigurationValue = 1, 350 .iConfiguration = 0, /* dynamic */ 351 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 352 .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW, 353}; 354 355static int 356webcam_unbind(struct usb_composite_dev *cdev) 357{ 358 if (!IS_ERR_OR_NULL(f_uvc)) 359 usb_put_function(f_uvc); 360 if (!IS_ERR_OR_NULL(fi_uvc)) 361 usb_put_function_instance(fi_uvc); 362 return 0; 363} 364 365static int 366webcam_bind(struct usb_composite_dev *cdev) 367{ 368 struct f_uvc_opts *uvc_opts; 369 int ret; 370 371 fi_uvc = usb_get_function_instance("uvc"); 372 if (IS_ERR(fi_uvc)) 373 return PTR_ERR(fi_uvc); 374 375 uvc_opts = container_of(fi_uvc, struct f_uvc_opts, func_inst); 376 377 uvc_opts->streaming_interval = streaming_interval; 378 uvc_opts->streaming_maxpacket = streaming_maxpacket; 379 uvc_opts->streaming_maxburst = streaming_maxburst; 380 381 uvc_opts->fs_control = uvc_fs_control_cls; 382 uvc_opts->ss_control = uvc_ss_control_cls; 383 uvc_opts->fs_streaming = uvc_fs_streaming_cls; 384 uvc_opts->hs_streaming = uvc_hs_streaming_cls; 385 uvc_opts->ss_streaming = uvc_ss_streaming_cls; 386 387 /* Allocate string descriptor numbers ... note that string contents 388 * can be overridden by the composite_dev glue. 389 */ 390 ret = usb_string_ids_tab(cdev, webcam_strings); 391 if (ret < 0) 392 goto error; 393 webcam_device_descriptor.iManufacturer = 394 webcam_strings[USB_GADGET_MANUFACTURER_IDX].id; 395 webcam_device_descriptor.iProduct = 396 webcam_strings[USB_GADGET_PRODUCT_IDX].id; 397 webcam_config_driver.iConfiguration = 398 webcam_strings[STRING_DESCRIPTION_IDX].id; 399 400 /* Register our configuration. */ 401 if ((ret = usb_add_config(cdev, &webcam_config_driver, 402 webcam_config_bind)) < 0) 403 goto error; 404 405 usb_composite_overwrite_options(cdev, &coverwrite); 406 INFO(cdev, "Webcam Video Gadget\n"); 407 return 0; 408 409error: 410 usb_put_function_instance(fi_uvc); 411 return ret; 412} 413 414/* -------------------------------------------------------------------------- 415 * Driver 416 */ 417 418static struct usb_composite_driver webcam_driver = { 419 .name = "g_webcam", 420 .dev = &webcam_device_descriptor, 421 .strings = webcam_device_strings, 422 .max_speed = USB_SPEED_SUPER, 423 .bind = webcam_bind, 424 .unbind = webcam_unbind, 425}; 426 427module_usb_composite_driver(webcam_driver); 428 429MODULE_AUTHOR("Laurent Pinchart"); 430MODULE_DESCRIPTION("Webcam Video Gadget"); 431MODULE_LICENSE("GPL"); 432