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

📄 qc-vv6410.c

📁 在Linux下用于webeye的摄像头的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Start of file *//* {{{ [fold] Comments *//* * qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam * * vv6410.c - VV6410 Sensor Implementation * * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *//* }}} */#ifdef NOKERNEL#include "quickcam.h"#else#include <linux/quickcam.h>#endif#ifndef QCEGA_MODE#define QCEGA_MODE 0		/* If the driver doesn't work for you, try changing this to "1" */#endif/* LSB bit of I2C address signifies write (0) or read (1) *//* I2C Address */#define VV6410_ADDR		(0x10<<1)/* {{{ [fold] I2C Registers *//* Status registers */#define VV6410_DEVICEH		0x00	/* Chip identification number including revision indicator */#define VV6410_DEVICEL		0x01#define VV6410_STATUS0		0x02	/* User can determine whether timed I2C data has been consumed by interrogating flag states */#define VV6410_LINECOUNTH	0x03	/* Current line counter value */#define VV6410_LINECOUNTL	0x04#define VV6410_XENDH		0x05	/* End x coordinate of image size */#define VV6410_XENDL		0x06#define VV6410_YENDH		0x07	/* End y coordinate of image size */#define VV6410_YENDL		0x08#define VV6410_DARKAVGH		0x09	/* This is the average pixel value returned from the dark line offset cancellation algorithm */#define VV6410_DARKAVGL		0x0A#define VV6410_BLACKAVGH	0x0B	/* This is the average pixel value returned from the black line offset cancellation algorithm  */#define VV6410_BLACKAVGL	0x0C#define VV6410_STATUS1		0x0D	/* Flags to indicate whether the x or y image coordinates have been clipped *//* Setup registers */#define VV6410_SETUP0		0x10	/* Low-power/sleep modes & video timing */#define VV6410_SETUP1		0x11	/* Various parameters */#define VV6410_SYNCVALUE	0x12	/* Contains pixel counter reset value used by external sync */#define VV6410_FGMODES		0x14	/* Frame grabbing modes (FST, LST and QCK) */#define VV6410_PINMAPPING	0x15	/* FST and QCK mapping modes. */#define VV6410_DATAFORMAT	0x16	/* Data resolution */#define VV6410_OPFORMAT		0x17	/* Output coding formats */#define VV6410_MODESELECT	0x18	/* Various mode select bits *//* Exposure registers */#define VV6410_FINEH		0x20	/* Fine exposure. */#define VV6410_FINEL		0x21#define VV6410_COARSEH		0x22	/* Coarse exposure */#define VV6410_COARSEL		0x23#define VV6410_ANALOGGAIN	0x24	/* Analog gain setting */#define VV6410_CLKDIV		0x25	/* Clock division */#define VV6410_DARKOFFSETH	0x2C	/* Dark line offset cancellation value */#define VV6410_DARKOFFSETL	0x2D#define VV6410_DARKOFFSETSETUP	0x2E	/* Dark line offset cancellation enable *//* Colour registers (none on this camera!) *//* Video timing registers */#define VV6410_LINELENGTHH	0x52	/* Line Length (Pixel Clocks) */#define VV6410_LINELENGTHL	0x53#define VV6410_XOFFSETH		0x57	/* X-co-ordinate of top left corner of region of interest (x-offset) */#define VV6410_XOFFSETL		0x58#define VV6410_YOFFSETH		0x59	/* Y-co-ordinate of top left corner of region of interest (y-offset) */#define VV6410_YOFFSETL		0x5A#define VV6410_FIELDLENGTHH	0x61	/* Field length (Lines) */#define VV6410_FIELDLENGTHL	0x62/* Text overlay registers (none on this camera!) *//* I2C autoload registers (none on this camera!) *//* System registers */#define VV6410_BLACKOFFSETH	0x70	/* Black offset cancellation default value */#define VV6410_BLACKOFFSETL	0x71#define VV6410_BLACKOFFSETSETUP	0x72	/* Black offset cancellation setup */#define VV6410_CR0		0x75	/* Analog Control Register 0 */#define VV6410_CR1		0x76	/* Analog Control Register 1 */#define VV6410_AS0		0x77	/* ADC Setup Register */#define VV6410_AT0		0x78	/* Analog Test Register */#define VV6410_AT1		0x79	/* Audio Amplifier Setup Register *//* }}} */#define I2C_SET_CHECK(reg,val)	if ((r = qc_i2c_set(qc,(reg),(val)))<0) goto fail#define STV_SET_CHECK(reg,val)	if ((r = qc_stv_set(qc,(reg),(val)))<0) goto fail#define STV_SETW_CHECK(reg,val)	if ((r = qc_stv_setw(qc,(reg),(val)))<0) goto fail#define IS_850(qc)		(GET_PRODUCTID(qc)==0x850)	/* Is it QuickCam Web/Legocam? */#if QCEGA_MODE#warning "Using old compatible code (QCEGA_MODE=1)"#warning "If this works but otherwise it doesn't work, let me know!"static int mode = 0;#define VV6410_CONTROL 		0x10	// Setup0#define VV6410_GAIN  		0x24/* {{{ [fold] vv6410_set_window() */static int vv6410_set_window(struct quickcam *qc, int x, int y,int width, int height){	int r = 0;	// x offset        x = MAX(1,x);	I2C_SET_CHECK(0x57,x >> 8);	I2C_SET_CHECK(0x58,x & 0xff);	// y offset        y = MAX(1,y);	I2C_SET_CHECK(0x59,y >> 8);	I2C_SET_CHECK(0x5a,y & 0xff);        // Set the real        if (qc->sensor_data.subsample) {            qc->sensor_data.width=180;            qc->sensor_data.height=148;        } else {            qc->sensor_data.width=356;            qc->sensor_data.height=292;        }	// line length        if (qc->sensor_data.subsample) {            if (IS_850(qc))                width=250;            else                width=360; /* 180 * 2 (CLK-DIV is 2) */        }        else {          if (IS_850(qc))                width=416;          else                width=712; /* 356 * 2 */	}	I2C_SET_CHECK(0x52, width >> 8);	I2C_SET_CHECK(0x53, width & 0xff);	// field length (num lines)        if (qc->sensor_data.subsample)          height=160; /* nearest of 148 = 10 * 16 */        else          height=320; // 304; /* nearest of 292 = 19 * 16 */ 	I2C_SET_CHECK(0x61,height >> 8);	I2C_SET_CHECK(0x62,height & 0xff);        // usb_quickcam_i2c_add(&i2cbuff,0x25,0x02);	if ((r = qc_i2c_wait(qc))<0) goto fail;        return 0;fail:	return -ENAMETOOLONG;	//some silly code just for testing}/* }}} */#endif/* {{{ [fold] vv6410_set_size: Set window size */static int vv6410_set_size(struct quickcam *qc, unsigned int width, unsigned int height){	struct qc_sensor_data *sd = &qc->sensor_data;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_set_size(qc=%p,width=%i,height=%i)",qc,width,height);	/* VV6410 appears to always give fixed 356*292 pixels */	sd->width = sd->maxwidth;	sd->height = sd->maxheight;	return 0;}/* }}} *//* {{{ [fold] vv6410_start: Start grabbing */static int vv6410_start(struct quickcam *qc){	struct qc_sensor_data *sd = &qc->sensor_data;	int r;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_start(qc=%p)",qc);	if (PARANOID && !qc)  { PDEBUG("qc==NULL"); return -EINVAL; }	I2C_SET_CHECK(VV6410_SETUP0, sd->subsample ? (BIT(7)|BIT(6)) : 0x00);	if (IS_850(qc)) qc_stv_set(qc, 0x1445, 1);		/* Turn on LED */	r = qc_i2c_wait(qc);fail:	return r;}/* }}} *//* {{{ [fold] vv6410_stop: Stop grabbing */static int vv6410_stop(struct quickcam *qc){	static const int low_power_mode = 0; //1;	static const int sleep_mode     = 1;	struct qc_sensor_data *sd = &qc->sensor_data;	unsigned char cmd;	int r;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_stop(qc=%p)",qc);	if (IS_850(qc)) qc_stv_set(qc, 0x1445, 0);		/* Turn off LED */	cmd = (sleep_mode << 1) | low_power_mode;	if (sd->subsample) cmd |= BIT(7)|BIT(6);		/* sub-sampled QCIF mode */	I2C_SET_CHECK(VV6410_SETUP0, cmd);	r = qc_i2c_wait(qc);fail:	return r;}/* }}} */#if COMPRESSstruct stv_init {	const u8 *data;	/* If NULL, only single value to write, stored in len */	u16 start;	u8 len;};#endif/* {{{ [fold] vv6410_init: Initialise parameters for vv6410 sensor. *//* Just try to send the same commands as Windoze QuickCam soft */static int vv6410_init(struct quickcam *qc){	struct qc_sensor_data *sd = &qc->sensor_data;	int r;#if COMPRESS	if (IS_850(qc)) {/* {{{ [fold] Initialization with compression support *//* {{{ [fold] [fold] stv_init[] */	static const u8 x0540[] = {			/* 0x0540 - 0x0551 */		0x97,0x0B,0x4C,0xFC,0x36,0x00,0x75,0x00,0x59,0x02,0x32,0x01,0x56,0xFD,0xEE,0xFF,		0xB8,0x05 };	static const u8 x0560[] = {			/* 0x0560 - 0x0563 */		0x40,0xFF,0xBF,0xBF };	static const u8 x1500[] = {			/* 0x1500 - 0x150F */		0x0B,0xA7,0xB7,0x00,0x00,0x00,0x14,0x14,0x14,0x14,0x2B,0x02,0x2B,0x02,0x2B,0x02 };	static const u8 x1520[] = {			/* 0x1520 - 0x152A */		0x05,0x14,0x0F,0x0F,0x98,0x98,0x98,0x98,0x2D,0x00,0x01 };	static const u8 x1530[] = {			/* 0x1530 - 0x153B */		0x08,0x02,0x00,0x00,0x02,0x00,0x02,0x00,0x60,0x01,0x20,0x01 };	static const u8 x1552[] = {			/* 0x1552 - 0x1558 */		0x72,0x90,0x00,0xB0,0xF0,0x77,0x72 };	static const u8 x1564[] = {			/* 0x1564 - 0x1567 */		0x00,0xFF,0x0C,0x00 };	static const u8 x1580[] = {			/* 0x1580 - 0x158F */		0x02,0x40,0x01,0xF0,0x00,0xD1,0x01,0xAC,0x01,0x07,0x00,0x00,0x00,0x00,0x00,0x00 };	static const u8 x1590[] = {			/* 0x1590 - 0x15A5 */		0xA8,0x05,0x64,0x07,0x0F,0x03,0xD8,0x07,0xA6,0x06,0x71,0x04,0x8F,0x01,0xFF,0xFB,		0xEC,0xE6,0xE0,0xD9,0xC4,0xB8 };	static const u8 x15C1[] = {			/* 0x15C1 - 0x15C2 */		0x4B, 0x02 };			/* Output word 0x024B=587 (ISO size) */	static const struct stv_init stv_init[] = {		{ NULL,  0x1620, 0x80 },	/* This reg is written twice. Some kind of reset? */		{ NULL,  0x1620, 0x00 },		{ x0540, 0x0540, SIZE(x0540) },		{ x0560, 0x0560, SIZE(x0560) },		{ NULL,  0x1423, 0x04 },		{ NULL,  0x1440, 0x00 },		{ NULL,  0x1443, 0x00 },		{ NULL,  0x1445, 0x01 },		{ x1500, 0x1500, SIZE(x1500) },		{ x1520, 0x1520, SIZE(x1520) },		{ x1530, 0x1530, SIZE(x1530) },		{ x1552, 0x1552, SIZE(x1552) },		{ x1564, 0x1564, SIZE(x1564) },		{ x1580, 0x1580, SIZE(x1580) },		{ x1590, 0x1590, SIZE(x1590) },		{ x15C1, 0x15C1, SIZE(x15C1) },		{ NULL,  0x15C3, 0x00 },		{ NULL,  0x15C9, 0x01 },		{ NULL,  0x1704, 0x00 },	};/* }}} *//* {{{ [fold] vv_init[][2] */	static const u8 vv_init[][2] = {		/* Setup registers */		{ VV6410_SETUP0,	BIT(2) },	/* Soft reset */		{ VV6410_SETUP0,	BIT(1)|BIT(0) },	/* 25 fps PAL (30 fps NTSC doesn't work!), sleep mode */		{ VV6410_SETUP1,	BIT(6) },	/* Use unsuffled read-out mode */		{ VV6410_FGMODES,	BIT(6)|BIT(4)|BIT(2)|BIT(0) },	/* All modes to 1 */		{ VV6410_PINMAPPING,	0x00 },		{ VV6410_DATAFORMAT,	BIT(7)|BIT(0) },	/* Pre-clock generator divide off */		{ VV6410_OPFORMAT,	BIT(3)|BIT(4) },		/* Exposure registers */		{ VV6410_FINEH,		320 >> 8 },		/* Initial exposure */		{ VV6410_FINEL,		320 & 0xFF },		{ VV6410_COARSEH,	192 >> 8 },		{ VV6410_COARSEL,	192 & 0xFF },		{ VV6410_ANALOGGAIN,	0xF0 | 11 },		/* Gain to 11 */		{ VV6410_CLKDIV,	0x01 },			/* Pixel clock divisor 2 */		/* Video timing registers */		{ VV6410_LINELENGTHH,	(416-1) >> 8 },		/* Set line length (columns) to 417 */		{ VV6410_LINELENGTHL,	(416-1) & 0xFF },		{ VV6410_FIELDLENGTHH,	(320-1) >> 8 },		/* Set field length (rows) to 320 */		{ VV6410_FIELDLENGTHL,	(320-1) & 0xFF },		/* System registers */		{ VV6410_AS0,		BIT(6)|BIT(4)|BIT(3)|BIT(2)|BIT(1) },	/* Enable voltage doubler */		{ VV6410_AT0,		0x00 },		{ VV6410_AT1,		BIT(4)|BIT(0) },	/* Power up audio, differential */	};/* }}} */	unsigned int cols = 416;	unsigned int rows = 320;	unsigned int x = 1;	unsigned int y = 1;	int i,j;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_init(qc=%p)",qc);	if (PARANOID && !qc) { PDEBUG("qc==NULL"); return -EINVAL; }	sd->width  = 320;	/* Default to compressed mode */	sd->height = 240;	for (i=0; i<SIZE(stv_init); i++) {		if (stv_init[i].data==NULL) {			STV_SET_CHECK(stv_init[i].start, stv_init[i].len);		} else {			for (j=0; j<stv_init[i].len; j++) {				STV_SET_CHECK(stv_init[i].start+j, stv_init[i].data[j]);

⌨️ 快捷键说明

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