📄 vino.c
字号:
/* * Driver for the VINO (Video In No Out) system found in SGI Indys. * * This file is subject to the terms and conditions of the GNU General Public * License version 2 as published by the Free Software Foundation. * * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> * * Based on the previous version of the driver for 2.4 kernels by: * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> *//* * TODO: * - remove "mark pages reserved-hacks" from memory allocation code * and implement nopage() * - check decimation, calculating and reporting image size when * using decimation * - implement read(), user mode buffers and overlay (?) */#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/moduleparam.h>#include <linux/time.h>#include <linux/version.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <linux/i2c.h>#include <linux/i2c-algo-sgi.h>#include <linux/videodev.h>#include <linux/videodev2.h>#include <linux/video_decoder.h>#include "compat.h"#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)#include <linux/mutex.h>#endif#include <asm/paccess.h>#include <asm/io.h>#include <asm/sgi/ip22.h>#include <asm/sgi/mc.h>#include "vino.h"#include "saa7191.h"#include "indycam.h"/* Uncomment the following line to get lots and lots of (mostly useless) * debug info. * Note that the debug output also slows down the driver significantly */// #define VINO_DEBUG// #define VINO_DEBUG_INT#define VINO_MODULE_VERSION "0.0.5"#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 5)MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");MODULE_VERSION(VINO_MODULE_VERSION);MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");MODULE_LICENSE("GPL");#ifdef VINO_DEBUG#define dprintk(x...) printk("VINO: " x);#else#define dprintk(x...)#endif#define VINO_NO_CHANNEL 0#define VINO_CHANNEL_A 1#define VINO_CHANNEL_B 2#define VINO_PAL_WIDTH 768#define VINO_PAL_HEIGHT 576#define VINO_NTSC_WIDTH 640#define VINO_NTSC_HEIGHT 480#define VINO_MIN_WIDTH 32#define VINO_MIN_HEIGHT 32#define VINO_CLIPPING_START_ODD_D1 1#define VINO_CLIPPING_START_ODD_PAL 15#define VINO_CLIPPING_START_ODD_NTSC 12#define VINO_CLIPPING_START_EVEN_D1 2#define VINO_CLIPPING_START_EVEN_PAL 15#define VINO_CLIPPING_START_EVEN_NTSC 12#define VINO_INPUT_CHANNEL_COUNT 3/* the number is the index for vino_inputs */#define VINO_INPUT_NONE -1#define VINO_INPUT_COMPOSITE 0#define VINO_INPUT_SVIDEO 1#define VINO_INPUT_D1 2#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE)#define VINO_FIFO_THRESHOLD_DEFAULT 16#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \ * VINO_PAL_HEIGHT * 4 \ + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))#define VINO_FRAMEBUFFER_COUNT_MAX 8#define VINO_FRAMEBUFFER_UNUSED 0#define VINO_FRAMEBUFFER_IN_USE 1#define VINO_FRAMEBUFFER_READY 2#define VINO_QUEUE_ERROR -1#define VINO_QUEUE_MAGIC 0x20050125#define VINO_MEMORY_NONE 0#define VINO_MEMORY_MMAP 1#define VINO_MEMORY_USERPTR 2#define VINO_DUMMY_DESC_COUNT 4#define VINO_DESC_FETCH_DELAY 5 /* microseconds */#define VINO_MAX_FRAME_SKIP_COUNT 128/* the number is the index for vino_data_formats */#define VINO_DATA_FMT_NONE -1#define VINO_DATA_FMT_GREY 0#define VINO_DATA_FMT_RGB332 1#define VINO_DATA_FMT_RGB32 2#define VINO_DATA_FMT_YUV 3#define VINO_DATA_FMT_COUNT 4/* the number is the index for vino_data_norms */#define VINO_DATA_NORM_NONE -1#define VINO_DATA_NORM_NTSC 0#define VINO_DATA_NORM_PAL 1#define VINO_DATA_NORM_SECAM 2#define VINO_DATA_NORM_D1 3/* The following are special entries that can be used to * autodetect the norm. */#define VINO_DATA_NORM_AUTO 0xfe#define VINO_DATA_NORM_AUTO_EXT 0xff#define VINO_DATA_NORM_COUNT 4/* Internal data structure definitions */struct vino_input { char *name; v4l2_std_id std;};struct vino_clipping { unsigned int left, right, top, bottom;};struct vino_data_format { /* the description */ char *description; /* bytes per pixel */ unsigned int bpp; /* V4L2 fourcc code */ __u32 pixelformat; /* V4L2 colorspace (duh!) */ enum v4l2_colorspace colorspace;};struct vino_data_norm { char *description; unsigned int width, height; struct vino_clipping odd; struct vino_clipping even; v4l2_std_id std; unsigned int fps_min, fps_max; __u32 framelines;};struct vino_descriptor_table { /* the number of PAGE_SIZE sized pages in the buffer */ unsigned int page_count; /* virtual (kmalloc'd) pointers to the actual data * (in PAGE_SIZE chunks, used with mmap streaming) */ unsigned long *virtual; /* cpu address for the VINO descriptor table * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ unsigned long *dma_cpu; /* dma address for the VINO descriptor table * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ dma_addr_t dma;};struct vino_framebuffer { /* identifier nubmer */ unsigned int id; /* the length of the whole buffer */ unsigned int size; /* the length of actual data in buffer */ unsigned int data_size; /* the data format */ unsigned int data_format; /* the state of buffer data */ unsigned int state; /* is the buffer mapped in user space? */ unsigned int map_count; /* memory offset for mmap() */ unsigned int offset; /* frame counter */ unsigned int frame_counter; /* timestamp (written when image capture finishes) */ struct timeval timestamp; struct vino_descriptor_table desc_table; spinlock_t state_lock;};struct vino_framebuffer_fifo { unsigned int length; unsigned int used; unsigned int head; unsigned int tail; unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX];};struct vino_framebuffer_queue { unsigned int magic; /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */ unsigned int type; unsigned int length; /* data field of in and out contain index numbers for buffer */ struct vino_framebuffer_fifo in; struct vino_framebuffer_fifo out; struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX]; spinlock_t queue_lock; struct mutex queue_mutex; wait_queue_head_t frame_wait_queue;};struct vino_interrupt_data { struct timeval timestamp; unsigned int frame_counter; unsigned int skip_count; unsigned int skip;};struct vino_channel_settings { unsigned int channel; int input; unsigned int data_format; unsigned int data_norm; struct vino_clipping clipping; unsigned int decimation; unsigned int line_size; unsigned int alpha; unsigned int fps; unsigned int framert_reg; unsigned int fifo_threshold; struct vino_framebuffer_queue fb_queue; /* number of the current field */ unsigned int field; /* read in progress */ int reading; /* streaming is active */ int streaming; /* the driver is currently processing the queue */ int capturing; struct mutex channel_mutex; spinlock_t capture_lock; unsigned int users; struct vino_interrupt_data int_data; /* V4L support */ struct video_device *v4l_device;};struct vino_client { /* the channel which owns this client: * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */ unsigned int owner; struct i2c_client *driver;};struct vino_settings { struct vino_channel_settings a; struct vino_channel_settings b; struct vino_client decoder; struct vino_client camera; /* a lock for vino register access */ spinlock_t vino_lock; /* a lock for channel input changes */ spinlock_t input_lock; unsigned long dummy_page; struct vino_descriptor_table dummy_desc_table;};/* Module parameters *//* * Using vino_pixel_conversion the ABGR32-format pixels supplied * by the VINO chip can be converted to more common formats * like RGBA32 (or probably RGB24 in the future). This way we * can give out data that can be specified correctly with * the V4L2-definitions. * * The pixel format is specified as RGBA32 when no conversion * is used. * * Note that this only affects the 32-bit bit depth. * * Use non-zero value to enable conversion. */static int vino_pixel_conversion = 0;module_param_named(pixelconv, vino_pixel_conversion, int, 0);MODULE_PARM_DESC(pixelconv, "enable pixel conversion (non-zero value enables)");/* Internal data structures */static struct sgi_vino *vino;static struct vino_settings *vino_drvdata;static const char *vino_driver_name = "vino";static const char *vino_driver_description = "SGI VINO";static const char *vino_bus_name = "GIO64 bus";static const char *vino_v4l_device_name_a = "SGI VINO Channel A";static const char *vino_v4l_device_name_b = "SGI VINO Channel B";static void vino_capture_tasklet(unsigned long channel);DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A);DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B);static const struct vino_input vino_inputs[] = { { .name = "Composite", .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, },{ .name = "S-Video", .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, },{ .name = "D1/IndyCam", .std = V4L2_STD_NTSC, }};static const struct vino_data_format vino_data_formats[] = { { .description = "8-bit greyscale", .bpp = 1, .pixelformat = V4L2_PIX_FMT_GREY, .colorspace = V4L2_COLORSPACE_SMPTE170M, },{ .description = "8-bit dithered RGB 3-3-2", .bpp = 1, .pixelformat = V4L2_PIX_FMT_RGB332, .colorspace = V4L2_COLORSPACE_SRGB, },{ .description = "32-bit RGB", .bpp = 4, .pixelformat = V4L2_PIX_FMT_RGB32, .colorspace = V4L2_COLORSPACE_SRGB, },{ .description = "YUV 4:2:2", .bpp = 2, .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped? .colorspace = V4L2_COLORSPACE_SMPTE170M, }};static const struct vino_data_norm vino_data_norms[] = { { .description = "NTSC", .std = V4L2_STD_NTSC, .fps_min = 6, .fps_max = 30, .framelines = 525, .width = VINO_NTSC_WIDTH, .height = VINO_NTSC_HEIGHT, .odd = { .top = VINO_CLIPPING_START_ODD_NTSC, .left = 0, .bottom = VINO_CLIPPING_START_ODD_NTSC + VINO_NTSC_HEIGHT / 2 - 1, .right = VINO_NTSC_WIDTH, }, .even = { .top = VINO_CLIPPING_START_EVEN_NTSC, .left = 0, .bottom = VINO_CLIPPING_START_EVEN_NTSC + VINO_NTSC_HEIGHT / 2 - 1, .right = VINO_NTSC_WIDTH, }, },{ .description = "PAL", .std = V4L2_STD_PAL, .fps_min = 5, .fps_max = 25, .framelines = 625, .width = VINO_PAL_WIDTH, .height = VINO_PAL_HEIGHT, .odd = { .top = VINO_CLIPPING_START_ODD_PAL, .left = 0, .bottom = VINO_CLIPPING_START_ODD_PAL + VINO_PAL_HEIGHT / 2 - 1, .right = VINO_PAL_WIDTH, }, .even = { .top = VINO_CLIPPING_START_EVEN_PAL, .left = 0, .bottom = VINO_CLIPPING_START_EVEN_PAL + VINO_PAL_HEIGHT / 2 - 1, .right = VINO_PAL_WIDTH, }, },{ .description = "SECAM", .std = V4L2_STD_SECAM, .fps_min = 5, .fps_max = 25, .framelines = 625, .width = VINO_PAL_WIDTH, .height = VINO_PAL_HEIGHT, .odd = { .top = VINO_CLIPPING_START_ODD_PAL, .left = 0, .bottom = VINO_CLIPPING_START_ODD_PAL + VINO_PAL_HEIGHT / 2 - 1, .right = VINO_PAL_WIDTH, }, .even = { .top = VINO_CLIPPING_START_EVEN_PAL, .left = 0, .bottom = VINO_CLIPPING_START_EVEN_PAL + VINO_PAL_HEIGHT / 2 - 1, .right = VINO_PAL_WIDTH, }, },{ .description = "NTSC/D1", .std = V4L2_STD_NTSC, .fps_min = 6, .fps_max = 30, .framelines = 525, .width = VINO_NTSC_WIDTH, .height = VINO_NTSC_HEIGHT, .odd = { .top = VINO_CLIPPING_START_ODD_D1, .left = 0, .bottom = VINO_CLIPPING_START_ODD_D1 + VINO_NTSC_HEIGHT / 2 - 1, .right = VINO_NTSC_WIDTH, }, .even = { .top = VINO_CLIPPING_START_EVEN_D1, .left = 0, .bottom = VINO_CLIPPING_START_EVEN_D1 + VINO_NTSC_HEIGHT / 2 - 1, .right = VINO_NTSC_WIDTH, }, }};#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Automatic Gain Control", .minimum = 0, .maximum = 1, .step = 1, .default_value = INDYCAM_AGC_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_AGC, 0 }, },{ .id = V4L2_CID_AUTO_WHITE_BALANCE, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Automatic White Balance", .minimum = 0, .maximum = 1, .step = 1, .default_value = INDYCAM_AWB_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_AWB, 0 }, },{ .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Gain", .minimum = INDYCAM_GAIN_MIN, .maximum = INDYCAM_GAIN_MAX, .step = 1, .default_value = INDYCAM_GAIN_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_GAIN, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Red Saturation", .minimum = INDYCAM_RED_SATURATION_MIN, .maximum = INDYCAM_RED_SATURATION_MAX, .step = 1, .default_value = INDYCAM_RED_SATURATION_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 1, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Blue Saturation", .minimum = INDYCAM_BLUE_SATURATION_MIN, .maximum = INDYCAM_BLUE_SATURATION_MAX, .step = 1, .default_value = INDYCAM_BLUE_SATURATION_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 }, },{ .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Red Balance", .minimum = INDYCAM_RED_BALANCE_MIN, .maximum = INDYCAM_RED_BALANCE_MAX, .step = 1, .default_value = INDYCAM_RED_BALANCE_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 }, },{ .id = V4L2_CID_BLUE_BALANCE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -