mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-14 20:36:41 +07:00
d7e2853679
Now that the SPDX tag is in all USB files, that identifies the license in a specific and legally-defined manner. So the extra GPL text wording can be removed as it is no longer needed at all. This is done on a quest to remove the 700+ different ways that files in the kernel describe the GPL license text. And there's unneeded stuff like the address (sometimes incorrect) for the FSF which is never needed. No copyright headers or other non-license-description text was removed. Cc: Johan Hovold <johan@kernel.org> Cc: Ruslan Bilovol <ruslan.bilovol@gmail.com> Cc: Peter Chen <peter.chen@nxp.com> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: David Windsor <dwindsor@gmail.com> Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
436 lines
13 KiB
C
436 lines
13 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* webcam.c -- USB webcam gadget driver
|
|
*
|
|
* Copyright (C) 2009-2010
|
|
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/usb/video.h>
|
|
|
|
#include "u_uvc.h"
|
|
|
|
USB_GADGET_COMPOSITE_OPTIONS();
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* module parameters specific to the Video streaming endpoint */
|
|
static unsigned int streaming_interval = 1;
|
|
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
|
|
MODULE_PARM_DESC(streaming_interval, "1 - 16");
|
|
|
|
static unsigned int streaming_maxpacket = 1024;
|
|
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
|
|
MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
|
|
|
|
static unsigned int streaming_maxburst;
|
|
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
|
|
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
|
|
|
|
static unsigned int trace;
|
|
module_param(trace, uint, S_IRUGO|S_IWUSR);
|
|
MODULE_PARM_DESC(trace, "Trace level bitmask");
|
|
/* --------------------------------------------------------------------------
|
|
* Device descriptor
|
|
*/
|
|
|
|
#define WEBCAM_VENDOR_ID 0x1d6b /* Linux Foundation */
|
|
#define WEBCAM_PRODUCT_ID 0x0102 /* Webcam A/V gadget */
|
|
#define WEBCAM_DEVICE_BCD 0x0010 /* 0.10 */
|
|
|
|
static char webcam_vendor_label[] = "Linux Foundation";
|
|
static char webcam_product_label[] = "Webcam gadget";
|
|
static char webcam_config_label[] = "Video";
|
|
|
|
/* string IDs are assigned dynamically */
|
|
|
|
#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
|
|
|
|
static struct usb_string webcam_strings[] = {
|
|
[USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
|
|
[USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
|
|
[USB_GADGET_SERIAL_IDX].s = "",
|
|
[STRING_DESCRIPTION_IDX].s = webcam_config_label,
|
|
{ }
|
|
};
|
|
|
|
static struct usb_gadget_strings webcam_stringtab = {
|
|
.language = 0x0409, /* en-us */
|
|
.strings = webcam_strings,
|
|
};
|
|
|
|
static struct usb_gadget_strings *webcam_device_strings[] = {
|
|
&webcam_stringtab,
|
|
NULL,
|
|
};
|
|
|
|
static struct usb_function_instance *fi_uvc;
|
|
static struct usb_function *f_uvc;
|
|
|
|
static struct usb_device_descriptor webcam_device_descriptor = {
|
|
.bLength = USB_DT_DEVICE_SIZE,
|
|
.bDescriptorType = USB_DT_DEVICE,
|
|
/* .bcdUSB = DYNAMIC */
|
|
.bDeviceClass = USB_CLASS_MISC,
|
|
.bDeviceSubClass = 0x02,
|
|
.bDeviceProtocol = 0x01,
|
|
.bMaxPacketSize0 = 0, /* dynamic */
|
|
.idVendor = cpu_to_le16(WEBCAM_VENDOR_ID),
|
|
.idProduct = cpu_to_le16(WEBCAM_PRODUCT_ID),
|
|
.bcdDevice = cpu_to_le16(WEBCAM_DEVICE_BCD),
|
|
.iManufacturer = 0, /* dynamic */
|
|
.iProduct = 0, /* dynamic */
|
|
.iSerialNumber = 0, /* dynamic */
|
|
.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,
|
|
.bDescriptorSubType = UVC_VC_HEADER,
|
|
.bcdUVC = cpu_to_le16(0x0100),
|
|
.wTotalLength = 0, /* dynamic */
|
|
.dwClockFrequency = cpu_to_le32(48000000),
|
|
.bInCollection = 0, /* dynamic */
|
|
.baInterfaceNr[0] = 0, /* dynamic */
|
|
};
|
|
|
|
static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
|
|
.bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VC_INPUT_TERMINAL,
|
|
.bTerminalID = 1,
|
|
.wTerminalType = cpu_to_le16(0x0201),
|
|
.bAssocTerminal = 0,
|
|
.iTerminal = 0,
|
|
.wObjectiveFocalLengthMin = cpu_to_le16(0),
|
|
.wObjectiveFocalLengthMax = cpu_to_le16(0),
|
|
.wOcularFocalLength = cpu_to_le16(0),
|
|
.bControlSize = 3,
|
|
.bmControls[0] = 2,
|
|
.bmControls[1] = 0,
|
|
.bmControls[2] = 0,
|
|
};
|
|
|
|
static const struct uvc_processing_unit_descriptor uvc_processing = {
|
|
.bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VC_PROCESSING_UNIT,
|
|
.bUnitID = 2,
|
|
.bSourceID = 1,
|
|
.wMaxMultiplier = cpu_to_le16(16*1024),
|
|
.bControlSize = 2,
|
|
.bmControls[0] = 1,
|
|
.bmControls[1] = 0,
|
|
.iProcessing = 0,
|
|
};
|
|
|
|
static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
|
|
.bLength = UVC_DT_OUTPUT_TERMINAL_SIZE,
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL,
|
|
.bTerminalID = 3,
|
|
.wTerminalType = cpu_to_le16(0x0101),
|
|
.bAssocTerminal = 0,
|
|
.bSourceID = 2,
|
|
.iTerminal = 0,
|
|
};
|
|
|
|
DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
|
|
|
|
static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
|
|
.bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VS_INPUT_HEADER,
|
|
.bNumFormats = 2,
|
|
.wTotalLength = 0, /* dynamic */
|
|
.bEndpointAddress = 0, /* dynamic */
|
|
.bmInfo = 0,
|
|
.bTerminalLink = 3,
|
|
.bStillCaptureMethod = 0,
|
|
.bTriggerSupport = 0,
|
|
.bTriggerUsage = 0,
|
|
.bControlSize = 1,
|
|
.bmaControls[0][0] = 0,
|
|
.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,
|
|
.bmInterfaceFlags = 0,
|
|
.bCopyProtect = 0,
|
|
};
|
|
|
|
DECLARE_UVC_FRAME_UNCOMPRESSED(1);
|
|
DECLARE_UVC_FRAME_UNCOMPRESSED(3);
|
|
|
|
static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
|
|
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
|
|
.bFrameIndex = 1,
|
|
.bmCapabilities = 0,
|
|
.wWidth = cpu_to_le16(640),
|
|
.wHeight = cpu_to_le16(360),
|
|
.dwMinBitRate = cpu_to_le32(18432000),
|
|
.dwMaxBitRate = cpu_to_le32(55296000),
|
|
.dwMaxVideoFrameBufferSize = cpu_to_le32(460800),
|
|
.dwDefaultFrameInterval = cpu_to_le32(666666),
|
|
.bFrameIntervalType = 3,
|
|
.dwFrameInterval[0] = cpu_to_le32(666666),
|
|
.dwFrameInterval[1] = cpu_to_le32(1000000),
|
|
.dwFrameInterval[2] = cpu_to_le32(5000000),
|
|
};
|
|
|
|
static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
|
|
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
|
|
.bFrameIndex = 2,
|
|
.bmCapabilities = 0,
|
|
.wWidth = cpu_to_le16(1280),
|
|
.wHeight = cpu_to_le16(720),
|
|
.dwMinBitRate = cpu_to_le32(29491200),
|
|
.dwMaxBitRate = cpu_to_le32(29491200),
|
|
.dwMaxVideoFrameBufferSize = cpu_to_le32(1843200),
|
|
.dwDefaultFrameInterval = cpu_to_le32(5000000),
|
|
.bFrameIntervalType = 1,
|
|
.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,
|
|
.bmInterfaceFlags = 0,
|
|
.bCopyProtect = 0,
|
|
};
|
|
|
|
DECLARE_UVC_FRAME_MJPEG(1);
|
|
DECLARE_UVC_FRAME_MJPEG(3);
|
|
|
|
static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
|
|
.bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VS_FRAME_MJPEG,
|
|
.bFrameIndex = 1,
|
|
.bmCapabilities = 0,
|
|
.wWidth = cpu_to_le16(640),
|
|
.wHeight = cpu_to_le16(360),
|
|
.dwMinBitRate = cpu_to_le32(18432000),
|
|
.dwMaxBitRate = cpu_to_le32(55296000),
|
|
.dwMaxVideoFrameBufferSize = cpu_to_le32(460800),
|
|
.dwDefaultFrameInterval = cpu_to_le32(666666),
|
|
.bFrameIntervalType = 3,
|
|
.dwFrameInterval[0] = cpu_to_le32(666666),
|
|
.dwFrameInterval[1] = cpu_to_le32(1000000),
|
|
.dwFrameInterval[2] = cpu_to_le32(5000000),
|
|
};
|
|
|
|
static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
|
|
.bLength = UVC_DT_FRAME_MJPEG_SIZE(1),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubType = UVC_VS_FRAME_MJPEG,
|
|
.bFrameIndex = 2,
|
|
.bmCapabilities = 0,
|
|
.wWidth = cpu_to_le16(1280),
|
|
.wHeight = cpu_to_le16(720),
|
|
.dwMinBitRate = cpu_to_le32(29491200),
|
|
.dwMaxBitRate = cpu_to_le32(29491200),
|
|
.dwMaxVideoFrameBufferSize = cpu_to_le32(1843200),
|
|
.dwDefaultFrameInterval = cpu_to_le32(5000000),
|
|
.bFrameIntervalType = 1,
|
|
.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 uvc_descriptor_header * const uvc_fs_control_cls[] = {
|
|
(const struct uvc_descriptor_header *) &uvc_control_header,
|
|
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
|
|
(const struct uvc_descriptor_header *) &uvc_processing,
|
|
(const struct uvc_descriptor_header *) &uvc_output_terminal,
|
|
NULL,
|
|
};
|
|
|
|
static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
|
|
(const struct uvc_descriptor_header *) &uvc_control_header,
|
|
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
|
|
(const struct uvc_descriptor_header *) &uvc_processing,
|
|
(const struct uvc_descriptor_header *) &uvc_output_terminal,
|
|
NULL,
|
|
};
|
|
|
|
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 *) &uvc_frame_yuv_360p,
|
|
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
|
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
|
(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,
|
|
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 *) &uvc_frame_yuv_360p,
|
|
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
|
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
|
(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,
|
|
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 *) &uvc_frame_yuv_360p,
|
|
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
|
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
|
(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,
|
|
NULL,
|
|
};
|
|
|
|
/* --------------------------------------------------------------------------
|
|
* USB configuration
|
|
*/
|
|
|
|
static int
|
|
webcam_config_bind(struct usb_configuration *c)
|
|
{
|
|
int status = 0;
|
|
|
|
f_uvc = usb_get_function(fi_uvc);
|
|
if (IS_ERR(f_uvc))
|
|
return PTR_ERR(f_uvc);
|
|
|
|
status = usb_add_function(c, f_uvc);
|
|
if (status < 0)
|
|
usb_put_function(f_uvc);
|
|
|
|
return status;
|
|
}
|
|
|
|
static struct usb_configuration webcam_config_driver = {
|
|
.label = webcam_config_label,
|
|
.bConfigurationValue = 1,
|
|
.iConfiguration = 0, /* dynamic */
|
|
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
|
.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW,
|
|
};
|
|
|
|
static int
|
|
webcam_unbind(struct usb_composite_dev *cdev)
|
|
{
|
|
if (!IS_ERR_OR_NULL(f_uvc))
|
|
usb_put_function(f_uvc);
|
|
if (!IS_ERR_OR_NULL(fi_uvc))
|
|
usb_put_function_instance(fi_uvc);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
webcam_bind(struct usb_composite_dev *cdev)
|
|
{
|
|
struct f_uvc_opts *uvc_opts;
|
|
int ret;
|
|
|
|
fi_uvc = usb_get_function_instance("uvc");
|
|
if (IS_ERR(fi_uvc))
|
|
return PTR_ERR(fi_uvc);
|
|
|
|
uvc_opts = container_of(fi_uvc, struct f_uvc_opts, func_inst);
|
|
|
|
uvc_opts->streaming_interval = streaming_interval;
|
|
uvc_opts->streaming_maxpacket = streaming_maxpacket;
|
|
uvc_opts->streaming_maxburst = streaming_maxburst;
|
|
uvc_set_trace_param(trace);
|
|
|
|
uvc_opts->fs_control = uvc_fs_control_cls;
|
|
uvc_opts->ss_control = uvc_ss_control_cls;
|
|
uvc_opts->fs_streaming = uvc_fs_streaming_cls;
|
|
uvc_opts->hs_streaming = uvc_hs_streaming_cls;
|
|
uvc_opts->ss_streaming = uvc_ss_streaming_cls;
|
|
|
|
/* Allocate string descriptor numbers ... note that string contents
|
|
* can be overridden by the composite_dev glue.
|
|
*/
|
|
ret = usb_string_ids_tab(cdev, webcam_strings);
|
|
if (ret < 0)
|
|
goto error;
|
|
webcam_device_descriptor.iManufacturer =
|
|
webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
|
|
webcam_device_descriptor.iProduct =
|
|
webcam_strings[USB_GADGET_PRODUCT_IDX].id;
|
|
webcam_config_driver.iConfiguration =
|
|
webcam_strings[STRING_DESCRIPTION_IDX].id;
|
|
|
|
/* Register our configuration. */
|
|
if ((ret = usb_add_config(cdev, &webcam_config_driver,
|
|
webcam_config_bind)) < 0)
|
|
goto error;
|
|
|
|
usb_composite_overwrite_options(cdev, &coverwrite);
|
|
INFO(cdev, "Webcam Video Gadget\n");
|
|
return 0;
|
|
|
|
error:
|
|
usb_put_function_instance(fi_uvc);
|
|
return ret;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
* Driver
|
|
*/
|
|
|
|
static struct usb_composite_driver webcam_driver = {
|
|
.name = "g_webcam",
|
|
.dev = &webcam_device_descriptor,
|
|
.strings = webcam_device_strings,
|
|
.max_speed = USB_SPEED_SUPER,
|
|
.bind = webcam_bind,
|
|
.unbind = webcam_unbind,
|
|
};
|
|
|
|
module_usb_composite_driver(webcam_driver);
|
|
|
|
MODULE_AUTHOR("Laurent Pinchart");
|
|
MODULE_DESCRIPTION("Webcam Video Gadget");
|
|
MODULE_LICENSE("GPL");
|
|
|