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

📄 msp3400.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
		break;	default: /* doing nothing: a safe, sane default */		audmode = 0;		return;	}	msp->audmode = audmode;	msp34xxg_set_source(client, source);}/* ----------------------------------------------------------------------- */static int msp_attach(struct i2c_adapter *adap, int addr, int kind);static 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 int msp_suspend(struct device * dev, u32 state, u32 level);static int msp_resume(struct device * dev, u32 level);static void msp_wake_thread(struct i2c_client *client);static struct i2c_driver driver = {	.owner          = THIS_MODULE,	.name           = "i2c msp3400 driver",        .id             = I2C_DRIVERID_MSP3400,        .flags          = I2C_DF_NOTIFY,        .attach_adapter = msp_probe,        .detach_client  = msp_detach,        .command        = msp_command,	.driver = {		.suspend = msp_suspend,		.resume  = msp_resume,	},};static struct i2c_client client_template ={	I2C_DEVNAME("(unset)"),	.flags     = I2C_CLIENT_ALLOW_USE,        .driver    = &driver,};static int msp_attach(struct i2c_adapter *adap, int addr, int kind){	struct msp3400c *msp;        struct i2c_client *c;	int (*thread_func)(void *data) = NULL;        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->volume  = 58880;  /* 0db gain */	msp->balance = 32768;	msp->bass    = 32768;	msp->treble  = 32768;	msp->input   = -1;	msp->muted   = 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->volume, msp->balance);	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);	msp->opmode = opmode;	if (OPMODE_AUTO == msp->opmode) {#if 0 /* seems to work for ivtv only, disable by default for now ... */		if (HAVE_SIMPLER(msp))			msp->opmode = OPMODE_SIMPLER;		else#endif		if (HAVE_SIMPLE(msp))			msp->opmode = OPMODE_SIMPLE;		else			msp->opmode = OPMODE_MANUAL;	}	/* 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_SIMPLER(msp))		printk(" +simpler");	if (HAVE_RADIO(msp))		printk(" +radio");	/* version-specific initialization */	switch (msp->opmode) {	case OPMODE_MANUAL:		printk(" mode=manual");		thread_func = msp3400c_thread;		break;	case OPMODE_SIMPLE:		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, c, "msp34xx");		if (NULL == msp->kthread)			printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");		msp_wake_thread(c);	}	/* 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 */	if (msp->kthread >= 0) {		msp->restart = 1;		kthread_stop(msp->kthread);	}    	msp3400c_reset(client);	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_set_audmode(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:		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;			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_set_audmode(client, msp->audmode);		}		msp_wake_thread(client);		break;	case AUDC_SET_RADIO:		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n");		msp->norm = VIDEO_MODE_RADIO;		dprintk(KERN_DEBUG "msp34xx: 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->volume, msp->balance);			break;		case OPMODE_SIMPLE:		case OPMODE_SIMPLER:			/* the thread will do for us */			msp_wake_thread(client);			break;		}		break;	/* --- 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 = msp->volume;		va->balance = (va->volume) ? msp->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;		dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n");		msp->muted = (va->flags & VIDEO_AUDIO_MUTE);		msp->volume = va->volume;		msp->balance = va->balance;		msp->bass = va->bass;		msp->treble = va->treble;		msp3400c_setvolume(client, msp->muted,				   msp->volume, msp->balance);		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;		dprintk(KERN_DEBUG "msp34xx: 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 */		dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n");		msp_wake_thread(client);		break;	}	/* --- v4l2 ioctls --- */	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;	}	/* msp34xx specific */	case MSP_SET_MATRIX:	{		struct msp_matrix *mspm = arg;		dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n");		msp3400c_set_scart(client, mspm->input, mspm->output);		break;	}	default:		/* nothing */		break;	}	return 0;}static int msp_suspend(struct device * dev, u32 state, u32 level){	struct i2c_client *c = container_of(dev, struct i2c_client, dev);	dprintk("msp34xx: suspend\n");	msp3400c_reset(c);	return 0;}static int msp_resume(struct device * dev, u32 level){	struct i2c_client *c = container_of(dev, struct i2c_client, dev);	dprintk("msp34xx: resume\n");	msp_wake_thread(c);	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 + -