📄 qc-vv6450.c
字号:
/* * qce-ga, linux V4L driver for the Quickcam Express and Dexxa Quickcam * * vv6450.c - Sensor Implementation for Quickcam Messenger??? * The sensor is NOT called 6450, I just copied the vv6410.c * to have something to work with. * * 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/* LSB bit of I2C address signifies write (0) or read (1) *//* I2C Registers *//* Status registers */#define VV6450_DEVICEH 0xE00A /* Chip identification number including revision indicator */#define VV6450_STATUS0 0x02 /* User can determine whether timed I2C data has been consumed by interrogating flag states */#define VV6450_LINECOUNTH 0x03 /* Current line counter value */#define VV6450_LINECOUNTL 0x04#define VV6450_XENDH 0x05 /* End x coordinate of image size */#define VV6450_XENDL 0x06#define VV6450_YENDH 0x07 /* End y coordinate of image size */#define VV6450_YENDL 0x08#define VV6450_DARKAVGH 0x09 /* This is the average pixel value returned from the dark line offset cancellation algorithm */#define VV6450_DARKAVGL 0x0A#define VV6450_BLACKAVGH 0x0B /* This is the average pixel value returned from the black line offset cancellation algorithm */#define VV6450_BLACKAVGL 0x0C#define VV6450_STATUS1 0x0D /* Flags to indicate whether the x or y image coordinates have been clipped *//* Setup registers */#define VV6450_SETUP0 0x10 /* Low-power/sleep modes & video timing */#define VV6450_SETUP1 0x11 /* Various parameters */#define VV6450_SYNCVALUE 0x12 /* Contains pixel counter reset value used by external sync */#define VV6450_FGMODES 0x14 /* Frame grabbing modes (FST, LST and QCK) */#define VV6450_PINMAPPING 0x15 /* FST and QCK mapping modes. */#define VV6450_DATAFORMAT 0x16 /* Data resolution */#define VV6450_OPFORMAT 0x17 /* Output coding formats */#define VV6450_MODESELECT 0x18 /* Various mode select bits *//* Exposure registers */#define VV6450_FINEH 0x20 /* Fine exposure. */#define VV6450_FINEL 0x21#define VV6450_COARSEH 0x22 /* Coarse exposure */#define VV6450_COARSEL 0x23#define VV6450_ANALOGGAIN 0x24 /* Analog gain setting */#define VV6450_CLKDIV 0x25 /* Clock division */#define VV6450_DARKOFFSETH 0x2C /* Dark line offset cancellation value */#define VV6450_DARKOFFSETL 0x2D#define VV6450_DARKOFFSETSETUP 0x2E /* Dark line offset cancellation enable *//* Colour registers (none on this camera!) *//* Video timing registers */#define VV6450_LINELENGTHH 0x52 /* Line Length (Pixel Clocks) */#define VV6450_LINELENGTHL 0x53#define VV6450_XOFFSETH 0x57 /* X-co-ordinate of top left corner of region of interest (x-offset) */#define VV6450_XOFFSETL 0x58#define VV6450_YOFFSETH 0x59 /* Y-co-ordinate of top left corner of region of interest (y-offset) */#define VV6450_YOFFSETL 0x5A#define VV6450_FIELDLENGTHH 0x61 /* Field length (Lines) */#define VV6450_FIELDLENGTHL 0x62/* Text overlay registers (none on this camera!) *//* I2C autoload registers (none on this camera!) *//* System registers */#define VV6450_BLACKOFFSETH 0x70 /* Black offset cancellation default value */#define VV6450_BLACKOFFSETL 0x71#define VV6450_BLACKOFFSETSETUP 0x72 /* Black offset cancellation setup */#define VV6450_CR0 0x75 /* Analog Control Register 0 */#define VV6450_CR1 0x76 /* Analog Control Register 1 */#define VV6450_AS0 0x77 /* ADC Setup Register */#define VV6450_AT0 0x78 /* Analog Test Register */#define VV6450_AT1 0x79 /* Audio Amplifier Setup Register *///#define I2C_SET_CHECK(reg,val) if ((r = qc_i2c_set(qc,(reg),(val)))<0) goto fail#define I2C_SET_CHECK(reg,val) do {} while(0)#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/** * Set window size */static int vv6450_set_size(struct quickcam *qc, unsigned int width, unsigned int height){ int r = 0; struct qc_sensor_data *sd = &qc->sensor_data; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6450_set_size(quickcam=%p,width=%i,height=%i)",qc,width,height); if ( (width <= 162) && (height <= 124) ) { sd->width = 162; sd->height = 124; STV_SET_CHECK(0x1505, 0x0f); if(r) goto fail; } else#ifndef MIN#define MIN(a, b) ((a) < (b) ? (a) : (b))#endif if ( (width <= 176) && (height <= 144) ) { /* exception for small QCIF even if not good fit */ sd->width = 162; sd->height = 124; qc->vwin.width = MIN(sd->width, width); qc->vwin.height = MIN(sd->height, height); STV_SET_CHECK(0x1505, 0x0f); if(r) goto fail; //return 0; } else if ( (width <= 162) && (height <= 248) ) { sd->width = 162; sd->height = 248; STV_SET_CHECK(0x1505, 0x08); if(r) goto fail; } else if ( (width <= 324) && (height <= 124) ) { sd->width = 324; sd->height = 124; STV_SET_CHECK(0x1505, 0x04); if(r) goto fail; } else if ( (width <= 324) && (height <= 248) ) { sd->width = 324; sd->height = 248; STV_SET_CHECK(0x1505, 0x02); if(r) goto fail; } else if ( (width <= 352) && (height <= 288) ) { /* exception for CIF even if not good fit */ sd->width = 324; sd->height = 248; qc->vwin.width = MIN(sd->width, width); qc->vwin.height = MIN(sd->height, height); STV_SET_CHECK(0x1505, 0x02); if(r) goto fail; //return 0; } else#ifdef TRY_HIGHRES if ( (width <= 648) && (height <= 496) ) { // this doesn't work yet sd->width = 648; sd->height = 496; STV_SET_CHECK(0x1505, 0x01); if(r) goto fail; } else#endif {#if 1 PDEBUG("Unknown resolution %dx%d, set 324x248", width, height); sd->width = 324; sd->height = 248; qc->vwin.width = sd->width; qc->vwin.height = sd->height; STV_SET_CHECK(0x1505, 0x02); if(r) goto fail;#endif goto fail; }#if 0 qc->vwin.width = width; qc->vwin.height = height; qc->vwin.width = sd->width; qc->vwin.height = sd->height;#endif qc->vwin.width = MIN(sd->width, width); qc->vwin.height = MIN(sd->height, height); PDEBUG("set sensor=%dx%d vwin=%dx%d", sd->width, sd->height, qc->vwin.width, qc->vwin.height); return 0;fail: return -1;}/* start grabbing */static int vv6450_start(struct quickcam *qc){ int r = 0; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6450_start(quickcam=%p)",qc); if (PARANOID && !qc) { PDEBUG("qc==NULL"); return -EINVAL; } r = qc_i2c_wait(qc); STV_SET_CHECK(STV_ISO_ENABLE, 0x01); return 0;fail: //PDEBUG("Error start"); return r;}/* stop grabbing */static int vv6450_stop(struct quickcam *qc){ static const int low_power_mode = 1; static const int sleep_mode = 1; struct qc_sensor_data *sd = &qc->sensor_data; unsigned char cmd; int r = 0; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6450_stop(quickcam=%p)",qc); cmd = (sleep_mode << 1) | low_power_mode; if (sd->subsample) cmd |= BIT(7)|BIT(6); /* sub-sampled QCIF mode */ r = qc_i2c_wait(qc); STV_SET_CHECK(STV_ISO_ENABLE, 0x00); return 0;fail: //PDEBUG("Error stop"); return r;}struct stv_init { const u8 *data; /* If NULL, only single value to write, stored in len */ u16 start; u16 len;};/* * initialise parameters for vv6450 sensor. * Just try to send the same commands as Windoze Quickcam soft. */static int vv6450_init(struct quickcam *qc){ struct qc_sensor_data *sd = &qc->sensor_data; int r = 0; static const struct stv_init stv_init[] = {/* LOGTAG */ { NULL, STV_ISO_ENABLE, 0x00 }, /* disable capture *//* LOGTAG */ { NULL, 0x1436, 0x00 },/* LOGTAG */ { NULL, 0x1432, 0x03 }, /* 0x00-0x1F contrast ? *//* LOGTAG */ { NULL, 0x143a, 0xF9 }, /* 0x00-0x0F - gain *//* LOGTAG */ { NULL, 0x0509, 0x38 }, /* R *//* LOGTAG */ { NULL, 0x050a, 0x38 }, /* G *//* LOGTAG */ { NULL, 0x050b, 0x38 }, /* B *//* LOGTAG */ { NULL, 0x050c, 0x2A },/* LOGTAG */ { NULL, 0x050d, 0x01 },/* LOGTAG */ { NULL, 0x1431, 0x00 }, /* 0x00-0x07 ??? *//* LOGTAG */ { NULL, 0x1433, 0x34 }, /* 160x120 */ /* 0x00-0x01 night filter *//* LOGTAG */ { NULL, 0x1438, 0x18 }, /* 640x480 */// 18 bayes// 10 compressed?/* LOGTAG */ { NULL, 0x1439, 0x00 },// antiflimmer?? 0xa2 ger perfekt bild mot monitor/* LOGTAG */ { NULL, 0x143b, 0x05 },/* LOGTAG */ { NULL, 0x143c, 0x00 }, /* 0x00-0x01 - ??? */// shutter time 0x0000-0x03FF// low value give good picures on moving objects (but requires much light)// high value gives good picures in darkness (but tends to be overexposed)/* LOGTAG */ { NULL, 0x143e, 0x01 },/* LOGTAG */ { NULL, 0x143d, 0x00 },/* LOGTAG */ { NULL, 0x1442, 0xe2 },// write: 1x1x xxxx// read: 1x1x xxxx// bit 5 == button pressed and hold if 0// write 0xe2,0xea// 0x144a// 0x00 init// bit 7 == button has been pressed, but not handled// interrupt//if(urb->iso_frame_desc[i].status == 0x80) {//if(urb->iso_frame_desc[i].status == 0x88) {/* LOGTAG */ { NULL, 0x1500, 0xd0 },/* LOGTAG */ { NULL, 0x1500, 0xd0 },/* LOGTAG */ { NULL, 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? *//* LOGTAG */ { NULL, 0x1501, 0xaf },// high val-> ljus area blir morkare.// low val -> ljus area blir ljusare./* LOGTAG */ { NULL, 0x1502, 0xc2 },// high val-> ljus area blir morkare.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -