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

📄 ov511.c

📁 EVC 写的 wince usb camera 代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	default:		err("Invalid sensor");		return -EINVAL;	}	/******** Palette-specific regs ********/	if (mode == VIDEO_PALETTE_GREY) {		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {			/* these aren't valid on the OV6620/OV7620/6630? */			i2c_w_mask(ov, 0x0e, 0x40, 0x40);		}		if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518		    && ov518_color) {			i2c_w_mask(ov, 0x12, 0x00, 0x10);			i2c_w_mask(ov, 0x13, 0x00, 0x20);		} else {			i2c_w_mask(ov, 0x13, 0x20, 0x20);		}	} else {		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {			/* not valid on the OV6620/OV7620/6630? */			i2c_w_mask(ov, 0x0e, 0x00, 0x40);		}		/* The OV518 needs special treatment. Although both the OV518		 * and the OV6630 support a 16-bit video bus, only the 8 bit Y		 * bus is actually used. The UV bus is tied to ground.		 * Therefore, the OV6630 needs to be in 8-bit multiplexed		 * output mode */		if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518		    && ov518_color) {			i2c_w_mask(ov, 0x12, 0x10, 0x10);			i2c_w_mask(ov, 0x13, 0x20, 0x20);		} else {			i2c_w_mask(ov, 0x13, 0x00, 0x20);		}	}	/******** Clock programming ********/	/* The OV6620 needs special handling. This prevents the 	 * severe banding that normally occurs */	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)	{		/* Clock down */		i2c_w(ov, 0x2a, 0x04);		if (ov->compress) {//			clock = 0;    /* This ensures the highest frame rate */			clock = 3;		} else if (clockdiv == -1) {   /* If user didn't override it */			clock = 3;    /* Gives better exposure time */		} else {			clock = clockdiv;		}		PDEBUG(4, "Setting clock divisor to %d", clock);		i2c_w(ov, 0x11, clock);		i2c_w(ov, 0x2a, 0x84);		/* This next setting is critical. It seems to improve		 * the gain or the contrast. The "reserved" bits seem		 * to have some effect in this case. */		i2c_w(ov, 0x2d, 0x85);	}	else	{		if (ov->compress) {			clock = 1;    /* This ensures the highest frame rate */		} else if (clockdiv == -1) {   /* If user didn't override it */			/* Calculate and set the clock divisor */			clock = ((sub_flag ? ov->subw * ov->subh				  : width * height)				 * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)				 / 66000;		} else {			clock = clockdiv;		}		PDEBUG(4, "Setting clock divisor to %d", clock);		i2c_w(ov, 0x11, clock);	}	/******** Special Features ********/	if (framedrop >= 0)		i2c_w(ov, 0x16, framedrop);	/* Test Pattern */	i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);	/* Enable auto white balance */	i2c_w_mask(ov, 0x12, 0x04, 0x04);	// This will go away as soon as ov51x_mode_init_sensor_regs()	// is fully tested.	/* 7620/6620/6630? don't have register 0x35, so play it safe */	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {		if (width == 640 && height == 480)			i2c_w(ov, 0x35, 0x9e);		else			i2c_w(ov, 0x35, 0x1e);	}	return 0;}static intset_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,		     int sub_flag){	int ret;	int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; 	int hoffset, voffset, hwscale = 0, vwscale = 0;	/* The different sensor ICs handle setting up of window differently.	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */	switch (ov->sensor) {	case SEN_OV7610:	case SEN_OV76BE:		hwsbase = 0x38;		hwebase = 0x3a;		vwsbase = vwebase = 0x05;		break;	case SEN_OV6620:	case SEN_OV6630:		hwsbase = 0x38;		hwebase = 0x3a;		vwsbase = 0x05;		vwebase = 0x06;		break;	case SEN_OV7620:		hwsbase = 0x2f;		/* From 7620.SET (spec is wrong) */		hwebase = 0x2f;		vwsbase = vwebase = 0x05;		break;	default:		err("Invalid sensor");		return -EINVAL;	}	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {		/* Note: OV518(+) does downsample on its own) */		if ((width > 176 && height > 144)		    || ov->bclass == BCL_OV518) {  /* CIF */			ret = mode_init_ov_sensor_regs(ov, width, height,				mode, sub_flag, 0);			if (ret < 0)				return ret;			hwscale = 1;			vwscale = 1;  /* The datasheet says 0; it's wrong */			hwsize = 352;			vwsize = 288;		} else if (width > 176 || height > 144) {			err("Illegal dimensions");			return -EINVAL;		} else {			    /* QCIF */			ret = mode_init_ov_sensor_regs(ov, width, height,				mode, sub_flag, 1);			if (ret < 0)				return ret;			hwsize = 176;			vwsize = 144;		}	} else {		if (width > 320 && height > 240) {  /* VGA */			ret = mode_init_ov_sensor_regs(ov, width, height,				mode, sub_flag, 0);			if (ret < 0)				return ret;			hwscale = 2;			vwscale = 1;			hwsize = 640;			vwsize = 480;		} else if (width > 320 || height > 240) {			err("Illegal dimensions");			return -EINVAL;		} else {			    /* QVGA */			ret = mode_init_ov_sensor_regs(ov, width, height,				mode, sub_flag, 1);			if (ret < 0)				return ret;			hwscale = 1;			hwsize = 320;			vwsize = 240;		}	}	/* Center the window */	hoffset = ((hwsize - width) / 2) >> hwscale;	voffset = ((vwsize - height) / 2) >> vwscale;	/* FIXME! - This needs to be changed to support 160x120 and 6620!!! */	if (sub_flag) {		i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));		i2c_w(ov, 0x18,	hwebase+((ov->subx+ov->subw)>>hwscale));		i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));		i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));	} else {		i2c_w(ov, 0x17, hwsbase + hoffset);		i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));		i2c_w(ov, 0x19, vwsbase + voffset);		i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));	}#ifdef OV511_DEBUG	if (dump_sensor)		dump_i2c_regs(ov);#endif	return 0;}/* Set up the OV511/OV511+ with the given image parameters. * * Do not put any sensor-specific code in here (including I2C I/O functions) */static intov511_mode_init_regs(struct usb_ov511 *ov,		     int width, int height, int mode, int sub_flag){	int hsegs, vsegs;	if (sub_flag) {		width = ov->subw;		height = ov->subh;	}	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",	       width, height, mode, sub_flag);	// FIXME: This should be moved to a 7111a-specific function once	// subcapture is dealt with properly	if (ov->sensor == SEN_SAA7111A) {		if (width == 320 && height == 240) {			/* No need to do anything special */		} else if (width == 640 && height == 480) {			/* Set the OV511 up as 320x480, but keep the			 * V4L resolution as 640x480 */			width = 320;		} else {			err("SAA7111A only allows 320x240 or 640x480");			return -EINVAL;		}	}	/* Make sure width and height are a multiple of 8 */	if (width % 8 || height % 8) {		err("Invalid size (%d, %d) (mode = %d)", width, height, mode);		return -EINVAL;	}	if (width < ov->minwidth || height < ov->minheight) {		err("Requested dimensions are too small");		return -EINVAL;	}	if (ov51x_stop(ov) < 0)		return -EIO;	if (mode == VIDEO_PALETTE_GREY) {		reg_w(ov, R511_CAM_UV_EN, 0x00);		reg_w(ov, R511_SNAP_UV_EN, 0x00);		reg_w(ov, R511_SNAP_OPTS, 0x01);	} else {		reg_w(ov, R511_CAM_UV_EN, 0x01);		reg_w(ov, R511_SNAP_UV_EN, 0x01);		reg_w(ov, R511_SNAP_OPTS, 0x03);	}	/* Here I'm assuming that snapshot size == image size.	 * I hope that's always true. --claudio	 */	hsegs = (width >> 3) - 1;	vsegs = (height >> 3) - 1;	reg_w(ov, R511_CAM_PXCNT, hsegs);	reg_w(ov, R511_CAM_LNCNT, vsegs);	reg_w(ov, R511_CAM_PXDIV, 0x00);	reg_w(ov, R511_CAM_LNDIV, 0x00);	/* YUV420, low pass filter on */	reg_w(ov, R511_CAM_OPTS, 0x03);	/* Snapshot additions */	reg_w(ov, R511_SNAP_PXCNT, hsegs);	reg_w(ov, R511_SNAP_LNCNT, vsegs);	reg_w(ov, R511_SNAP_PXDIV, 0x00);	reg_w(ov, R511_SNAP_LNDIV, 0x00);	if (ov->compress) {		/* Enable Y and UV quantization and compression */		reg_w(ov, R511_COMP_EN, 0x07);		reg_w(ov, R511_COMP_LUT_EN, 0x03);		ov51x_reset(ov, OV511_RESET_OMNICE);	}	if (ov51x_restart(ov) < 0)		return -EIO;	return 0;}/* Sets up the OV518/OV518+ with the given image parameters * * OV518 needs a completely different approach, until we can figure out what * the individual registers do. Also, only 15 FPS is supported now. * * Do not put any sensor-specific code in here (including I2C I/O functions) */static intov518_mode_init_regs(struct usb_ov511 *ov,		     int width, int height, int mode, int sub_flag){	int hsegs, vsegs, hi_res;	if (sub_flag) {		width = ov->subw;		height = ov->subh;	}	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",	       width, height, mode, sub_flag);	if (width % 16 || height % 8) {		err("Invalid size (%d, %d)", width, height);		return -EINVAL;	}	if (width < ov->minwidth || height < ov->minheight) {		err("Requested dimensions are too small");		return -EINVAL;	}	if (width >= 320 && height >= 240) {		hi_res = 1;	} else if (width >= 320 || height >= 240) {		err("Invalid width/height combination (%d, %d)", width, height);		return -EINVAL;	} else {		hi_res = 0;	}	if (ov51x_stop(ov) < 0)		return -EIO;	/******** Set the mode ********/	reg_w(ov, 0x2b, 0);	reg_w(ov, 0x2c, 0);	reg_w(ov, 0x2d, 0);	reg_w(ov, 0x2e, 0);	reg_w(ov, 0x3b, 0);	reg_w(ov, 0x3c, 0);	reg_w(ov, 0x3d, 0);	reg_w(ov, 0x3e, 0);	if (ov->bridge == BRG_OV518 && ov518_color) {		/* OV518 needs U and V swapped */		i2c_w_mask(ov, 0x15, 0x00, 0x01);	 	if (mode == VIDEO_PALETTE_GREY) {			/* Set 16-bit input format (UV data are ignored) */			reg_w_mask(ov, 0x20, 0x00, 0x08);			/* Set 8-bit (4:0:0) output format */			reg_w_mask(ov, 0x28, 0x00, 0xf0);			reg_w_mask(ov, 0x38, 0x00, 0xf0);		} else {			/* Set 8-bit (YVYU) input format */			reg_w_mask(ov, 0x20, 0x08, 0x08);			/* Set 12-bit (4:2:0) output format */			reg_w_mask(ov, 0x28, 0x80, 0xf0);			reg_w_mask(ov, 0x38, 0x80, 0xf0);		}	} else {		reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);		reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);	}	hsegs = width / 16;	vsegs = height / 4;	reg_w(ov, 0x29, hsegs);	reg_w(ov, 0x2a, vsegs);	reg_w(ov, 0x39, hsegs);	reg_w(ov, 0x3a, vsegs);	/* Windows driver does this here; who knows why */	reg_w(ov, 0x2f, 0x80);	/******** Set the framerate (to 15 FPS) ********/	/* Mode independent, but framerate dependent, regs */	reg_w(ov, 0x51, 0x02);	/* Clock divider; lower==faster */	reg_w(ov, 0x22, 0x18);	reg_w(ov, 0x23, 0xff);	if (ov->bridge == BRG_OV518PLUS)		reg_w(ov, 0x21, 0x19);	else		reg_w(ov, 0x71, 0x19);	/* Compression-related? */	// FIXME: Sensor-specific	/* Bit 5 is what matters here. Of course, it is "reserved" */	i2c_w(ov, 0x54, 0x23);	reg_w(ov, 0x2f, 0x80);	if (ov->bridge == BRG_OV518PLUS) {		reg_w(ov, 0x24, 0x94);		reg_w(ov, 0x25, 0x90);		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */		ov518_reg_w32(ov, 0xc6,    540, 2);	/* 21ch   */		ov518_reg_w32(ov, 0xc7,    540, 2);	/* 21ch   */		ov518_reg_w32(ov, 0xc8,    108, 2);	/* 6ch    */		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */		ov518_reg_w32(ov, 0xcc,   2400, 2);	/* 960h   */		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */	} else {		reg_w(ov, 0x24, 0x9f);		reg_w(ov, 0x25, 0x90);		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */		ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */		ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */		ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */		ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */	}	reg_w(ov, 0x2f, 0x80);	if (ov51x_restart(ov) < 0)		return -EIO;	/* Reset it just for good measure */	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)		return -EIO;	return 0;}/* This is a wrapper around the OV511, OV518, and sensor specific functions */static intmode_init_regs(struct usb_ov511 *ov,	       int width, int height, int mode, int sub_flag){	int rc = 0;	if (!ov || !ov->dev)		return -EFAULT;	if (ov->bclass == BCL_OV518) {		rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);	} else {		rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);	}	if (FATAL_ERROR(rc))		return rc;	switch (ov->sensor) {	case SEN_OV7610:	case SEN_OV7620:	case SEN_OV76BE:	case SEN_OV8600:	case SEN_OV6620:	case SEN_OV6630:		rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);		break;	case SEN_KS0127:	case SEN_KS0127B:		err("KS0127-series decoders not supported yet");		rc = -EINVAL;		break;	case SEN_SAA7111A://		rc = mode_init_saa_sensor_regs(ov, width, height, mode,//					       sub_flag);		PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));		break;	default:		err("Unknown sensor");		rc = -EINVAL;	}	if (FATAL_ERROR(rc))		return rc;	/* Sensor-independent settings */	rc = sensor_set_auto_brightness(ov, ov->auto_brt);	if (FATAL_ERROR(rc))		return rc;	rc = sensor_set_auto_exposure(ov, ov->auto_exp);	if (FATAL_ERROR(rc))		return rc;	rc = sensor_set_banding_filter(ov, bandingfilter);	if (FATAL_ERROR(rc))		return rc;	if (ov->lightfreq) {		rc = sensor_set_light_freq(ov, lightfreq);		if (FATAL_ERROR(rc))			return rc;	}	rc = sensor_set_backlight(ov, ov->backlight);	if (FATAL_ERROR(rc))		return rc;	rc = sensor_set_mirror(ov, ov->mirror);	if (FATAL_ERROR(rc))		return rc;	return 0;}/* This sets the default image parameters. This is useful for apps that use * read() and do not set these. */static intov51x_set_default_params(struct usb_ov511 *ov){	int i;	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used	 * (using read() instead). */	for (i = 0; i < OV511_NUMFRAMES; i++) {		ov->frame[i].width = ov->maxwidth;		ov->frame[i].height = ov->maxheight;		ov->frame[i].bytes_read = 0;		if (force_palette)			ov->frame[i].format = force_palette;		else			ov->frame[i].format = VIDEO_PALETTE_YUV420;		ov->frame[i].depth = get_depth(ov->frame[i].format);	}	PDEBUG(3, "%dx%d, %s

⌨️ 快捷键说明

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