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

📄 saa7115.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		return -EINVAL;	}	return 0;}static int saa711x_set_size(struct i2c_client *client, int width, int height){	struct saa711x_state *state = i2c_get_clientdata(client);	int HPSC, HFSC;	int VSCY;	int res;	int is_50hz = state->std & V4L2_STD_625_50;	int Vsrc = is_50hz ? 576 : 480;	v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);	/* FIXME need better bounds checking here */	if ((width < 1) || (width > 1440))		return -EINVAL;	if ((height < 1) || (height > Vsrc))		return -EINVAL;	if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {		/* Decoder only supports 720 columns and 480 or 576 lines */		if (width != 720)			return -EINVAL;		if (height != Vsrc)			return -EINVAL;	}	state->width = width;	state->height = height;	if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))		return 0;	/* probably have a valid size, let's set it */	/* Set output width/height */	/* width */	saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,					(u8) (width & 0xff));	saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,					(u8) ((width >> 8) & 0xff));	/* Vertical Scaling uses height/2 */	res=height/2;	/* On 60Hz, it is using a higher Vertical Output Size */	if (!is_50hz)		res += (VRES_60HZ - 480) >> 1;		/* height */	saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,					(u8) (res & 0xff));	saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,					(u8) ((res >> 8) & 0xff));	/* Scaling settings */	/* Hprescaler is floor(inres/outres) */	HPSC = (int)(720 / width);	/* 0 is not allowed (div. by zero) */	HPSC = HPSC ? HPSC : 1;	HFSC = (int)((1024 * 720) / (HPSC * width));	/* FIXME hardcodes to "Task B"	 * write H prescaler integer */	saa711x_write(client, R_D0_B_HORIZ_PRESCALING,				(u8) (HPSC & 0x3f));	v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);	/* write H fine-scaling (luminance) */	saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,				(u8) (HFSC & 0xff));	saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,				(u8) ((HFSC >> 8) & 0xff));	/* write H fine-scaling (chrominance)	 * must be lum/2, so i'll just bitshift :) */	saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,				(u8) ((HFSC >> 1) & 0xff));	saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,				(u8) ((HFSC >> 9) & 0xff));	VSCY = (int)((1024 * Vsrc) / height);	v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);	/* Correct Contrast and Luminance */	saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,					(u8) (64 * 1024 / VSCY));	saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,					(u8) (64 * 1024 / VSCY));		/* write V fine-scaling (luminance) */	saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,					(u8) (VSCY & 0xff));	saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,					(u8) ((VSCY >> 8) & 0xff));		/* write V fine-scaling (chrominance) */	saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,					(u8) (VSCY & 0xff));	saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,					(u8) ((VSCY >> 8) & 0xff));	saa711x_writeregs(client, saa7115_cfg_reset_scaler);	/* Activates task "B" */	saa711x_write(client, R_80_GLOBAL_CNTL_1,				saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);	return 0;}static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std){	struct saa711x_state *state = i2c_get_clientdata(client);	/* Prevent unnecessary standard changes. During a standard	   change the I-Port is temporarily disabled. Any devices	   reading from that port can get confused.	   Note that VIDIOC_S_STD is also used to switch from	   radio to TV mode, so if a VIDIOC_S_STD is broadcast to	   all I2C devices then you do not want to have an unwanted	   side-effect here. */	if (std == state->std)		return;	state->std = std;	// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.	if (std & V4L2_STD_525_60) {		v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");		saa711x_writeregs(client, saa7115_cfg_60hz_video);		saa711x_set_size(client, 720, 480);	} else {		v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");		saa711x_writeregs(client, saa7115_cfg_50hz_video);		saa711x_set_size(client, 720, 576);	}	/* Register 0E - Bits D6-D4 on NO-AUTO mode		(SAA7111 and SAA7113 doesn't have auto mode)	    50 Hz / 625 lines           60 Hz / 525 lines	000 PAL BGDHI (4.43Mhz)         NTSC M (3.58MHz)	001 NTSC 4.43 (50 Hz)           PAL 4.43 (60 Hz)	010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)	011 NTSC N (3.58MHz)            PAL M (3.58MHz)	100 reserved                    NTSC-Japan (3.58MHz)	*/	if (state->ident == V4L2_IDENT_SAA7111 ||	    state->ident == V4L2_IDENT_SAA7113) {		u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;		if (std == V4L2_STD_PAL_M) {			reg |= 0x30;		} else if (std == V4L2_STD_PAL_N) {			reg |= 0x20;		} else if (std == V4L2_STD_PAL_60) {			reg |= 0x10;		} else if (std == V4L2_STD_NTSC_M_JP) {			reg |= 0x40;		} else if (std & V4L2_STD_SECAM) {			reg |= 0x50;		}		saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);	} else {		/* restart task B if needed */		int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;		if (taskb && state->ident == V4L2_IDENT_SAA7114) {			saa711x_writeregs(client, saa7115_cfg_vbi_on);		}		/* switch audio mode too! */		saa711x_set_audio_clock_freq(client, state->audclk_freq);	}}static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client){	struct saa711x_state *state = i2c_get_clientdata(client);	return state->std;}static void saa711x_log_status(struct i2c_client *client){	struct saa711x_state *state = i2c_get_clientdata(client);	int reg1e, reg1f;	int signalOk;	int vcr;	v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);	if (state->ident != V4L2_IDENT_SAA7115) {		/* status for the saa7114 */		reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);		signalOk = (reg1f & 0xc1) == 0x81;		v4l_info(client, "Video signal:    %s\n", signalOk ? "ok" : "bad");		v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");		return;	}	/* status for the saa7115 */	reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);	reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);	signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;	vcr = !(reg1f & 0x10);	if (state->input >= 6) {		v4l_info(client, "Input:           S-Video %d\n", state->input - 6);	} else {		v4l_info(client, "Input:           Composite %d\n", state->input);	}	v4l_info(client, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");	v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");	switch (reg1e & 0x03) {		case 1:			v4l_info(client, "Detected format: NTSC\n");			break;		case 2:			v4l_info(client, "Detected format: PAL\n");			break;		case 3:			v4l_info(client, "Detected format: SECAM\n");			break;		default:			v4l_info(client, "Detected format: BW/No color\n");			break;	}	v4l_info(client, "Width, Height:   %d, %d\n", state->width, state->height);}/* setup the sliced VBI lcr registers according to the sliced VBI format */static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt){	struct saa711x_state *state = i2c_get_clientdata(client);	int is_50hz = (state->std & V4L2_STD_625_50);	u8 lcr[24];	int i, x;#if 1	/* saa7113/7114/7118 VBI support are experimental */	if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))		return;#else	/* SAA7113 and SAA7118 also should support VBI - Need testing */	if (state->ident != V4L2_IDENT_SAA7115)		return;#endif	for (i = 0; i <= 23; i++)		lcr[i] = 0xff;	if (fmt->service_set == 0) {		/* raw VBI */		if (is_50hz)			for (i = 6; i <= 23; i++)				lcr[i] = 0xdd;		else			for (i = 10; i <= 21; i++)				lcr[i] = 0xdd;	} else {		/* sliced VBI */		/* first clear lines that cannot be captured */		if (is_50hz) {			for (i = 0; i <= 5; i++)				fmt->service_lines[0][i] =					fmt->service_lines[1][i] = 0;		}		else {			for (i = 0; i <= 9; i++)				fmt->service_lines[0][i] =					fmt->service_lines[1][i] = 0;			for (i = 22; i <= 23; i++)				fmt->service_lines[0][i] =					fmt->service_lines[1][i] = 0;		}		/* Now set the lcr values according to the specified service */		for (i = 6; i <= 23; i++) {			lcr[i] = 0;			for (x = 0; x <= 1; x++) {				switch (fmt->service_lines[1-x][i]) {					case 0:						lcr[i] |= 0xf << (4 * x);						break;					case V4L2_SLICED_TELETEXT_B:						lcr[i] |= 1 << (4 * x);						break;					case V4L2_SLICED_CAPTION_525:						lcr[i] |= 4 << (4 * x);						break;					case V4L2_SLICED_WSS_625:						lcr[i] |= 5 << (4 * x);						break;					case V4L2_SLICED_VPS:						lcr[i] |= 7 << (4 * x);						break;				}			}		}	}	/* write the lcr registers */	for (i = 2; i <= 23; i++) {		saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);	}	/* enable/disable raw VBI capturing */	saa711x_writeregs(client, fmt->service_set == 0 ?				saa7115_cfg_vbi_on :				saa7115_cfg_vbi_off);}static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt){	static u16 lcr2vbi[] = {		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */		0, V4L2_SLICED_CAPTION_525,	/* 4 */		V4L2_SLICED_WSS_625, 0,		/* 5 */		V4L2_SLICED_VPS, 0, 0, 0, 0,	/* 7 */		0, 0, 0, 0	};	struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;	int i;	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)		return -EINVAL;	memset(sliced, 0, sizeof(*sliced));	/* done if using raw VBI */	if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)		return 0;	for (i = 2; i <= 23; i++) {		u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);		sliced->service_lines[0][i] = lcr2vbi[v >> 4];		sliced->service_lines[1][i] = lcr2vbi[v & 0xf];		sliced->service_set |=			sliced->service_lines[0][i] | sliced->service_lines[1][i];	}	return 0;}static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt){	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {		saa711x_set_lcr(client, &fmt->fmt.sliced);		return 0;	}	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);}/* Decode the sliced VBI data stream as created by the saa7115.   The format is described in the saa7115 datasheet in Tables 25 and 26   and in Figure 33.   The current implementation uses SAV/EAV codes and not the ancillary data   headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV   code. */static void saa711x_decode_vbi_line(struct i2c_client *client,				    struct v4l2_decode_vbi_line *vbi){	static const char vbi_no_data_pattern[] = {		0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0	};	struct saa711x_state *state = i2c_get_clientdata(client);	u8 *p = vbi->p;	u32 wss;	int id1, id2;   /* the ID1 and ID2 bytes from the internal header */	vbi->type = 0;  /* mark result as a failure */	id1 = p[2];	id2 = p[3];	/* Note: the field bit is inverted for 60 Hz video */	if (state->std & V4L2_STD_525_60)		id1 ^= 0x40;	/* Skip internal header, p now points to the start of the payload */	p += 4;	vbi->p = p;	/* calculate field and line number of the VBI packet (1-23) */	vbi->is_second_field = ((id1 & 0x40) != 0);	vbi->line = (id1 & 0x3f) << 3;	vbi->line |= (id2 & 0x70) >> 4;	/* Obtain data type */	id2 &= 0xf;	/* If the VBI slicer does not detect any signal it will fill up	   the payload buffer with 0xa0 bytes. */	if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))		return;	/* decode payloads */	switch (id2) {	case 1:		vbi->type = V4L2_SLICED_TELETEXT_B;

⌨️ 快捷键说明

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