tda9887.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 920 行 · 第 1/2 页

C
920
字号
	}	if (UNSET != qss) {		if (qss)			buf[1] |= cQSS;		else			buf[1] &= ~cQSS;	}	if (adjust >= 0x00 && adjust < 0x20) {		buf[2] &= ~cTopMask;		buf[2] |= adjust;	}	return 0;}static int tda9887_set_config(struct tda9887 *t, char *buf){	if (t->config & TDA9887_PORT1_ACTIVE)		buf[1] &= ~cOutputPort1Inactive;	if (t->config & TDA9887_PORT1_INACTIVE)		buf[1] |= cOutputPort1Inactive;	if (t->config & TDA9887_PORT2_ACTIVE)		buf[1] &= ~cOutputPort2Inactive;	if (t->config & TDA9887_PORT2_INACTIVE)		buf[1] |= cOutputPort2Inactive;	if (t->config & TDA9887_QSS)		buf[1] |= cQSS;	if (t->config & TDA9887_INTERCARRIER)		buf[1] &= ~cQSS;	if (t->config & TDA9887_AUTOMUTE)		buf[1] |= cAutoMuteFmActive;	if (t->config & TDA9887_DEEMPHASIS_MASK) {		buf[2] &= ~0x60;		switch (t->config & TDA9887_DEEMPHASIS_MASK) {		case TDA9887_DEEMPHASIS_NONE:			buf[2] |= cDeemphasisOFF;			break;		case TDA9887_DEEMPHASIS_50:			buf[2] |= cDeemphasisON | cDeemphasis50;			break;		case TDA9887_DEEMPHASIS_75:			buf[2] |= cDeemphasisON | cDeemphasis75;			break;		}	}	if (t->config & TDA9887_TOP_SET) {		buf[2] &= ~cTopMask;		buf[2] |= (t->config >> 8) & cTopMask;	}	if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))		buf[1] &= ~cQSS;	return 0;}/* ---------------------------------------------------------------------- */static char pal[] = "--";static char secam[] = "--";static char ntsc[] = "-";module_param_string(pal, pal, sizeof(pal), 0644);module_param_string(secam, secam, sizeof(secam), 0644);module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);static int tda9887_fixup_std(struct tda9887 *t){	/* get more precise norm info from insmod option */	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {		switch (pal[0]) {		case 'b':		case 'B':		case 'g':		case 'G':		case 'h':		case 'H':		case 'n':		case 'N':			if (pal[1] == 'c' || pal[1] == 'C') {				tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");				t->std = V4L2_STD_PAL_Nc;			} else {				tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");				t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;			}			break;		case 'i':		case 'I':			tda9887_dbg("insmod fixup: PAL => PAL-I\n");			t->std = V4L2_STD_PAL_I;			break;		case 'd':		case 'D':		case 'k':		case 'K':			tda9887_dbg("insmod fixup: PAL => PAL-DK\n");			t->std = V4L2_STD_PAL_DK;			break;		case 'm':		case 'M':			tda9887_dbg("insmod fixup: PAL => PAL-M\n");			t->std = V4L2_STD_PAL_M;			break;		case '-':			/* default parameter, do nothing */			break;		default:			tda9887_info("pal= argument not recognised\n");			break;		}	}	if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {		switch (secam[0]) {		case 'b':		case 'B':		case 'g':		case 'G':		case 'h':		case 'H':			tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");			t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;			break;		case 'd':		case 'D':		case 'k':		case 'K':			tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");			t->std = V4L2_STD_SECAM_DK;			break;		case 'l':		case 'L':			if (secam[1] == 'c' || secam[1] == 'C') {				tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");				t->std = V4L2_STD_SECAM_LC;			} else {				tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");				t->std = V4L2_STD_SECAM_L;			}			break;		case '-':			/* default parameter, do nothing */			break;		default:			tda9887_info("secam= argument not recognised\n");			break;		}	}	if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {		switch (ntsc[0]) {		case 'm':		case 'M':			tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");			t->std = V4L2_STD_NTSC_M;			break;		case 'j':		case 'J':			tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");			t->std = V4L2_STD_NTSC_M_JP;			break;		case 'k':		case 'K':			tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");			t->std = V4L2_STD_NTSC_M_KR;			break;		case '-':			/* default parameter, do nothing */			break;		default:			tda9887_info("ntsc= argument not recognised\n");			break;		}	}	return 0;}static int tda9887_status(struct tda9887 *t){	unsigned char buf[1];	int rc;	memset(buf,0,sizeof(buf));	if (1 != (rc = i2c_master_recv(&t->client,buf,1)))		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);	dump_read_message(t, buf);	return 0;}static int tda9887_configure(struct tda9887 *t){	int rc;	memset(t->data,0,sizeof(t->data));	tda9887_set_tvnorm(t,t->data);	/* A note on the port settings:	   These settings tend to depend on the specifics of the board.	   By default they are set to inactive (bit value 1) by this driver,	   overwriting any changes made by the tvnorm. This means that it	   is the responsibility of the module using the tda9887 to set	   these values in case of changes in the tvnorm.	   In many cases port 2 should be made active (0) when selecting	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.	   For the other standards the tda9887 application note says that	   the ports should be set to active (0), but, again, that may	   differ depending on the precise hardware configuration.	 */	t->data[1] |= cOutputPort1Inactive;	t->data[1] |= cOutputPort2Inactive;	tda9887_set_config(t,t->data);	tda9887_set_insmod(t,t->data);	if (t->mode == T_STANDBY) {		t->data[1] |= cForcedMuteAudioON;	}	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",		t->data[1],t->data[2],t->data[3]);	if (debug > 1)		dump_write_message(t, t->data);	if (4 != (rc = i2c_master_send(&t->client,t->data,4)))		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);	if (debug > 2) {		msleep_interruptible(1000);		tda9887_status(t);	}	return 0;}/* ---------------------------------------------------------------------- */static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind){	struct tda9887 *t;	client_template.adapter = adap;	client_template.addr    = addr;	if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))		return -ENOMEM;	t->client      = client_template;	t->std         = 0;	t->radio_mode = V4L2_TUNER_MODE_STEREO;	tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);	i2c_set_clientdata(&t->client, t);	i2c_attach_client(&t->client);	return 0;}static int tda9887_probe(struct i2c_adapter *adap){	if (adap->class & I2C_CLASS_TV_ANALOG)		return i2c_probe(adap, &addr_data, tda9887_attach);	return 0;}static int tda9887_detach(struct i2c_client *client){	struct tda9887 *t = i2c_get_clientdata(client);	i2c_detach_client(client);	kfree(t);	return 0;}#define SWITCH_V4L2	if (!t->using_v4l2 && debug) \			  tda9887_info("switching to v4l2\n"); \			  t->using_v4l2 = 1;#define CHECK_V4L2	if (t->using_v4l2) { if (debug) \			  tda9887_info("ignore v4l1 call\n"); \			  return 0; }static inttda9887_command(struct i2c_client *client, unsigned int cmd, void *arg){	struct tda9887 *t = i2c_get_clientdata(client);	switch (cmd) {	/* --- configuration --- */	case AUDC_SET_RADIO:	{		t->mode = T_RADIO;		tda9887_configure(t);		break;	}	case TUNER_SET_STANDBY:	{		t->mode = T_STANDBY;		tda9887_configure(t);		break;	}	case TDA9887_SET_CONFIG:	{		int *i = arg;		t->config = *i;		tda9887_configure(t);		break;	}	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	   kernel pointer here... */	case VIDIOCSCHAN:	{		static const v4l2_std_id map[] = {			[ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,			[ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,			[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,			[ 4 /* bttv */     ] = V4L2_STD_PAL_M,			[ 5 /* bttv */     ] = V4L2_STD_PAL_N,			[ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,		};		struct video_channel *vc = arg;		CHECK_V4L2;		t->mode = T_ANALOG_TV;		if (vc->norm < ARRAY_SIZE(map))			t->std = map[vc->norm];		tda9887_fixup_std(t);		tda9887_configure(t);		break;	}	case VIDIOC_S_STD:	{		v4l2_std_id *id = arg;		SWITCH_V4L2;		t->mode = T_ANALOG_TV;		t->std   = *id;		tda9887_fixup_std(t);		tda9887_configure(t);		break;	}	case VIDIOC_S_FREQUENCY:	{		struct v4l2_frequency *f = arg;		SWITCH_V4L2;		if (V4L2_TUNER_ANALOG_TV == f->type) {			if (t->mode == T_ANALOG_TV)				return 0;			t->mode = T_ANALOG_TV;		}		if (V4L2_TUNER_RADIO == f->type) {			if (t->mode == T_RADIO)				return 0;			t->mode = T_RADIO;		}		tda9887_configure(t);		break;	}	case VIDIOC_G_TUNER:	{		static int AFC_BITS_2_kHz[] = {			-12500,  -37500,  -62500,  -97500,			-112500, -137500, -162500, -187500,			187500,  162500,  137500,  112500,			97500 ,  62500,   37500 ,  12500		};		struct v4l2_tuner* tuner = arg;		if (t->mode == T_RADIO) {			__u8 reg = 0;			tuner->afc=0;			if (1 == i2c_master_recv(&t->client,&reg,1))				tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];		}		break;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner* tuner = arg;		if (t->mode == T_RADIO) {			t->radio_mode = tuner->audmode;			tda9887_configure (t);		}		break;	}	case VIDIOC_LOG_STATUS:	{		tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);		break;	}	default:		/* nothing */		break;	}	return 0;}static int tda9887_suspend(struct device * dev, pm_message_t state){	struct i2c_client *c = container_of(dev, struct i2c_client, dev);	struct tda9887 *t = i2c_get_clientdata(c);	tda9887_dbg("suspend\n");	return 0;}static int tda9887_resume(struct device * dev){	struct i2c_client *c = container_of(dev, struct i2c_client, dev);	struct tda9887 *t = i2c_get_clientdata(c);	tda9887_dbg("resume\n");	tda9887_configure(t);	return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver driver = {	.id             = I2C_DRIVERID_TDA9887,	.attach_adapter = tda9887_probe,	.detach_client  = tda9887_detach,	.command        = tda9887_command,	.driver = {		.name    = "tda9887",		.suspend = tda9887_suspend,		.resume  = tda9887_resume,	},};static struct i2c_client client_template ={	.name      = "tda9887",	.driver    = &driver,};static int __init tda9887_init_module(void){	return i2c_add_driver(&driver);}static void __exit tda9887_cleanup_module(void){	i2c_del_driver(&driver);}module_init(tda9887_init_module);module_exit(tda9887_cleanup_module);/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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