📄 uvcvideo.c
字号:
/* * uvcvideo.c -- USB Video Class driver * * Copyright (C) 2005-2006 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * *//* * WARNING: This driver is definitely *NOT* complete. It will (hopefully) * support UVC devices with a camera sensors, a processing unit and several * optional extension units. Everything else is unsupported. * * The driver doesn't support the deprecated v4l1 interface. It implements the * mmap capture method only, and doesn't do any image format conversion in * software. If your user-space application doesn't support YUYV or MJPEG, fix * it :-). Please note that the MJPEG data have been stripped from their * Huffman tables (DHT marker), you will need to add it back if your JPEG * codec can't handle MJPEG data. * * Multiple open is not supported. Opening the driver multiple times will fail * with -EBUSY. This might or might not be fixed soon. * * Although the driver compiles on 2.6.12, you should use a 2.6.15 or newer * kernel because of USB issues. */ #include <linux/kernel.h>#include <linux/version.h>#include <linux/list.h>#include <linux/module.h>#include <linux/usb.h>#include <linux/videodev.h>#include <linux/vmalloc.h>#include <linux/wait.h>#include <asm/atomic.h>#include <asm/semaphore.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)#include <media/v4l2-common.h>#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,99)#include "v4l2_enumfrmfmt.h"#endif#include "uvcvideo.h"#define DRIVER_AUTHOR "Laurent Pinchart <laurent.pinchart@skynet.be>"#define DRIVER_DESC "USB Video Class driver"#define DRIVER_VERSION "0.1.0"#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)#define UVC_CTRL_TIMEOUT 300#define UVC_GUID_UVC_CAMERA {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}#define UVC_GUID_UVC_PROCESSING {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}#define UVC_GUID_LOGITECH_XU1 {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1d}#define UVC_GUID_LOGITECH_XU2 {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}#define UVC_GUID_LOGITECH_XU3 {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}#define UVC_GUID_LOGITECH_MOTOR {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}#define UVC_GUID_FORMAT_MJPEG {0x4d, 0x4a, 0x50, 0x47, 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}#define UVC_GUID_FORMAT_YUY2 {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}#define UVC_GUID_FORMAT_NV12 {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}#define UVC_CONTROL_SET_CUR (1 << 0)#define UVC_CONTROL_GET_CUR (1 << 1)#define UVC_CONTROL_GET_MIN (1 << 2)#define UVC_CONTROL_GET_MAX (1 << 3)#define UVC_CONTROL_GET_RES (1 << 4)#define UVC_CONTROL_GET_DEF (1 << 5)#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ UVC_CONTROL_GET_DEF)/* Number of isochronous URBs. */#define UVC_URBS 5/* Maximum number of packets per isochronous URB. */#define UVC_MAX_ISO_PACKETS 40/* Maximum frame size in bytes, for sanity checking. */#define UVC_MAX_FRAME_SIZE (16*1024*1024)/* Maximum number of video buffers. */#define UVC_MAX_VIDEO_BUFFERS 32/* ------------------------------------------------------------------------ * Structures */struct uvc_device;/* TODO: Put the most frequently accessed fields at the beginning of * structures to maximize cache efficiency. */struct uvc_streaming_control { __u16 bmHint; __u8 bFormatIndex; __u8 bFrameIndex; __u32 dwFrameInterval; __u16 wKeyFrameRate; __u16 wPFrameRate; __u16 wCompQuality; __u16 wCompWindowSize; __u16 wDelay; __u32 dwMaxVideoFrameSize; __u32 dwMaxPayloadTransferSize; __u32 dwClockFrequency; __u8 bmFramingInfo; __u8 bPreferedVersion; __u8 bMinVersion; __u8 bMaxVersion;};struct uvc_menu_info { __u32 index; __u8 name[32];};struct uvc_control_desc { __u32 v4l2; enum v4l2_ctrl_type type; __u8 name[32]; __u8 id; __u8 bit; __u8 size; __u8 unit[16]; __u8 flags; struct uvc_menu_info *menu_info; __u32 menu_count;};struct uvc_format_desc { __u8 guid[16]; __u32 fcc;};struct uvc_terminal { struct list_head list; __u8 id; __u16 type; char name[64]; union { struct { __u16 wObjectiveFocalLengthMin; __u16 wObjectiveFocalLengthMax; __u16 wOcularFocalLength; __u8 bControlSize; __u8 *bmControls; } camera; struct { __u8 bSourceID; } output; };};struct uvc_unit { struct list_head list; int id; int type; char name[64]; union { struct { __u8 bSourceID; __u16 wMaxMultiplier; __u8 bControlSize; __u8 *bmControls; __u8 bmVideoStandards; } processing; struct { __u8 bNrInPins; __u8 *baSourceID; } selector; struct { __u8 guidExtensionCode[16]; __u8 bNumControls; __u8 bNrInPins; __u8 *baSourceID; __u8 bControlSize; __u8 *bmControls; __u8 *bmControlsType; } extension; };};struct uvc_frame { __u8 bFrameIndex; __u8 bmCapabilities; __u16 wWidth; __u16 wHeight; __u32 dwMinBitRate; __u32 dwMaxBitRate; __u32 dwMaxVideoFrameBufferSize; __u8 bFrameIntervalType; __u32 dwDefaultFrameInterval; __u32 *dwFrameInterval;};struct uvc_format { __u8 type; __u8 index; __u8 bpp; __u8 colorspace; __u32 fcc; __u32 flags; char name[32]; unsigned int nframes; struct uvc_frame *frame;};struct uvc_input_header { __u8 bNumFormats; __u8 bEndpointAddress; __u8 bmInfo; __u8 bTerminalLink; __u8 bStillCaptureMethod; __u8 bTriggerSupport; __u8 bTriggerUsage; __u8 bControlSize; __u8 *bmaControls;};struct uvc_output_header {};struct uvc_streaming { struct list_head list; struct usb_interface *intf; int intfnum; __u16 maxpsize; union { struct uvc_input_header input; struct uvc_output_header output; }; unsigned int nformats; struct uvc_format *format; struct uvc_streaming_control ctrl; struct uvc_format *cur_format; struct uvc_frame *cur_frame; struct semaphore lock;};enum uvc_stream_state { UVC_STREAM_OFF = 0, UVC_STREAM_INTERRUPT = 1, UVC_STREAM_ON = 2,};enum uvc_buffer_state { UVC_BUF_STATE_IDLE = 0, UVC_BUF_STATE_QUEUED = 1, UVC_BUF_STATE_ACTIVE = 2, UVC_BUF_STATE_DONE = 3, UVC_BUF_STATE_ERROR = 4,};struct uvc_buffer { unsigned int size; unsigned long vma_use_count; struct list_head stream; /* Touched by interrupt handler. */ struct v4l2_buffer buf; struct list_head queue; wait_queue_head_t wait; enum uvc_buffer_state state;};struct uvc_video_queue { void *mem; unsigned int streaming; __u32 sequence; __u8 last_fid; unsigned int count; struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; struct semaphore lock; spinlock_t irqlock; struct list_head mainqueue; struct list_head irqqueue;};struct uvc_video_device { struct uvc_device *dev; struct video_device *vdev; atomic_t count; enum uvc_stream_state stream; struct uvc_terminal *iterm; struct uvc_terminal *oterm; struct uvc_unit *processing; struct uvc_unit *extension[8]; struct uvc_video_queue queue; struct uvc_streaming *streaming; struct urb *urb[UVC_URBS]; char *iso_buffer[UVC_URBS];};enum uvc_device_state { UVC_DEV_DISCONNECTED = 1,};struct uvc_device { struct usb_device *udev; struct usb_interface *intf; int intfnum; enum uvc_device_state state; struct kref kref; /* Video control interface */ __u16 uvc_version; __u32 clock_frequency; struct list_head terminals; struct list_head units; struct uvc_video_device video; /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; __u8 status[16]; /* Video Streaming interfaces */ struct list_head streaming;};struct uvc_fh { struct uvc_device *video;};/* ------------------------------------------------------------------------ * Forward declarations */static DECLARE_MUTEX(dev_sem);static struct usb_driver uvc_driver;static void uvc_delete(struct kref *kref);/* ------------------------------------------------------------------------ * Control, formats, ... */static struct uvc_menu_info power_line_frequency_controls[] = { { 0, "Disabled" }, { 1, "50 Hz" }, { 2, "60 Hz" },};static struct uvc_control_desc uvc_ctrls[] = { { .v4l2 = V4L2_CID_BRIGHTNESS, .name = "Brightness", .id = PU_BRIGHTNESS_CONTROL, .bit = 0, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_CONTRAST, .name = "Contrast", .id = PU_CONTRAST_CONTROL, .bit = 1, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_HUE, .name = "Hue", .id = PU_HUE_CONTROL, .bit = 2, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_SATURATION, .name = "Saturation", .id = PU_SATURATION_CONTROL, .bit = 3, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_SHARPNESS, .name = "Sharpness", .id = PU_SHARPNESS_CONTROL, .bit = 4, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_GAMMA, .name = "Gamma", .id = PU_GAMMA_CONTROL, .bit = 5, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_BACKLIGHT_COMPENSATION, .name = "Backlight Compensation", .id = PU_BACKLIGHT_COMPENSATION_CONTROL, .bit = 8, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_GAIN, .name = "Gain", .id = PU_GAIN_CONTROL, .bit = 9, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .v4l2 = V4L2_CID_POWER_LINE_FREQUENCY, .name = "Power Line Frequency", .id = PU_POWER_LINE_FREQUENCY_CONTROL, .bit = 10, .size = 1, .type = V4L2_CTRL_TYPE_MENU, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, .menu_info = power_line_frequency_controls, .menu_count = ARRAY_SIZE(power_line_frequency_controls), }, { .v4l2 = V4L2_CID_HUE_AUTO, .name = "Hue, Auto", .id = PU_HUE_AUTO_CONTROL, .bit = 11, .size = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF, }, {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -