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

📄 msp3400.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (HAVE_NICAM(msp)) {		/* nicam prescale */		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */	}}/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */static int best_video_sound(int rxsubchans){	if (rxsubchans & V4L2_TUNER_SUB_STEREO)		return V4L2_TUNER_MODE_STEREO;	if (rxsubchans & V4L2_TUNER_SUB_LANG1)		return V4L2_TUNER_MODE_LANG1;	if (rxsubchans & V4L2_TUNER_SUB_LANG2)		return V4L2_TUNER_MODE_LANG2;	return V4L2_TUNER_MODE_MONO;}/* turn on/off nicam + stereo */static void msp3400c_setstereo(struct i2c_client *client, int mode){	static char *strmode[] = { "0", "mono", "stereo", "3",		"lang1", "5", "6", "7", "lang2"	};	struct msp3400c *msp = i2c_get_clientdata(client);	int nicam = 0;		/* channel source: FM/AM or nicam */	int src = 0;	if (IS_MSP34XX_G(msp)) {		/* this method would break everything, let's make sure		 * it's never called		 */		msp3400_dbg		    ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",		     mode);		return;	}	/* switch demodulator */	switch (msp->mode) {	case MSP_MODE_FM_TERRA:		msp3400_dbg("FM setstereo: %s\n", strmode[mode]);		msp3400c_setcarrier(client,msp->second,msp->main);		switch (mode) {		case V4L2_TUNER_MODE_STEREO:			msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);			break;		case V4L2_TUNER_MODE_MONO:		case V4L2_TUNER_MODE_LANG1:		case V4L2_TUNER_MODE_LANG2:			msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000);			break;		}		break;	case MSP_MODE_FM_SAT:		msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);		switch (mode) {		case V4L2_TUNER_MODE_MONO:			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));			break;		case V4L2_TUNER_MODE_STEREO:			msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));			break;		case V4L2_TUNER_MODE_LANG1:			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));			break;		case V4L2_TUNER_MODE_LANG2:			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));			break;		}		break;	case MSP_MODE_FM_NICAM1:	case MSP_MODE_FM_NICAM2:	case MSP_MODE_AM_NICAM:		msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);		msp3400c_setcarrier(client,msp->second,msp->main);		if (msp->nicam_on)			nicam=0x0100;		break;	case MSP_MODE_BTSC:		msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);		nicam=0x0300;		break;	case MSP_MODE_EXTERN:		msp3400_dbg("extern setstereo: %s\n",strmode[mode]);		nicam = 0x0200;		break;	case MSP_MODE_FM_RADIO:		msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);		break;	default:		msp3400_dbg("mono setstereo\n");		return;	}	/* switch audio */	switch (best_video_sound(mode)) {	case V4L2_TUNER_MODE_STEREO:		src = 0x0020 | nicam;		break;	case V4L2_TUNER_MODE_MONO:		if (msp->mode == MSP_MODE_AM_NICAM) {			msp3400_dbg("switching to AM mono\n");			/* AM mono decoding is handled by tuner, not MSP chip */			/* SCART switching control register */			msp3400c_set_scart(client,SCART_MONO,0);			src = 0x0200;			break;		}	case V4L2_TUNER_MODE_LANG1:		src = 0x0000 | nicam;		break;	case V4L2_TUNER_MODE_LANG2:		src = 0x0010 | nicam;		break;	}	msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);	if (dolby) {		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);	} else {		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);	}}static voidmsp3400c_print_mode(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	if (msp->main == msp->second) {		msp3400_dbg("mono sound carrier: %d.%03d MHz\n",		       msp->main/910000,(msp->main/910)%1000);	} else {		msp3400_dbg("main sound carrier: %d.%03d MHz\n",		       msp->main/910000,(msp->main/910)%1000);	}	if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)		msp3400_dbg("NICAM/FM carrier   : %d.%03d MHz\n",		       msp->second/910000,(msp->second/910)%1000);	if (msp->mode == MSP_MODE_AM_NICAM)		msp3400_dbg("NICAM/AM carrier   : %d.%03d MHz\n",		       msp->second/910000,(msp->second/910)%1000);	if (msp->mode == MSP_MODE_FM_TERRA &&	    msp->main != msp->second) {		msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",		       msp->second/910000,(msp->second/910)%1000);	}}#define MSP3400_MAX 4static struct i2c_client *msps[MSP3400_MAX];static void msp3400c_restore_dfp(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	int i;	for (i = 0; i < DFP_COUNT; i++) {		if (-1 == msp->dfp_regs[i])			continue;		msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);	}}/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */static int msp3400c_write_dfp_with_default(struct i2c_client *client,					int addr, int default_value){	struct msp3400c *msp = i2c_get_clientdata(client);	int value = default_value;	if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])		value = msp->dfp_regs[addr];	return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);}/* ----------------------------------------------------------------------- */struct REGISTER_DUMP {	int   addr;	char *name;};struct REGISTER_DUMP d1[] = {	{0x007e, "autodetect"},	{0x0023, "C_AD_BITS "},	{0x0038, "ADD_BITS  "},	{0x003e, "CIB_BITS  "},	{0x0057, "ERROR_RATE"},};static int autodetect_stereo(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	int val;	int rxsubchans = msp->rxsubchans;	int newnicam   = msp->nicam_on;	int update = 0;	switch (msp->mode) {	case MSP_MODE_FM_TERRA:		val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);		if (val > 32767)			val -= 65536;		msp3400_dbg("stereo detect register: %d\n",val);		if (val > 4096) {			rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;		} else if (val < -4096) {			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;		} else {			rxsubchans = V4L2_TUNER_SUB_MONO;		}		newnicam = 0;		break;	case MSP_MODE_FM_NICAM1:	case MSP_MODE_FM_NICAM2:	case MSP_MODE_AM_NICAM:		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);		msp3400_dbg("nicam sync=%d, mode=%d\n",			val & 1, (val & 0x1e) >> 1);		if (val & 1) {			/* nicam synced */			switch ((val & 0x1e) >> 1)  {			case 0:			case 8:				rxsubchans = V4L2_TUNER_SUB_STEREO;				break;			case 1:			case 9:				rxsubchans = V4L2_TUNER_SUB_MONO					| V4L2_TUNER_SUB_LANG1;				break;			case 2:			case 10:				rxsubchans = V4L2_TUNER_SUB_MONO					| V4L2_TUNER_SUB_LANG1					| V4L2_TUNER_SUB_LANG2;				break;			default:				rxsubchans = V4L2_TUNER_SUB_MONO;				break;			}			newnicam=1;		} else {			newnicam = 0;			rxsubchans = V4L2_TUNER_SUB_MONO;		}		break;	case MSP_MODE_BTSC:		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);		msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",			val,			(val & 0x0002) ? "no"     : "yes",			(val & 0x0004) ? "no"     : "yes",			(val & 0x0040) ? "stereo" : "mono",			(val & 0x0080) ? ", nicam 2nd mono" : "",			(val & 0x0100) ? ", bilingual/SAP"  : "");		rxsubchans = V4L2_TUNER_SUB_MONO;		if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;		if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;		break;	}	if (rxsubchans != msp->rxsubchans) {		update = 1;		msp3400_dbg("watch: rxsubchans %d => %d\n",			msp->rxsubchans,rxsubchans);		msp->rxsubchans = rxsubchans;	}	if (newnicam != msp->nicam_on) {		update = 1;		msp3400_dbg("watch: nicam %d => %d\n",			msp->nicam_on,newnicam);		msp->nicam_on = newnicam;	}	return update;}/* * A kernel thread for msp3400 control -- we don't want to block the * in the ioctl while doing the sound carrier & stereo detect */static int msp34xx_sleep(struct msp3400c *msp, int timeout){	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(&msp->wq, &wait);	if (!kthread_should_stop()) {		if (timeout < 0) {			set_current_state(TASK_INTERRUPTIBLE);			schedule();		} else {			schedule_timeout_interruptible						(msecs_to_jiffies(timeout));		}	}	remove_wait_queue(&msp->wq, &wait);	try_to_freeze();	return msp->restart;}/* stereo/multilang monitoring */static void watch_stereo(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	if (autodetect_stereo(client)) {		if (msp->stereo & V4L2_TUNER_MODE_STEREO)			msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);		else if (msp->stereo & VIDEO_SOUND_LANG1)			msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);		else			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);	}	if (once)		msp->watch_stereo = 0;}static int msp3400c_thread(void *data){	struct i2c_client *client = data;	struct msp3400c *msp = i2c_get_clientdata(client);	struct CARRIER_DETECT *cd;	int count, max1,max2,val1,val2, val,this;	msp3400_info("msp3400 daemon started\n");	for (;;) {		msp3400_dbg_mediumvol("msp3400 thread: sleep\n");		msp34xx_sleep(msp,-1);		msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");	restart:		msp3400_dbg("thread: restart scan\n");		msp->restart = 0;		if (kthread_should_stop())			break;		if (VIDEO_MODE_RADIO == msp->norm ||		    MSP_MODE_EXTERN  == msp->mode) {			/* no carrier scan, just unmute */			msp3400_info("thread: no carrier scan\n");			msp3400c_setvolume(client, msp->muted, msp->left, msp->right);			continue;		}		/* mute */		msp3400c_setvolume(client, msp->muted, 0, 0);		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );		val1 = val2 = 0;		max1 = max2 = -1;		msp->watch_stereo = 0;		/* some time for the tuner to sync */		if (msp34xx_sleep(msp,200))			goto restart;		/* carrier detect pass #1 -- main carrier */		cd = carrier_detect_main;		count = CARRIER_COUNT(carrier_detect_main);		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {			/* autodetect doesn't work well with AM ... */			max1 = 3;			count = 0;			msp3400_dbg("AM sound override\n");		}		for (this = 0; this < count; this++) {			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);			if (msp34xx_sleep(msp,100))				goto restart;			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);			if (val > 32767)				val -= 65536;			if (val1 < val)				val1 = val, max1 = this;			msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);		}		/* carrier detect pass #2 -- second (stereo) carrier */		switch (max1) {		case 1: /* 5.5 */			cd = carrier_detect_55;			count = CARRIER_COUNT(carrier_detect_55);			break;		case 3: /* 6.5 */			cd = carrier_detect_65;			count = CARRIER_COUNT(carrier_detect_65);			break;		case 0: /* 4.5 */		case 2: /* 6.0 */		default:			cd = NULL;			count = 0;			break;		}		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {			/* autodetect doesn't work well with AM ... */			cd = NULL;			count = 0;			max2 = 0;		}		for (this = 0; this < count; this++) {			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);			if (msp34xx_sleep(msp,100))				goto restart;			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);			if (val > 32767)				val -= 65536;			if (val2 < val)				val2 = val, max2 = this;			msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);		}		/* programm the msp3400 according to the results */		msp->main   = carrier_detect_main[max1].cdo;		switch (max1) {		case 1: /* 5.5 */			if (max2 == 0) {				/* B/G FM-stereo */				msp->second = carrier_detect_55[max2].cdo;				msp3400c_setmode(client, MSP_MODE_FM_TERRA);				msp->nicam_on = 0;				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);				msp->watch_stereo = 1;			} else if (max2 == 1 && HAVE_NICAM(msp)) {				/* B/G NICAM */				msp->second = carrier_detect_55[max2].cdo;				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);				msp->nicam_on = 1;				msp3400c_setcarrier(client, msp->second, msp->main);				msp->watch_stereo = 1;			} else {				goto no_second;			}			break;		case 2: /* 6.0 */			/* PAL I NICAM */			msp->second = MSP_CARRIER(6.552);			msp3400c_setmode(client, MSP_MODE_FM_NICAM2);			msp->nicam_on = 1;			msp3400c_setcarrier(client, msp->second, msp->main);			msp->watch_stereo = 1;			break;		case 3: /* 6.5 */			if (max2 == 1 || max2 == 2) {				/* D/K FM-stereo */				msp->second = carrier_detect_65[max2].cdo;				msp3400c_setmode(client, MSP_MODE_FM_TERRA);				msp->nicam_on = 0;				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);				msp->watch_stereo = 1;			} else if (max2 == 0 &&				   msp->norm == VIDEO_MODE_SECAM) {				/* L NICAM or AM-mono */				msp->second = carrier_detect_65[max2].cdo;				msp3400c_setmode(client, MSP_MODE_AM_NICAM);				msp->nicam_on = 0;				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);				msp3400c_setcarrier(client, msp->second, msp->main);				/* volume prescale for SCART (AM mono input) */				msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);				msp->watch_stereo = 1;			} else if (max2 == 0 && HAVE_NICAM(msp)) {				/* D/K NICAM */				msp->second = carrier_detect_65[max2].cdo;				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);				msp->nicam_on = 1;				msp3400c_setcarrier(client, msp->second, msp->main);				msp->watch_stereo = 1;			} else {				goto no_second;			}			break;		case 0: /* 4.5 */		default:		no_second:			msp->second = carrier_detect_main[max1].cdo;			msp3400c_setmode(client, MSP_MODE_FM_TERRA);			msp->nicam_on = 0;			msp3400c_setcarrier(client, msp->second, msp->main);			msp->rxsubchans = V4L2_TUNER_SUB_MONO;			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);			break;		}		/* unmute */		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);		msp3400c_restore_dfp(client);		if (debug)			msp3400c_print_mode(client);		/* monitor tv audio mode */		while (msp->watch_stereo) {			if (msp34xx_sleep(msp,5000))				goto restart;			watch_stereo(client);		}	}	msp3400_dbg("thread: exit\n");	return 0;}/* ----------------------------------------------------------------------- *//* this one uses the automatic sound standard detection of newer           *//* msp34xx chip versions                                                   */static struct MODES {	int retval;	int main, second;	char *name;} modelist[] = {	{ 0x0000, 0, 0, "ERROR" },	{ 0x0001, 0, 0, "autodetect start" },	{ 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },	{ 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },	{ 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },	{ 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },	{ 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },	{ 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },	{ 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },	{ 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },	{ 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },	{ 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },	{ 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },	{ 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },	{ 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },	{ 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },	{ 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },	{ 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },	{ 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },	{     -1, 0, 0, NULL }, /* EOF */};static inline const char *msp34xx_standard_mode_name(int mode){	int i;	for (i = 0; modelist[i].name != NULL; i++)		if (modelist[i].retval == mode)			return modelist[i].name;	return "unknown";}static int msp34xx_modus(struct i2c_client *client, int norm){	switch (norm) {

⌨️ 快捷键说明

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