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

📄 msp3400.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
			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("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 (;;) {				current->state   = TASK_INTERRUPTIBLE;				schedule_timeout(HZ/10);				if (signal_pending(current))					goto done;				if (msp->restart)					goto restart;				/* check results */				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);				if (val < 0x07ff)					break;				dprintk("msp3410: detection still in progress\n");			}		}		for (i = 0; modelist[i].name != NULL; i++)			if (modelist[i].retval == val)				break;		dprintk("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("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 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;			/* scart routing */			msp3400c_set_scart(client,SCART_IN2,0);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);			break;		case 0x0003:			msp->mode   = MSP_MODE_FM_TERRA;			msp->stereo = VIDEO_SOUND_MONO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			break;		}				/* unmute */		msp3400c_setbass(client, msp->bass);		msp3400c_settreble(client, msp->treble);		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);		if (msp->watch_stereo)			mod_timer(&msp->wake_stereo, jiffies+HZ);		msp->active = 0;	}done:	dprintk("msp3410: thread: exit\n");	msp->active = 0;	msp->thread = NULL;	if(msp->notify != NULL)		up(msp->notify);	return 0;}/* ----------------------------------------------------------------------- */static int msp_attach(struct i2c_adapter *adap, int addr,		      unsigned short flags, 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 struct i2c_driver driver = {        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 = {	name:   "(unset)",        driver: &driver,};static int msp_attach(struct i2c_adapter *adap, int addr,		      unsigned short flags, int kind){	DECLARE_MUTEX_LOCKED(sem);	struct msp3400c *msp;        struct i2c_client *c;	int              rev1,rev2,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;	c->data = msp;	init_waitqueue_head(&msp->wq);	if (-1 == msp3400c_reset(c)) {		kfree(msp);		dprintk("msp3400: no chip found\n");		return -1;	}    	rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);	if (-1 != rev1)		rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);	if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {		kfree(msp);		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(client,I2C_MSP3400C_DFP, 0x0014, 0x1040);#endif	sprintf(c->name,"MSP34%02d%c-%c%d",		(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);	msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0;	if (simple == -1) {		/* default mode */		/* msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; */		msp->simple = ((rev1&0xff)+'@' > 'C');	} else {		/* use insmod option */		msp->simple = simple;	}	/* timer for stereo checking */	msp->wake_stereo.function = msp3400c_stereo_wake;	msp->wake_stereo.data     = (unsigned long)msp;	/* hello world :-) */	printk(KERN_INFO "msp34xx: init: chip=%s",c->name);	if (msp->nicam)		printk(", has NICAM support");	printk("\n");	/* startup control thread */	MOD_INC_USE_COUNT;	msp->notify = &sem;	kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread,		      (void *)c, 0);	down(&sem);	msp->notify = NULL;	wake_up_interruptible(&msp->wq);	/* update our own array */	for (i = 0; i < MSP3400_MAX; i++) {		if (NULL == msps[i]) {			msps[i] = c;			break;		}	}		/* done */        i2c_attach_client(c);	return 0;}static int msp_detach(struct i2c_client *client){	DECLARE_MUTEX_LOCKED(sem);	struct msp3400c *msp  = (struct msp3400c*)client->data;	int i;		/* shutdown control thread */	del_timer(&msp->wake_stereo);	if (msp->thread) 	{		msp->notify = &sem;		msp->rmmod = 1;		wake_up_interruptible(&msp->wq);		down(&sem);		msp->notify = NULL;	}    	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);	MOD_DEC_USE_COUNT;	return 0;}static int msp_probe(struct i2c_adapter *adap){	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))		return i2c_probe(adap, &addr_data, msp_attach);	return 0;}static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg){	struct msp3400c *msp  = (struct msp3400c*)client->data;        __u16           *sarg = arg;#if 0	int             *iarg = (int*)arg;#endif	switch (cmd) {	case AUDC_SET_INPUT:#if 1		/* hauppauge 44xxx scart switching */		switch (*sarg) {		case AUDIO_RADIO:			msp3400c_set_scart(client,SCART_IN2,0);			break;		case AUDIO_EXTERN:			msp3400c_set_scart(client,SCART_IN1,0);			break;		default:			if (*sarg & AUDIO_MUTE)				msp3400c_set_scart(client,SCART_MUTE,0);			break;		}#endif		break;	case AUDC_SET_RADIO:		msp->norm = VIDEO_MODE_RADIO;		msp->watch_stereo=0;		del_timer(&msp->wake_stereo);		dprintk("msp34xx: switching to radio mode\n");		if (msp->simple) {			/* the thread will do for us */			msp3400c_setvolume(client,msp->muted,0,0);			if (msp->active)				msp->restart = 1;			wake_up_interruptible(&msp->wq);		} 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);					}		break;	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	   kernel pointer here... */	case VIDIOCGAUDIO:	{		struct video_audio *va = arg;		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);		va->balance=(32768*MIN(msp->left,msp->right))/			(va->volume ? va->volume : 1);		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;		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;		msp3400c_setvolume(client,msp->muted,msp->left,msp->right);		msp3400c_setbass(client,msp->bass);		msp3400c_settreble(client,msp->treble);		if (va->mode != 0) {			msp->watch_stereo=0;			del_timer(&msp->wake_stereo);			msp->stereo = va->mode;			msp3400c_setstereo(client,va->mode);		}		break;	}	case VIDIOCSCHAN:	{		struct video_channel *vc = arg;				dprintk("msp34xx: switching to TV mode\n");		msp->norm = vc->norm;		break;	}	case VIDIOCSFREQ:	{		/* new channel -- kick audio carrier scan */		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);		break;	}	/* --- v4l2 ioctls --- */	/* NOT YET */#if 0	/* --- old, obsolete interface --- */	case AUDC_SET_TVNORM:		msp->norm = *iarg;		break;	case AUDC_SWITCH_MUTE:		/* channels switching step one -- mute */		msp->watch_stereo=0;		del_timer(&msp->wake_stereo);		msp3400c_setvolume(client,0,0);		break;	case AUDC_NEWCHANNEL:		/* channels switching step two -- trigger sound carrier scan */		msp->watch_stereo=0;		del_timer(&msp->wake_stereo);		if (msp->active)			msp->restart = 1;		wake_up_interruptible(&msp->wq);		break;	case AUDC_GET_VOLUME_LEFT:		*sarg = msp->left;		break;	case AUDC_GET_VOLUME_RIGHT:		*sarg = msp->right;		break;	case AUDC_SET_VOLUME_LEFT:		msp->left = *sarg;		msp3400c_setvolume(client,msp->left, msp->right);		break;	case AUDC_SET_VOLUME_RIGHT:		msp->right = *sarg;		msp3400c_setvolume(client,msp->left, msp->right);		break;	case AUDC_GET_BASS:		*sarg = msp->bass;		break;	case AUDC_SET_BASS:		msp->bass = *sarg;		msp3400c_setbass(client,msp->bass);		break;	case AUDC_GET_TREBLE:		*sarg = msp->treble;		break;	case AUDC_SET_TREBLE:		msp->treble = *sarg;		msp3400c_settreble(client,msp->treble);		break;	case AUDC_GET_STEREO:		        autodetect_stereo(client);	        *sarg = msp->stereo;				break;	case AUDC_SET_STEREO:		if (*sarg) {			msp->watch_stereo=0;			del_timer(&msp->wake_stereo);			msp->stereo = *sarg;			msp3400c_setstereo(client,*sarg);		}		break;	case AUDC_GET_DC:		if (msp->simple)			break; /* fixme */		*sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) +			 (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c));		break;#endif	default:		/* nothing */	}	return 0;}/* ----------------------------------------------------------------------- */int msp3400_init_module(void){	i2c_add_driver(&driver);	return 0;}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 + -