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

📄 msp3400.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
			msp3400c_print_mode(msp);		/* monitor tv audio mode */		while (msp->watch_stereo) {			if (msp34xx_sleep(msp,5000))				goto restart;			watch_stereo(client);		}	}	dprintk(KERN_DEBUG "msp3400: 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(int norm){	switch (norm) {	case VIDEO_MODE_PAL:		return 0x1003;	case VIDEO_MODE_NTSC:  /* BTSC */		return 0x2003;	case VIDEO_MODE_SECAM:		return 0x0003;	case VIDEO_MODE_RADIO:		return 0x0003;	case VIDEO_MODE_AUTO:		return 0x2003;	default:		return 0x0003;	}}static int msp34xx_standard(int norm){	switch (norm) {	case VIDEO_MODE_PAL:		return 1;	case VIDEO_MODE_NTSC:  /* BTSC */		return 0x0020;	case VIDEO_MODE_SECAM:		return 1;	case VIDEO_MODE_RADIO:		return 0x0040;	default:		return 1;	}}static int msp3410d_thread(void *data){	struct i2c_client *client = data;	struct msp3400c *msp = i2c_get_clientdata(client);	int mode,val,i,std;	printk("msp3410: daemon started\n");	for (;;) {		d2printk(KERN_DEBUG "msp3410: thread: sleep\n");		msp34xx_sleep(msp,-1);		d2printk(KERN_DEBUG "msp3410: thread: wakeup\n");	restart:		dprintk("msp3410: thread: restart scan\n");		msp->restart = 0;		if (kthread_should_stop())			break;		if (msp->mode == MSP_MODE_EXTERN) {			/* no carrier scan needed, just unmute */			dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");			msp3400c_setvolume(client, msp->muted,					   msp->volume, msp->balance);			continue;		}		/* put into sane state (and mute) */		msp3400c_reset(client);		/* some time for the tuner to sync */		if (msp34xx_sleep(msp,200))			goto restart;		/* start autodetect */		mode = msp34xx_modus(msp->norm);		std  = msp34xx_standard(msp->norm);		msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);		msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);		msp->watch_stereo = 0;		if (debug)			printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",			       msp34xx_standard_mode_name(std) ,std);		if (std != 1) {			/* programmed some specific mode */			val = std;		} else {			/* triggered autodetect */			for (;;) {				if (msp34xx_sleep(msp,100))					goto restart;				/* check results */				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);				if (val < 0x07ff)					break;				dprintk(KERN_DEBUG "msp3410: detection still in progress\n");			}		}		for (i = 0; modelist[i].name != NULL; i++)			if (modelist[i].retval == val)				break;		dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",			modelist[i].name ? modelist[i].name : "unknown",			val);		msp->main   = modelist[i].main;		msp->second = modelist[i].second;		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {			/* autodetection has failed, let backup */			dprintk(KERN_DEBUG "msp3410: autodetection failed,"				" switching to backup mode: %s (0x%04x)\n",				modelist[8].name ? modelist[8].name : "unknown",val);			val = 0x0009;			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);		}		/* set various prescales */		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */		msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */		/* set stereo */		switch (val) {		case 0x0008: /* B/G NICAM */		case 0x000a: /* I NICAM */			if (val == 0x0008)				msp->mode = MSP_MODE_FM_NICAM1;			else				msp->mode = MSP_MODE_FM_NICAM2;			/* just turn on stereo */			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->nicam_on = 1;			msp->watch_stereo = 1;			msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);			break;		case 0x0009:			msp->mode = MSP_MODE_AM_NICAM;			msp->rxsubchans = V4L2_TUNER_SUB_MONO;			msp->nicam_on = 1;			msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO);			msp->watch_stereo = 1;			break;		case 0x0020: /* BTSC */			/* just turn on stereo */			msp->mode = MSP_MODE_BTSC;			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);			break;		case 0x0040: /* FM radio */			msp->mode   = MSP_MODE_FM_RADIO;			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->audmode = V4L2_TUNER_MODE_STEREO;			msp->nicam_on = 0;			msp->watch_stereo = 0;			/* not needed in theory if HAVE_RADIO(), but			   short programming enables carrier mute */			msp3400c_setmode(client,MSP_MODE_FM_RADIO);			msp3400c_setcarrier(client, MSP_CARRIER(10.7),					    MSP_CARRIER(10.7));			/* scart routing */			msp3400c_set_scart(client,SCART_IN2,0);#if 0			/* radio from SCART_IN2 */			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220);#else			/* msp34xx does radio decoding */			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);#endif			break;		case 0x0003:		case 0x0004:		case 0x0005:			msp->mode   = MSP_MODE_FM_TERRA;			msp->rxsubchans = V4L2_TUNER_SUB_MONO;			msp->audmode = V4L2_TUNER_MODE_MONO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			break;		}		/* unmute, restore misc registers */		msp3400c_setbass(client, msp->bass);		msp3400c_settreble(client, msp->treble);		msp3400c_setvolume(client, msp->muted,				    msp->volume, msp->balance);		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb);		/* monitor tv audio mode */		while (msp->watch_stereo) {			if (msp34xx_sleep(msp,5000))				goto restart;			watch_stereo(client);		}	}	dprintk(KERN_DEBUG "msp3410: thread: exit\n");	return 0;}/* ----------------------------------------------------------------------- *//* msp34xxG + (simpler no-thread)                                          *//* this one uses both automatic standard detection and automatic sound     *//* select which are available in the newer G versions                      *//* struct msp: only norm, acb and source are really used in this mode      */static void msp34xxg_set_source(struct i2c_client *client, int source);/* (re-)initialize the msp34xxg, according to the current norm in msp->norm * return 0 if it worked, -1 if it failed */static int msp34xxg_init(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	int modus,std;	if (msp3400c_reset(client))		return -1;	/* make sure that input/output is muted (paranoid mode) */	if (msp3400c_write(client,			   I2C_MSP3400C_DFP,			   0x13, /* ACB */			   0x0f20 /* mute DSP input, mute SCART 1 */))		return -1;	/* step-by-step initialisation, as described in the manual */	modus = msp34xx_modus(msp->norm);	std   = msp34xx_standard(msp->norm);	modus &= ~0x03; /* STATUS_CHANGE=0 */	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION=1 */	if (msp3400c_write(client,			   I2C_MSP3400C_DEM,			   0x30/*MODUS*/,			   modus))		return -1;	if (msp3400c_write(client,			   I2C_MSP3400C_DEM,			   0x20/*stanard*/,			   std))		return -1;	/* write the dfps that may have an influence on	   standard/audio autodetection right now */	msp34xxg_set_source(client, msp->source);	if (msp3400c_write(client, I2C_MSP3400C_DFP,			   0x0e, /* AM/FM Prescale */			   0x3000 /* default: [15:8] 75khz deviation */))		return -1;	if (msp3400c_write(client, I2C_MSP3400C_DFP,			   0x10, /* NICAM Prescale */			   0x5a00 /* default: 9db gain (as recommended) */))		return -1;	if (msp3400c_write(client,			   I2C_MSP3400C_DEM,			   0x20, /* STANDARD SELECT  */			   standard /* default: 0x01 for automatic standard select*/))		return -1;	return 0;}static int msp34xxg_thread(void *data){	struct i2c_client *client = data;	struct msp3400c *msp = i2c_get_clientdata(client);	int val, std, i;	printk("msp34xxg: daemon started\n");	for (;;) {		d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n");		msp34xx_sleep(msp,-1);		d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n");	restart:		dprintk("msp34xxg: thread: restart scan\n");		msp->restart = 0;		if (kthread_should_stop())			break;		/* setup the chip*/		msp34xxg_init(client);		std = standard;		if (std != 0x01)			goto unmute;		/* watch autodetect */		dprintk("msp34xxg: triggered autodetect, waiting for result\n");		for (i = 0; i < 10; i++) {			if (msp34xx_sleep(msp,100))				goto restart;			/* check results */			val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);			if (val < 0x07ff) {				std = val;				break;			}			dprintk("msp34xxg: detection still in progress\n");		}		if (0x01 == std) {			dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n");			continue;		}	unmute:		dprintk("msp34xxg: current mode: %s (0x%04x)\n",			msp34xx_standard_mode_name(std), std);		/* unmute: dispatch sound to scart output, set scart volume */		dprintk("msp34xxg: unmute\n");		msp3400c_setbass(client, msp->bass);		msp3400c_settreble(client, msp->treble);		msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance);		/* restore ACB */		if (msp3400c_write(client,				   I2C_MSP3400C_DFP,				   0x13, /* ACB */				   msp->acb))			return -1;	}	dprintk(KERN_DEBUG "msp34xxg: thread: exit\n");	return 0;}/* set the same 'source' for the loudspeaker, scart and quasi-peak detector * the value for source is the same as bit 15:8 of DFP registers 0x08, * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B * * this function replaces msp3400c_setstereo */static void msp34xxg_set_source(struct i2c_client *client, int source){	struct msp3400c *msp = i2c_get_clientdata(client);	/* fix matrix mode to stereo and let the msp choose what	 * to output according to 'source', as recommended	 */	int value = (source&0x07)<<8|(source==0 ? 0x00:0x20);	dprintk("msp34xxg: set source to %d (0x%x)\n", source, value);	msp3400c_write(client,		       I2C_MSP3400C_DFP,		       0x08, /* Loudspeaker Output */		       value);	msp3400c_write(client,		       I2C_MSP3400C_DFP,		       0x0a, /* SCART1 DA Output */		       value);	msp3400c_write(client,		       I2C_MSP3400C_DFP,		       0x0c, /* Quasi-peak detector */		       value);	/*	 * set identification threshold. Personally, I	 * I set it to a higher value that the default	 * of 0x190 to ignore noisy stereo signals.	 * this needs tuning. (recommended range 0x00a0-0x03c0)	 * 0x7f0 = forced mono mode	 */	msp3400c_write(client,		       I2C_MSP3400C_DEM,		       0x22, /* a2 threshold for stereo/bilingual */		       source==0 ? 0x7f0:stereo_threshold);	msp->source=source;}static void msp34xxg_detect_stereo(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	int status = msp3400c_read(client,				   I2C_MSP3400C_DEM,				   0x0200 /* STATUS */);	int is_bilingual = status&0x100;	int is_stereo = status&0x40;	msp->rxsubchans = 0;	if (is_stereo)		msp->rxsubchans |= V4L2_TUNER_SUB_STEREO;	else		msp->rxsubchans |= V4L2_TUNER_SUB_MONO;	if (is_bilingual) {		msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2;		/* I'm supposed to check whether it's SAP or not		 * and set only LANG2/SAP in this case. Yet, the MSP		 * does a lot of work to hide this and handle everything		 * the same way. I don't want to work around it so unless		 * this is a problem, I'll handle SAP just like lang1/lang2.		 */	}	dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",		status, is_stereo, is_bilingual, msp->rxsubchans);}static void msp34xxg_set_audmode(struct i2c_client *client, int audmode){	struct msp3400c *msp = i2c_get_clientdata(client);	int source = 0;	switch (audmode) {	case V4L2_TUNER_MODE_MONO:		source=0; /* mono only */		break;	case V4L2_TUNER_MODE_STEREO:		source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */		/* problem: that could also mean 2 (scart input) */		break;	case V4L2_TUNER_MODE_LANG1:		source=3; /* stereo or A */		break;	case V4L2_TUNER_MODE_LANG2:		source=4; /* stereo or B */

⌨️ 快捷键说明

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