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

📄 msp3400.c

📁 该代码是天敏电视卡天敏大师4的核心芯片在linux下面的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			break;		case VIDEO_MODE_NTSC:  /* BTSC */			mode = 0x2003;			std  = 0x0020;			break;		case VIDEO_MODE_SECAM: 			mode = 0x0003;			std  = 1;			break;		case VIDEO_MODE_RADIO:			mode = 0x0003;			std  = 0x0040;			break;		default:			mode = 0x0003;			std  = 1;			break;		}		msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);		msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);		if (debug) {			int i;			for (i = 0; modelist[i].name != NULL; i++)				if (modelist[i].retval == std)					break;			printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",			       modelist[i].name ? modelist[i].name : "unknown",std);		}		if (std != 1) {			/* programmed some specific mode */			val = std;		} else {			/* triggered autodetect */			for (;;) {				if (msp34xx_sleep(msp,HZ/10))					goto done;				if (msp->restart)					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->stereo = VIDEO_SOUND_STEREO;			msp->nicam_on = 1;			msp->watch_stereo = 1;			msp3400c_setstereo(client,VIDEO_SOUND_STEREO);			break;		case 0x0009:						msp->mode = MSP_MODE_AM_NICAM;			msp->stereo = VIDEO_SOUND_MONO;			msp->nicam_on = 1;			msp3400c_setstereo(client,VIDEO_SOUND_MONO);			msp->watch_stereo = 1;			break;		case 0x0020: /* BTSC */			/* just turn on stereo */			msp->mode   = MSP_MODE_BTSC;			msp->stereo = VIDEO_SOUND_STEREO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			msp3400c_setstereo(client,VIDEO_SOUND_STEREO);			break;		case 0x0040: /* FM radio */			msp->mode   = MSP_MODE_FM_RADIO;			msp->stereo = VIDEO_SOUND_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->stereo = VIDEO_SOUND_MONO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			break;		}				/* unmute + restore dfp registers */		msp3400c_setbass(client, msp->bass);		msp3400c_settreble(client, msp->treble);		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);		msp3400c_restore_dfp(client);		if (msp->watch_stereo)			mod_timer(&msp->wake_stereo, jiffies+HZ);		msp->active = 0;	}done:	msp->active = 0;	dprintk(KERN_DEBUG "msp3410: thread: exit\n");        complete_and_exit(&msp->texit, 0);	return 0;}/* ----------------------------------------------------------------------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int msp_attach(struct i2c_adapter *adap, int addr, int kind);#elsestatic int msp_attach(struct i2c_adapter *adap, int addr,		      unsigned short flags, int kind);#endifstatic int msp_detach(struct i2c_client *client);static int msp_probe(struct i2c_adapter *adap);static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);static struct i2c_driver driver = {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	.owner          = THIS_MODULE,#endif        .name           = "i2c msp3400 driver",        .id             = I2C_DRIVERID_MSP3400,        .flags          = I2C_DF_NOTIFY,        .attach_adapter = msp_probe,        .detach_client  = msp_detach,        .command        = msp_command,};static struct i2c_client client_template = {	I2C_DEVNAME("(unset)"),	.flags     = I2C_CLIENT_ALLOW_USE,        .driver    = &driver,};#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int msp_attach(struct i2c_adapter *adap, int addr, int kind)#elsestatic int msp_attach(struct i2c_adapter *adap, int addr,		      unsigned short flags, int kind)#endif{	struct msp3400c *msp;        struct i2c_client *c;	int i;        client_template.adapter = adap;        client_template.addr = addr;        if (-1 == msp3400c_reset(&client_template)) {                dprintk("msp3400: no chip found\n");                return -1;        }	        if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))                return -ENOMEM;        memcpy(c,&client_template,sizeof(struct i2c_client));	if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {		kfree(c);		return -ENOMEM;	}		memset(msp,0,sizeof(struct msp3400c));	msp->left   = 65535;	msp->right  = 65535;	msp->bass   = 32768;	msp->treble = 32768;	msp->input  = -1;	msp->muted  = 1;	for (i = 0; i < DFP_COUNT; i++)		msp->dfp_regs[i] = -1;	i2c_set_clientdata(c, msp);	init_waitqueue_head(&msp->wq);	if (-1 == msp3400c_reset(c)) {		kfree(msp);		kfree(c);		dprintk("msp3400: no chip found\n");		return -1;	}    	msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);	if (-1 != msp->rev1)		msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);	if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {		kfree(msp);		kfree(c);		printk("msp3400: error while reading chip version\n");		return -1;	}#if 0	/* this will turn on a 1kHz beep - might be useful for debugging... */	msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040);#endif	msp3400c_setvolume(c,msp->muted,msp->left,msp->right);	snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d",		 (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',		 ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);	if (simple == -1) {		/* default mode */		msp->simple = HAVE_SIMPLE(msp);	} else {		/* use insmod option */		msp->simple = simple;	}	/* timer for stereo checking */	init_timer(&msp->wake_stereo);	msp->wake_stereo.function = msp3400c_stereo_wake;	msp->wake_stereo.data     = (unsigned long)msp;	/* hello world :-) */	printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c));	if (HAVE_NICAM(msp))		printk(" +nicam");	if (HAVE_SIMPLE(msp))		printk(" +simple");	if (HAVE_RADIO(msp))		printk(" +radio");	printk("\n");	/* startup control thread */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	MOD_INC_USE_COUNT;#endif	init_completion(&msp->texit);	msp->tpid = kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread,				  (void *)c, 0);	if (msp->tpid < 0)		printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");	wake_up_interruptible(&msp->wq);	/* done */        i2c_attach_client(c);	return 0;}static int msp_detach(struct i2c_client *client){	struct msp3400c *msp  = i2c_get_clientdata(client);		/* shutdown control thread */	del_timer_sync(&msp->wake_stereo);	if (msp->tpid >= 0) {		msp->rmmod = 1;		wake_up_interruptible(&msp->wq);		wait_for_completion(&msp->texit);	}    	msp3400c_reset(client);	i2c_detach_client(client);	kfree(msp);	kfree(client);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	MOD_DEC_USE_COUNT;#endif	return 0;}static int msp_probe(struct i2c_adapter *adap){#ifdef I2C_ADAP_CLASS_TV_ANALOG	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)		return i2c_probe(adap, &addr_data, msp_attach);#else	switch (adap->id) {	case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3:	case I2C_ALGO_BIT | I2C_HW_B_BT848:	//case I2C_ALGO_SAA7134:		return i2c_probe(adap, &addr_data, msp_attach);		break;	}#endif	return 0;}static void msp_wake_thread(struct i2c_client *client){	struct msp3400c *msp  = i2c_get_clientdata(client);	msp3400c_setvolume(client,msp->muted,0,0);	msp->watch_stereo=0;	del_timer(&msp->wake_stereo);	if (msp->active)		msp->restart = 1;	wake_up_interruptible(&msp->wq);}static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg){	struct msp3400c *msp  = i2c_get_clientdata(client);        __u16           *sarg = arg;	int scart = 0;	switch (cmd) {	case AUDC_SET_INPUT:		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);		if (*sarg == msp->input)			break;		msp->input = *sarg;		switch (*sarg) {		case AUDIO_RADIO:			/* Hauppauge uses IN2 for the radio */			msp->mode   = MSP_MODE_FM_RADIO;			scart       = SCART_IN2;			break;		case AUDIO_EXTERN_1:			/* IN1 is often used for external input ... */			msp->mode   = MSP_MODE_EXTERN;			scart       = SCART_IN1;			break;		case AUDIO_EXTERN_2:			/* ... sometimes it is IN2 through ;) */			msp->mode   = MSP_MODE_EXTERN;			scart       = SCART_IN2;			break;		case AUDIO_TUNER:			msp->mode   = -1;			msp_wake_thread(client);			break;		default:			if (*sarg & AUDIO_MUTE)				msp3400c_set_scart(client,SCART_MUTE,0);			break;		}		if (scart) {			msp->stereo = VIDEO_SOUND_STEREO;			msp3400c_set_scart(client,scart,0);			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);			msp3400c_setstereo(client,msp->stereo);		}		if (msp->active)			msp->restart = 1;		break;	case AUDC_SET_RADIO:		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n");		msp->norm = VIDEO_MODE_RADIO;		msp->watch_stereo=0;		del_timer(&msp->wake_stereo);		dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");		if (msp->simple) {			/* the thread will do for us */			msp_wake_thread(client);		} else {			/* set msp3400 to FM radio mode */			msp3400c_setmode(client,MSP_MODE_FM_RADIO);			msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7));			msp3400c_setvolume(client,msp->muted,msp->left,msp->right);					}		if (msp->active)			msp->restart = 1;		break;#if 1	/* work-in-progress:  hook to control the DFP registers */	case MSP_SET_DFPREG:	{		struct msp_dfpreg *r = arg;		unsigned int i;		if (r->reg < 0 || r->reg >= DFP_COUNT)			return -EINVAL;		for (i = 0; i < ARRAY_SIZE(bl_dfp); i++)			if (r->reg == bl_dfp[i])				return -EINVAL;		msp->dfp_regs[r->reg] = r->value;		msp3400c_write(client,I2C_MSP3400C_DFP,r->reg,r->value);		return 0;	}	case MSP_GET_DFPREG:	{		struct msp_dfpreg *r = arg;		if (r->reg < 0 || r->reg >= DFP_COUNT)			return -EINVAL;		r->value = msp3400c_read(client,I2C_MSP3400C_DFP,r->reg);		return 0;	}#endif	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	   kernel pointer here... */	case VIDIOCGAUDIO:	{		struct video_audio *va = arg;		dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n");		va->flags |= VIDEO_AUDIO_VOLUME |			VIDEO_AUDIO_BASS |			VIDEO_AUDIO_TREBLE |			VIDEO_AUDIO_MUTABLE;		if (msp->muted)			va->flags |= VIDEO_AUDIO_MUTE;		va->volume=max(msp->left,msp->right);		if (0 == va->volume) {			va->balance = 32768;		} else {			va->balance = (32768 * min(msp->left,msp->right))				/ va->volume;			va->balance = (msp->left<msp->right) ?				(65535 - va->balance) : va->balance;		}		va->bass = msp->bass;		va->treble = msp->treble;		if (msp->norm != VIDEO_MODE_RADIO) {			autodetect_stereo(client);			va->mode = msp->stereo;		}		break;	}	case VIDIOCSAUDIO:	{		struct video_audio *va = arg;		dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n");		msp->muted = (va->flags & VIDEO_AUDIO_MUTE);		msp->left = (min(65536 - va->balance,32768) *			     va->volume) / 32768;		msp->right = (min(va->balance,(__u16)32768) *			      va->volume) / 32768;		msp->bass = va->bass;		msp->treble = va->treble;		msp3400c_setvolume(client,msp->muted,msp->left,msp->right);		msp3400c_setbass(client,msp->bass);		msp3400c_settreble(client,msp->treble);		if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO) {			msp->watch_stereo=0;			del_timer(&msp->wake_stereo);			msp->stereo = va->mode & 0x0f;			msp3400c_setstereo(client,va->mode & 0x0f);		}		break;	}	case VIDIOCSCHAN:	{		struct video_channel *vc = arg;				dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm);		msp->norm = vc->norm;		break;	}	case VIDIOCSFREQ:	{		/* new channel -- kick audio carrier scan */		dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n");		msp_wake_thread(client);		break;	}	default:		/* nothing */		break;	}	return 0;}/* ----------------------------------------------------------------------- */static int msp3400_init_module(void){	i2c_add_driver(&driver);	return 0;}static void msp3400_cleanup_module(void){	i2c_del_driver(&driver);}module_init(msp3400_init_module);module_exit(msp3400_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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -