?? ov511.c
字號:
/* * OmniVision OV511 Camera-to-USB Bridge Driver * * Copyright (c) 1999-2003 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: 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>#include <linux/module.h>#include <linux/init.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/ctype.h>#include <linux/pagemap.h>#include <asm/semaphore.h>#include <asm/processor.h>#include <linux/mm.h>#include <linux/device.h>#if defined (__i386__) #include <asm/cpufeature.h>#endif#include "ov511.h"/* * Version Information */#define DRIVER_VERSION "v1.64 for Linux 2.5"#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/* Pixel count * bytes per YUV420 pixel (1.5) */#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)#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;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;static int clockdiv = -1;static int packetsize = -1;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");MODULE_PARM(cams, "i");MODULE_PARM_DESC(cams, "Number of simultaneous cameras");MODULE_PARM(compress, "i");MODULE_PARM_DESC(compress, "Turn on compression");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);MODULE_LICENSE("GPL");/********************************************************************** * Miscellaneous Globals **********************************************************************/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 defined(__i386__) || defined(__x86_64__)#define ov51x_mmx_available (cpu_has_mmx)#else#define ov51x_mmx_available (0)#endifstatic 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);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 }};/********************************************************************** * Memory management **********************************************************************//* Here we want the physical address of the memory. * This is used when initializing the contents of the area. */static inline unsigned longkvirt_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) { SetPageReserved(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } return mem;}static voidrvfree(void *mem, unsigned long size){ unsigned long adr; if (!mem) return; adr = (unsigned long) mem; while ((long) size > 0) { ClearPageReserved(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } vfree(mem);}/********************************************************************** * * Register I/O * **********************************************************************//* Write an OV51x register */static intreg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value){ int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); down(&ov->cbuf_lock); ov->cbuf[0] = value; rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, &ov->cbuf[0], 1, HZ); up(&ov->cbuf_lock); if (rc < 0) err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); return rc;}/* Read from an OV51x register *//* returns: negative is error, pos or zero is data */static intreg_r(struct usb_ov511 *ov, unsigned char reg){ int rc; down(&ov->cbuf_lock); rc = usb_control_msg(ov->dev, usb_rcvctrlpipe(ov->dev, 0), (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, &ov->cbuf[0], 1, HZ); if (rc < 0) { err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); } else { rc = ov->cbuf[0]; PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); } up(&ov->cbuf_lock); return rc;}/* * Writes bits at positions specified by mask to an OV51x reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */static intreg_w_mask(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask){ int ret; unsigned char oldval, newval; ret = reg_r(ov, reg); if (ret < 0) return ret; oldval = (unsigned char) ret; oldval &= (~mask); /* Clear the masked bits */ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ return (reg_w(ov, reg, newval));}/* * Writes multiple (n) byte value to a single register. Only valid with certain * registers (0x30 and 0xc4 - 0xce). */static intov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n){ int rc; PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); down(&ov->cbuf_lock); *((u32 *)ov->cbuf) = __cpu_to_le32(val); rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), 1 /* REG_IO */, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, ov->cbuf, n, HZ); up(&ov->cbuf_lock); if (rc < 0) err("reg write multiple: error %d: %s", rc, symbolic(urb_errlist, rc)); return rc;}static intov511_upload_quan_tables(struct usb_ov511 *ov){ unsigned char *pYTable = yQuanTable511; unsigned char *pUVTable = uvQuanTable511; unsigned char val0, val1; int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { if (ENABLE_Y_QUANTABLE) { val0 = *pYTable++; val1 = *pYTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } if (ENABLE_UV_QUANTABLE) { val0 = *pUVTable++; val1 = *pUVTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } reg++; } return 0;}/* OV518 quantization tables are 8x4 (instead of 8x8) */static intov518_upload_quan_tables(struct usb_ov511 *ov){ unsigned char *pYTable = yQuanTable518; unsigned char *pUVTable = uvQuanTable518; unsigned char val0, val1; int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { if (ENABLE_Y_QUANTABLE) { val0 = *pYTable++; val1 = *pYTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } if (ENABLE_UV_QUANTABLE) { val0 = *pUVTable++; val1 = *pUVTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -