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

📄 saa7115.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 3 页
字号:
static int saa7115_odd_parity(u8 c){	c ^= (c >> 4);	c ^= (c >> 2);	c ^= (c >> 1);	return c & 1;}static int saa7115_decode_vps(u8 * dst, u8 * p){	static const u8 biphase_tbl[] = {		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,	};	int i;	u8 c, err = 0;	for (i = 0; i < 2 * 13; i += 2) {		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];		c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);		dst[i / 2] = c;	}	return err & 0xf0;}static int saa7115_decode_wss(u8 * p){	static const int wss_bits[8] = {		0, 0, 0, 1, 0, 1, 1, 1	};	unsigned char parity;	int wss = 0;	int i;	for (i = 0; i < 16; i++) {		int b1 = wss_bits[p[i] & 7];		int b2 = wss_bits[(p[i] >> 3) & 7];		if (b1 == b2)			return -1;		wss |= b2 << i;	}	parity = wss & 15;	parity ^= parity >> 2;	parity ^= parity >> 1;	if (!(parity & 1))		return -1;	return wss;}static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq){	struct saa7115_state *state = i2c_get_clientdata(client);	u32 acpf;	u32 acni;	u32 hz;	u64 f;	u8 acc = 0; 	/* reg 0x3a, audio clock control */	v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);	/* sanity check */	if (freq < 32000 || freq > 48000)		return -EINVAL;	/* The saa7113 has no audio clock */	if (state->ident == V4L2_IDENT_SAA7113)		return 0;	/* hz is the refresh rate times 100 */	hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;	/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */	acpf = (25600 * freq) / hz;	/* acni = (256 * freq * 2^23) / crystal_frequency =		  (freq * 2^(8+23)) / crystal_frequency =		  (freq << 31) / crystal_frequency */	f = freq;	f = f << 31;	do_div(f, state->crystal_freq);	acni = f;	if (state->ucgc) {		acpf = acpf * state->cgcdiv / 16;		acni = acni * state->cgcdiv / 16;		acc = 0x80;		if (state->cgcdiv == 3)			acc |= 0x40;	}	if (state->apll)		acc |= 0x08;	saa7115_write(client, 0x38, 0x03);	saa7115_write(client, 0x39, 0x10);	saa7115_write(client, 0x3a, acc);	saa7115_write(client, 0x30, acpf & 0xff);	saa7115_write(client, 0x31, (acpf >> 8) & 0xff);	saa7115_write(client, 0x32, (acpf >> 16) & 0x03);	saa7115_write(client, 0x34, acni & 0xff);	saa7115_write(client, 0x35, (acni >> 8) & 0xff);	saa7115_write(client, 0x36, (acni >> 16) & 0x3f);	state->audclk_freq = freq;	return 0;}static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl){	struct saa7115_state *state = i2c_get_clientdata(client);	switch (ctrl->id) {	case V4L2_CID_BRIGHTNESS:		if (ctrl->value < 0 || ctrl->value > 255) {			v4l_err(client, "invalid brightness setting %d\n", ctrl->value);			return -ERANGE;		}		state->bright = ctrl->value;		saa7115_write(client, 0x0a, state->bright);		break;	case V4L2_CID_CONTRAST:		if (ctrl->value < 0 || ctrl->value > 127) {			v4l_err(client, "invalid contrast setting %d\n", ctrl->value);			return -ERANGE;		}		state->contrast = ctrl->value;		saa7115_write(client, 0x0b, state->contrast);		break;	case V4L2_CID_SATURATION:		if (ctrl->value < 0 || ctrl->value > 127) {			v4l_err(client, "invalid saturation setting %d\n", ctrl->value);			return -ERANGE;		}		state->sat = ctrl->value;		saa7115_write(client, 0x0c, state->sat);		break;	case V4L2_CID_HUE:		if (ctrl->value < -127 || ctrl->value > 127) {			v4l_err(client, "invalid hue setting %d\n", ctrl->value);			return -ERANGE;		}		state->hue = ctrl->value;		saa7115_write(client, 0x0d, state->hue);		break;	default:		return -EINVAL;	}	return 0;}static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl){	struct saa7115_state *state = i2c_get_clientdata(client);	switch (ctrl->id) {	case V4L2_CID_BRIGHTNESS:		ctrl->value = state->bright;		break;	case V4L2_CID_CONTRAST:		ctrl->value = state->contrast;		break;	case V4L2_CID_SATURATION:		ctrl->value = state->sat;		break;	case V4L2_CID_HUE:		ctrl->value = state->hue;		break;	default:		return -EINVAL;	}	return 0;}static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std){	struct saa7115_state *state = i2c_get_clientdata(client);	int taskb = saa7115_read(client, 0x80) & 0x10;	/* 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;	// 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");		saa7115_writeregs(client, saa7115_cfg_60hz_video);	} else {		v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");		saa7115_writeregs(client, saa7115_cfg_50hz_video);	}	/* Register 0E - Bits D6-D4 on NO-AUTO mode		(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_SAA7113) {		u8 reg = saa7115_read(client, 0x0e) & 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;		}		saa7115_write(client, 0x0e, reg);	}	state->std = std;	/* restart task B if needed */	if (taskb && state->ident != V4L2_IDENT_SAA7115) {		saa7115_writeregs(client, saa7115_cfg_vbi_on);	}	/* switch audio mode too! */	saa7115_set_audio_clock_freq(client, state->audclk_freq);}static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client){	struct saa7115_state *state = i2c_get_clientdata(client);	return state->std;}static void saa7115_log_status(struct i2c_client *client){	struct saa7115_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 = saa7115_read(client, 0x1f);		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 = saa7115_read(client, 0x1e);	reg1f = saa7115_read(client, 0x1f);	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;	}}/* setup the sliced VBI lcr registers according to the sliced VBI format */static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt){	struct saa7115_state *state = i2c_get_clientdata(client);	int is_50hz = (state->std & V4L2_STD_625_50);	u8 lcr[24];	int i, x;	/* saa7113/7114 doesn't yet support VBI */	if (state->ident != V4L2_IDENT_SAA7115)		return;	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++) {		saa7115_write(client, i - 2 + 0x41, lcr[i]);	}	/* enable/disable raw VBI capturing */	saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);}static int saa7115_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 (saa7115_read(client, 0x80) & 0x10)		return 0;	for (i = 2; i <= 23; i++) {		u8 v = saa7115_read(client, i - 2 + 0x41);		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 saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt){	struct saa7115_state *state = i2c_get_clientdata(client);	struct v4l2_pix_format *pix;	int HPSC, HFSC;	int VSCY, Vsrc;	int is_50hz = state->std & V4L2_STD_625_50;	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {		saa7115_set_lcr(client, &fmt->fmt.sliced);		return 0;	}	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	pix = &(fmt->fmt.pix);	v4l_dbg(1, debug, client, "decoder set size\n");	/* FIXME need better bounds checking here */	if ((pix->width < 1) || (pix->width > 1440))		return -EINVAL;	if ((pix->height < 1) || (pix->height > 960))		return -EINVAL;	/* probably have a valid size, let's set it */	/* Set output width/height */	/* width */	saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));	saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));	/* height */	saa7115_write(client, 0xce, (u8) (pix->height & 0xff));	saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));	/* Scaling settings */	/* Hprescaler is floor(inres/outres) */	/* FIXME hardcoding input res */	if (pix->width != 720) {		HPSC = (int)(720 / pix->width);		/* 0 is not allowed (div. by zero) */		HPSC = HPSC ? HPSC : 1;		HFSC = (int)((1024 * 720) / (HPSC * pix->width));		v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);		/* FIXME hardcodes to "Task B"		 * write H prescaler integer */		saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));		/* write H fine-scaling (luminance) */		saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));		saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));		/* write H fine-scaling (chrominance)		 * must be lum/2, so i'll just bitshift :) */		saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));		saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));	} else {		if (is_50hz) {			v4l_dbg(1, debug, client, "Setting full 50hz width\n");			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);		} else {			v4l_dbg(1, debug, client, "Setting full 60hz width\n");			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);		}	}	Vsrc = is_50hz ? 576 : 480;	if (pix->height != Vsrc) {		VSCY = (int)((1024 * Vsrc) / pix->height);		v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);		/* Correct Contrast and Luminance */		saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));		saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));

⌨️ 快捷键说明

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