⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ov511.c

📁 0v511摄像头linux最新驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * OmniVision OV511 Camera-to-USB Bridge Driver
 *
 * Copyright (c) 1999-2002 Mark W. McClelland
 * Original decompression code Copyright 1998-2000 OmniVision Technologies
 * Many improvements by Bret Wallach <bwallac1@san.rr.com>
 * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
 * Snapshot code by Kevin Moore
 * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
 * Changes by Claudio Matsuoka <claudio@conectiva.com>
 * Original SAA7111A code by Dave Perks <dperks@ibm.net>
 * URB error messages from pwc driver by Nemosoft
 * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
 * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
 *
 * Based on the Linux CPiA driver written by Peter Pregler,
 * Scott J. Bertin and Johannes Erdfelt.
 * 
 * Please see the file: linux/Documentation/usb/ov511.txt 
 * and the website at:  http://alpha.dyndns.org/ov511
 * for more info.
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/config.h>

#if defined(OUTSIDE_KERNEL)
	#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
		#define MODVERSIONS
	#endif

	#include <linux/version.h>

	#ifdef MODVERSIONS
		#include <linux/modversions.h>
	#endif
#else
	#include <linux/version.h>
#endif

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <linux/wrapper.h>

/* 2.4.18+/2.5.5+ forward-compatibility; for page_address() */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 18)
	#include <linux/mm.h>
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
	#if defined (__i386__)
		#include <asm/cpufeature.h>
	#endif
#endif

/* 2.2.x compatibility */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
	#ifdef CONFIG_KMOD
		#include <linux/kmod.h>
	#endif

	/* For rvmalloc() and friends */
	#define virt_to_page(va) MAP_NR(va)
#endif

/************** Special compatibility options **************/

/* A new implementation of the V4L 1 API exists that gives drivers direct
 * access to file_operations. The old API is compatible with all 2.2 and 2.4
 * kernels, and all 2.5 kernels through 2.5.5 (at least).
 *
 * Remove this #define to enable the new API
 *
 * Note: This has nothing to do with the V4L 2 API.
 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 7)
	#define OV511_OLD_V4L
#endif

/* Conversion between standard V4L formats should only be done by apps. This
 * #define performs conversion in this driver, to maintain backward
 * compatibility with apps that can't convert YUV420 to their native format
 *
 * This should remain defined for 2.2 and 2.4 kernels. It should be removed
 * for 2.5 kernels, including the code that it enables.
 */
#define OV511_ALLOW_CONVERSION

/***********************************************************/

#include "ov511.h"

/*
 * Version Information
 */
#define DRIVER_VERSION "v1.63"
#define EMAIL "mark@alpha.dyndns.org"
#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
	<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
#define DRIVER_DESC "ov511 USB Camera Driver"

#define OV511_I2C_RETRIES 3
#define ENABLE_Y_QUANTABLE 1
#define ENABLE_UV_QUANTABLE 1

#define OV511_MAX_UNIT_VIDEO 16

#ifdef OV511_ALLOW_CONVERSION
	/* Pixel count * 3 bytes for RGB */
	#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3)
#else
	/* Pixel count * bytes per YUV420 pixel (1.5) */
	#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
#endif

#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))

/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)

#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)

/**********************************************************************
 * Module Parameters
 * (See ov511.txt for detailed descriptions of these)
 **********************************************************************/

/* These variables (and all static globals) default to zero */
static int autobright		= 1;
static int autogain		= 1;
static int autoexp		= 1;
static int debug;
static int snapshot;
#ifdef OV511_ALLOW_CONVERSION
	static int fix_rgb_offset;
	static int force_rgb;
#endif
static int cams			= 1;
static int compress;
static int testpat;
static int dumppix;
static int led 			= 1;
static int dump_bridge;
static int dump_sensor;
static int printph;
static int phy			= 0x1f;
static int phuv			= 0x05;
static int pvy			= 0x06;
static int pvuv			= 0x06;
static int qhy			= 0x14;
static int qhuv			= 0x03;
static int qvy			= 0x04;
static int qvuv			= 0x04;
static int lightfreq;
static int bandingfilter;

/* Pixel clock divisor */
static int clockdiv		= -1;

/* Isoc packet size */
static int packetsize		= -1;

/* Frame drop register (16h) */
static int framedrop		= -1;

static int fastset;
static int force_palette;
static int backlight;
static int unit_video[OV511_MAX_UNIT_VIDEO];
static int remove_zeros;
static int mirror;
static int ov518_color;

MODULE_PARM(autobright, "i");
MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
MODULE_PARM(autogain, "i");
MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
MODULE_PARM(autoexp, "i");
MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug,
  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
MODULE_PARM(snapshot, "i");
MODULE_PARM_DESC(snapshot, "Enable snapshot mode");

#ifdef OV511_ALLOW_CONVERSION
	MODULE_PARM(fix_rgb_offset, "i");
	MODULE_PARM_DESC(fix_rgb_offset,
	  "Fix vertical misalignment of red and blue at 640x480");
	MODULE_PARM(force_rgb, "i");
	MODULE_PARM_DESC(force_rgb, "Read RGB instead of BGR");
#endif

MODULE_PARM(cams, "i");
MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
MODULE_PARM(compress, "i");
MODULE_PARM_DESC(compress, "Turn on compression (not reliable yet)");
MODULE_PARM(testpat, "i");
MODULE_PARM_DESC(testpat,
  "Replace image with vertical bar testpattern (only partially working)");
MODULE_PARM(dumppix, "i");
MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
MODULE_PARM(led, "i");
MODULE_PARM_DESC(led,
  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
MODULE_PARM(dump_bridge, "i");
MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
MODULE_PARM(dump_sensor, "i");
MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
MODULE_PARM(printph, "i");
MODULE_PARM_DESC(printph, "Print frame start/end headers");
MODULE_PARM(phy, "i");
MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
MODULE_PARM(phuv, "i");
MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
MODULE_PARM(pvy, "i");
MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
MODULE_PARM(pvuv, "i");
MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
MODULE_PARM(qhy, "i");
MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
MODULE_PARM(qhuv, "i");
MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
MODULE_PARM(qvy, "i");
MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
MODULE_PARM(qvuv, "i");
MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
MODULE_PARM(lightfreq, "i");
MODULE_PARM_DESC(lightfreq,
  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
MODULE_PARM(bandingfilter, "i");
MODULE_PARM_DESC(bandingfilter,
  "Enable banding filter (to reduce effects of fluorescent lighting)");
MODULE_PARM(clockdiv, "i");
MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
MODULE_PARM(packetsize, "i");
MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
MODULE_PARM(framedrop, "i");
MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
MODULE_PARM(fastset, "i");
MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
MODULE_PARM(force_palette, "i");
MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
MODULE_PARM(backlight, "i");
MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i");
MODULE_PARM_DESC(unit_video,
  "Force use of specific minor number(s). 0 is not allowed.");
MODULE_PARM(remove_zeros, "i");
MODULE_PARM_DESC(remove_zeros,
  "Remove zero-padding from uncompressed incoming data");
MODULE_PARM(mirror, "i");
MODULE_PARM_DESC(mirror, "Reverse image horizontally");
MODULE_PARM(ov518_color, "i");
MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
#if defined(MODULE_LICENSE)	/* Introduced in ~2.4.10 */
MODULE_LICENSE("GPL");
#endif

/**********************************************************************
 * Miscellaneous Globals
 **********************************************************************/

/* 2.2.x compatibility */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
static char kernel_version[] = UTS_RELEASE;
#endif

static struct usb_driver ov511_driver;

static struct ov51x_decomp_ops *ov511_decomp_ops;
static struct ov51x_decomp_ops *ov511_mmx_decomp_ops;
static struct ov51x_decomp_ops *ov518_decomp_ops;
static struct ov51x_decomp_ops *ov518_mmx_decomp_ops;

/* Number of times to retry a failed I2C transaction. Increase this if you
 * are getting "Failed to read sensor ID..." */
static int i2c_detect_tries = 5;

/* MMX support is present in kernel and CPU. Checked upon decomp module load. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
	#if defined(__i386__) || defined(__x86_64__)
	#define ov51x_mmx_available (cpu_has_mmx)
	#else
	#define ov51x_mmx_available (0)
	#endif
#else
	static int ov51x_mmx_available;
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
static struct usb_device_id device_table [] = {
	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
	{ }  /* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, device_table);
#endif

static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;

/**********************************************************************
 * Symbolic Names
 **********************************************************************/

/* Known OV511-based cameras */
static struct symbolic_list camlist[] = {
	{   0, "Generic Camera (no ID)" },
	{   1, "Mustek WCam 3X" },
	{   3, "D-Link DSB-C300" },
	{   4, "Generic OV511/OV7610" },
	{   5, "Puretek PT-6007" },
	{   6, "Lifeview USB Life TV (NTSC)" },
	{  21, "Creative Labs WebCam 3" },
	{  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
	{  36, "Koala-Cam" },
	{  38, "Lifeview USB Life TV (PAL)" },
	{  41, "Samsung Anycam MPC-M10" },
	{  43, "Mtekvision Zeca MV402" },
	{  46, "Suma eON" },
	{  70, "Lifeview USB Life TV (PAL/SECAM)" },
	{ 100, "Lifeview RoboCam" },
	{ 102, "AverMedia InterCam Elite" },
	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
	{ 134, "Ezonics EZCam II" },
	{ 192, "Webeye 2000B" },
	{ 253, "Alpha Vision Tech. AlphaCam SE" },
	{  -1, NULL }
};

/* Video4Linux1 Palettes */
static struct symbolic_list v4l1_plist[] = {
	{ VIDEO_PALETTE_GREY,	"GREY" },
	{ VIDEO_PALETTE_HI240,	"HI240" },
	{ VIDEO_PALETTE_RGB565,	"RGB565" },
	{ VIDEO_PALETTE_RGB24,	"RGB24" },
	{ VIDEO_PALETTE_RGB32,	"RGB32" },
	{ VIDEO_PALETTE_RGB555,	"RGB555" },
	{ VIDEO_PALETTE_YUV422,	"YUV422" },
	{ VIDEO_PALETTE_YUYV,	"YUYV" },
	{ VIDEO_PALETTE_UYVY,	"UYVY" },
	{ VIDEO_PALETTE_YUV420,	"YUV420" },
	{ VIDEO_PALETTE_YUV411,	"YUV411" },
	{ VIDEO_PALETTE_RAW,	"RAW" },
	{ VIDEO_PALETTE_YUV422P,"YUV422P" },
	{ VIDEO_PALETTE_YUV411P,"YUV411P" },
	{ VIDEO_PALETTE_YUV420P,"YUV420P" },
	{ VIDEO_PALETTE_YUV410P,"YUV410P" },
	{ -1, NULL }
};

static struct symbolic_list brglist[] = {
	{ BRG_OV511,		"OV511" },
	{ BRG_OV511PLUS,	"OV511+" },
	{ BRG_OV518,		"OV518" },
	{ BRG_OV518PLUS,	"OV518+" },
	{ -1, NULL }
};

static struct symbolic_list senlist[] = {
	{ SEN_OV76BE,	"OV76BE" },
	{ SEN_OV7610,	"OV7610" },
	{ SEN_OV7620,	"OV7620" },
	{ SEN_OV7620AE,	"OV7620AE" },
	{ SEN_OV6620,	"OV6620" },
	{ SEN_OV6630,	"OV6630" },
	{ SEN_OV6630AE,	"OV6630AE" },
	{ SEN_OV6630AF,	"OV6630AF" },
	{ SEN_OV8600,	"OV8600" },
	{ SEN_KS0127,	"KS0127" },
	{ SEN_KS0127B,	"KS0127B" },
	{ SEN_SAA7111A,	"SAA7111A" },
	{ -1, NULL }
};

/* URB error codes: */
static struct symbolic_list urb_errlist[] = {
	{ -ENOSR,	"Buffer error (overrun)" },
	{ -EPIPE,	"Stalled (device not responding)" },
	{ -EOVERFLOW,	"Babble (bad cable?)" },
	{ -EPROTO,	"Bit-stuff error (bad cable?)" },
	{ -EILSEQ,	"CRC/Timeout" },
	{ -ETIMEDOUT,	"NAK (device does not respond)" },
	{ -1, NULL }
};

/**********************************************************************
 * Prototypes
 **********************************************************************/

static void ov51x_clear_snapshot(struct usb_ov511 *);
static inline int sensor_get_picture(struct usb_ov511 *,
				     struct video_picture *);
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
			       unsigned long);
static int ov51x_check_snapshot(struct usb_ov511 *);
#endif

/**********************************************************************
 * Memory management
 **********************************************************************/

#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 18)

/* Here we want the physical address of the memory.
 * This is used when initializing the contents of the area.
 */
static inline unsigned long
kvirt_to_pa(unsigned long adr)
{
	unsigned long kva, ret;

	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
	ret = __pa(kva);
	return ret;
}

static void *
rvmalloc(unsigned long size)
{
	void *mem;
	unsigned long adr;

	size = PAGE_ALIGN(size);
	mem = vmalloc_32(size);
	if (!mem)
		return NULL;

	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
	adr = (unsigned long) mem;
	while (size > 0) {
		mem_map_reserve(vmalloc_to_page((void *)adr));
		adr += PAGE_SIZE;
		size -= PAGE_SIZE;
	}

	return mem;
}

static void
rvfree(void *mem, unsigned long size)
{
	unsigned long adr;

	if (!mem)
		return;

	adr = (unsigned long) mem;
	while ((long) size > 0) {
		mem_map_unreserve(vmalloc_to_page((void *)adr));
		adr += PAGE_SIZE;
		size -= PAGE_SIZE;
	}
	vfree(mem);
}

#else	/* if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18) */

/* Given PGD from the address space's page table, return the kernel
 * virtual mapping of the physical memory mapped at ADR.
 */
static inline unsigned long
uvirt_to_kva(pgd_t *pgd, unsigned long adr)
{
	unsigned long ret = 0UL;
	pmd_t *pmd;
	pte_t *ptep, pte;

	if (!pgd_none(*pgd)) {
		pmd = pmd_offset(pgd, adr);
		if (!pmd_none(*pmd)) {
			ptep = pte_offset(pmd, adr);
			pte = *ptep;
			if (pte_present(pte)) {
				ret = (unsigned long)
				      page_address(pte_page(pte));
				ret |= (adr & (PAGE_SIZE - 1));
			}
		}
	}

	return ret;
}

/* Here we want the physical address of the memory.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -