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

📄 msp3400.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		printk(" mode=simple");		thread_func = msp3410d_thread;		break;	case OPMODE_SIMPLER:		printk(" mode=simpler");		thread_func = msp34xxg_thread;		break;	}	printk("\n");	/* startup control thread if needed */	if (thread_func) {		msp->kthread = kthread_run(thread_func, client, "msp34xx");		if (NULL == msp->kthread)			msp3400_warn("kernel_thread() failed\n");		msp_wake_thread(client);	}	/* done */	i2c_attach_client(client);	/* update our own array */	for (i = 0; i < MSP3400_MAX; i++) {		if (NULL == msps[i]) {			msps[i] = client;			break;		}	}	return 0;}static int msp_detach(struct i2c_client *client){	struct msp3400c *msp  = i2c_get_clientdata(client);	int i;	/* shutdown control thread */	if (msp->kthread) {		msp->restart = 1;		kthread_stop(msp->kthread);	}	msp3400c_reset(client);	/* update our own array */	for (i = 0; i < MSP3400_MAX; i++) {		if (client == msps[i]) {			msps[i] = NULL;			break;		}	}	i2c_detach_client(client);	kfree(msp);	kfree(client);	return 0;}static int msp_probe(struct i2c_adapter *adap){	if (adap->class & I2C_CLASS_TV_ANALOG)		return i2c_probe(adap, &addr_data, msp_attach);	return 0;}static void msp_wake_thread(struct i2c_client *client){	struct msp3400c *msp  = i2c_get_clientdata(client);	if (NULL == msp->kthread)		return;	msp3400c_setvolume(client,msp->muted,0,0);	msp->watch_stereo = 0;	msp->restart = 1;	wake_up_interruptible(&msp->wq);}/* ----------------------------------------------------------------------- */static int mode_v4l2_to_v4l1(int rxsubchans){	int mode = 0;	if (rxsubchans & V4L2_TUNER_SUB_STEREO)		mode |= VIDEO_SOUND_STEREO;	if (rxsubchans & V4L2_TUNER_SUB_LANG2)		mode |= VIDEO_SOUND_LANG2;	if (rxsubchans & V4L2_TUNER_SUB_LANG1)		mode |= VIDEO_SOUND_LANG1;	if (0 == mode)		mode |= VIDEO_SOUND_MONO;	return mode;}static int mode_v4l1_to_v4l2(int mode){	if (mode & VIDEO_SOUND_STEREO)		return V4L2_TUNER_MODE_STEREO;	if (mode & VIDEO_SOUND_LANG2)		return V4L2_TUNER_MODE_LANG2;	if (mode & VIDEO_SOUND_LANG1)		return V4L2_TUNER_MODE_LANG1;	return V4L2_TUNER_MODE_MONO;}static void msp_any_detect_stereo(struct i2c_client *client){	struct msp3400c *msp  = i2c_get_clientdata(client);	switch (msp->opmode) {	case OPMODE_MANUAL:	case OPMODE_SIMPLE:		autodetect_stereo(client);		break;	case OPMODE_SIMPLER:		msp34xxg_detect_stereo(client);		break;	}}static void msp_any_set_audmode(struct i2c_client *client, int audmode){	struct msp3400c *msp  = i2c_get_clientdata(client);	switch (msp->opmode) {	case OPMODE_MANUAL:	case OPMODE_SIMPLE:		msp->watch_stereo = 0;		msp3400c_setstereo(client, audmode);		break;	case OPMODE_SIMPLER:		msp34xxg_set_audmode(client, audmode);		break;	}}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:		msp3400_dbg("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;			break;		default:			if (*sarg & AUDIO_MUTE)				msp3400c_set_scart(client,SCART_MUTE,0);			break;		}		if (scart) {			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->audmode = V4L2_TUNER_MODE_STEREO;			msp3400c_set_scart(client,scart,0);			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);			if (msp->opmode != OPMODE_SIMPLER)				msp3400c_setstereo(client, msp->audmode);		}		msp_wake_thread(client);		break;	case AUDC_SET_RADIO:		msp3400_dbg("AUDC_SET_RADIO\n");		msp->norm = VIDEO_MODE_RADIO;		msp3400_dbg("switching to radio mode\n");		msp->watch_stereo = 0;		switch (msp->opmode) {		case OPMODE_MANUAL:			/* 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);			break;		case OPMODE_SIMPLE:		case OPMODE_SIMPLER:			/* the thread will do for us */			msp_wake_thread(client);			break;		}		break;		/* work-in-progress:  hook to control the DFP registers */	case MSP_SET_DFPREG:	{		struct msp_dfpreg *r = arg;		int i;		if (r->reg < 0 || r->reg >= DFP_COUNT)			return -EINVAL;		for (i = 0; i < sizeof(bl_dfp) / sizeof(int); 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;	}	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	   kernel pointer here... */	case VIDIOCGAUDIO:	{		struct video_audio *va = arg;		msp3400_dbg("VIDIOCGAUDIO\n");		va->flags |= VIDEO_AUDIO_VOLUME |			VIDEO_AUDIO_BASS |			VIDEO_AUDIO_TREBLE |			VIDEO_AUDIO_MUTABLE;		if (msp->muted)			va->flags |= VIDEO_AUDIO_MUTE;		if (msp->muted)			va->flags |= VIDEO_AUDIO_MUTE;		va->volume = MAX(msp->left, msp->right);		va->balance = (32768 * MIN(msp->left, msp->right)) /		    (va->volume ? va->volume : 1);		va->balance = (msp->left < msp->right) ?		    (65535 - va->balance) : va->balance;		if (0 == va->volume)			va->balance = 32768;		va->bass = msp->bass;		va->treble = msp->treble;		msp_any_detect_stereo(client);		va->mode = mode_v4l2_to_v4l1(msp->rxsubchans);		break;	}	case VIDIOCSAUDIO:	{		struct video_audio *va = arg;		msp3400_dbg("VIDIOCSAUDIO\n");		msp->muted = (va->flags & VIDEO_AUDIO_MUTE);		msp->left = (MIN(65536 - va->balance, 32768) *			     va->volume) / 32768;		msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;		msp->bass = va->bass;		msp->treble = va->treble;		msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",			va->volume);		msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",			va->balance);		msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",			va->flags);		msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",			msp->left);		msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",			msp->right);		msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",			msp->bass);		msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",			msp->treble);		msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",			msp->mode);		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_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));		break;	}	case VIDIOCSCHAN:	{		struct video_channel *vc = arg;		msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);		msp->norm = vc->norm;		msp_wake_thread(client);		break;	}	case VIDIOCSFREQ:	case VIDIOC_S_FREQUENCY:	{		/* new channel -- kick audio carrier scan */		msp3400_dbg("VIDIOCSFREQ\n");		msp_wake_thread(client);		break;	}	/* msp34xx specific */	case MSP_SET_MATRIX:	{		struct msp_matrix *mspm = arg;		msp3400_dbg("MSP_SET_MATRIX\n");		msp3400c_set_scart(client, mspm->input, mspm->output);		break;	}	/* --- v4l2 ioctls --- */	case VIDIOC_S_STD:	{		v4l2_std_id *id = arg;		/*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/		if (*id & V4L2_STD_PAL) {			msp->norm=VIDEO_MODE_PAL;		} else if (*id & V4L2_STD_SECAM) {			msp->norm=VIDEO_MODE_SECAM;		} else {			msp->norm=VIDEO_MODE_NTSC;		}		msp_wake_thread(client);		return 0;	}	case VIDIOC_ENUMINPUT:	{		struct v4l2_input *i = arg;		if (i->index != 0)			return -EINVAL;		i->type = V4L2_INPUT_TYPE_TUNER;		switch (i->index) {		case AUDIO_RADIO:			strcpy(i->name,"Radio");			break;		case AUDIO_EXTERN_1:			strcpy(i->name,"Extern 1");			break;		case AUDIO_EXTERN_2:			strcpy(i->name,"Extern 2");			break;		case AUDIO_TUNER:			strcpy(i->name,"Television");			break;		default:			return -EINVAL;		}		return 0;	}	case VIDIOC_G_AUDIO:	{		struct v4l2_audio *a = arg;		memset(a,0,sizeof(*a));		switch (a->index) {		case AUDIO_RADIO:			strcpy(a->name,"Radio");			break;		case AUDIO_EXTERN_1:			strcpy(a->name,"Extern 1");			break;		case AUDIO_EXTERN_2:			strcpy(a->name,"Extern 2");			break;		case AUDIO_TUNER:			strcpy(a->name,"Television");			break;		default:			return -EINVAL;		}		msp_any_detect_stereo(client);		if (msp->audmode == V4L2_TUNER_MODE_STEREO) {			a->capability=V4L2_AUDCAP_STEREO;		}		break;	}	case VIDIOC_S_AUDIO:	{		struct v4l2_audio *sarg = arg;		switch (sarg->index) {		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;			break;		}		if (scart) {			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->audmode = V4L2_TUNER_MODE_STEREO;			msp3400c_set_scart(client,scart,0);			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);		}		if (sarg->capability==V4L2_AUDCAP_STEREO) {			msp->audmode = V4L2_TUNER_MODE_STEREO;		} else {			msp->audmode &= ~V4L2_TUNER_MODE_STEREO;		}		msp_any_set_audmode(client, msp->audmode);		msp_wake_thread(client);		break;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *vt = arg;		msp_any_detect_stereo(client);		vt->audmode    = msp->audmode;		vt->rxsubchans = msp->rxsubchans;		vt->capability = V4L2_TUNER_CAP_STEREO |			V4L2_TUNER_CAP_LANG1|			V4L2_TUNER_CAP_LANG2;		break;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;		/* only set audmode */		if (vt->audmode != -1 && vt->audmode != 0)			msp_any_set_audmode(client, vt->audmode);		break;	}	case VIDIOC_G_AUDOUT:	{		struct v4l2_audioout *a=(struct v4l2_audioout *)arg;		int idx=a->index;		memset(a,0,sizeof(*a));		switch (idx) {		case 0:			strcpy(a->name,"Scart1 Out");			break;		case 1:			strcpy(a->name,"Scart2 Out");			break;		case 2:			strcpy(a->name,"I2S Out");			break;		default:			return -EINVAL;		}		break;	}	case VIDIOC_S_AUDOUT:	{		struct v4l2_audioout *a=(struct v4l2_audioout *)arg;		if (a->index<0||a->index>2)			return -EINVAL;		if (a->index==2) {			if (a->mode == V4L2_AUDMODE_32BITS)				msp->i2s_mode=1;			else				msp->i2s_mode=0;		}		msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",						a->index,msp->i2s_mode);		msp3400c_set_scart(client,msp->in_scart,a->index+1);		break;	}	default:		/* nothing */		break;	}	return 0;}static int msp_suspend(struct device * dev, pm_message_t state){	struct i2c_client *client = container_of(dev, struct i2c_client, dev);	msp3400_dbg("msp34xx: suspend\n");	msp3400c_reset(client);	return 0;}static int msp_resume(struct device * dev){	struct i2c_client *client = container_of(dev, struct i2c_client, dev);	msp3400_dbg("msp34xx: resume\n");	msp_wake_thread(client);	return 0;}/* ----------------------------------------------------------------------- */static int __init msp3400_init_module(void){	return i2c_add_driver(&driver);}static void __exit 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 + -