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

📄 msp3400.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
static struct msp3400c *mspmix = NULL;  /* ugly hack, should do something more sensible */static int mixer_num;static int mixer_modcnt = 0;static struct semaphore mixer_sem = MUTEX;static int mix_to_v4l(int i){	int r;	r = ((i & 0xff) * 65536 + 50) / 100;	if (r > 65535) r = 65535;	if (r <     0) r =     0;	return r;}static int v4l_to_mix(int i){	int r;	r = (i * 100 + 32768) / 65536;	if (r > 100) r = 100;	if (r <   0) r =   0;	return r | (r << 8);}static int v4l_to_mix2(int l, int r){	r = (r * 100 + 32768) / 65536;	if (r > 100) r = 100;	if (r <   0) r =   0;	l = (l * 100 + 32768) / 65536;	if (l > 100) l = 100;	if (l <   0) l =   0;	return (r << 8) | l;}static intmsp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	int ret,val = 0;	LOCK_FLAGS;        if (cmd == SOUND_MIXER_INFO) {                mixer_info info;                strncpy(info.id, "MSP3400", sizeof(info.id));                strncpy(info.name, "MSP 3400", sizeof(info.name));                info.modify_counter = mixer_modcnt;                if (copy_to_user((void *)arg, &info, sizeof(info)))                        return -EFAULT;                return 0;        }        if (cmd == SOUND_OLD_MIXER_INFO) {                _old_mixer_info info;                strncpy(info.id, "MSP3400", sizeof(info.id));                strncpy(info.name, "MSP 3400", sizeof(info.name));                if (copy_to_user((void *)arg, &info, sizeof(info)))                        return -EFAULT;                return 0;        }        if (cmd == OSS_GETVERSION)                return put_user(SOUND_VERSION, (int *)arg);	if (_SIOC_DIR(cmd) & _SIOC_WRITE)		if (get_user(val, (int *)arg))			return -EFAULT;    	down(&mixer_sem);	if (!mspmix) {		up(&mixer_sem);		return -ENODEV;	}	switch (cmd) {	case MIXER_READ(SOUND_MIXER_RECMASK):	case MIXER_READ(SOUND_MIXER_CAPS):	case MIXER_READ(SOUND_MIXER_RECSRC):	case MIXER_WRITE(SOUND_MIXER_RECSRC):		ret = 0;		break;	case MIXER_READ(SOUND_MIXER_STEREODEVS):		ret = SOUND_MASK_VOLUME;		break;	case MIXER_READ(SOUND_MIXER_DEVMASK):		ret = SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE;		break;	case MIXER_WRITE(SOUND_MIXER_VOLUME):		mspmix->left  = mix_to_v4l(val);		mspmix->right = mix_to_v4l(val >> 8);		LOCK_I2C_BUS(mspmix->bus);		msp3400c_setvolume(mspmix->bus,mspmix->left,mspmix->right);		UNLOCK_I2C_BUS(mspmix->bus);		mixer_modcnt++;		/* fall */	case MIXER_READ(SOUND_MIXER_VOLUME):		ret = v4l_to_mix2(mspmix->left, mspmix->right);		break;	case MIXER_WRITE(SOUND_MIXER_BASS):		mspmix->bass = mix_to_v4l(val);		LOCK_I2C_BUS(mspmix->bus);		msp3400c_setbass(mspmix->bus,mspmix->bass);		UNLOCK_I2C_BUS(mspmix->bus);		mixer_modcnt++;		/* fall */	case MIXER_READ(SOUND_MIXER_BASS):		ret = v4l_to_mix(mspmix->bass);		break;	case MIXER_WRITE(SOUND_MIXER_TREBLE):		mspmix->treble = mix_to_v4l(val);		LOCK_I2C_BUS(mspmix->bus);		msp3400c_settreble(mspmix->bus,mspmix->treble);		UNLOCK_I2C_BUS(mspmix->bus);		mixer_modcnt++;		/* fall */	case MIXER_READ(SOUND_MIXER_TREBLE):		ret = v4l_to_mix(mspmix->treble);		break;	default:		up(&mixer_sem);		return -EINVAL;	}	up(&mixer_sem);	if (put_user(ret, (int *)arg))		return -EFAULT;	return 0;}static intmsp3400c_mixer_open(struct inode *inode, struct file *file){        MOD_INC_USE_COUNT;        return 0;}static intmsp3400c_mixer_release(struct inode *inode, struct file *file){        MOD_DEC_USE_COUNT;        return 0;}static loff_tmsp3400c_mixer_llseek(struct file *file, loff_t offset, int origin){        return -ESPIPE;}static /*const*/ struct file_operations msp3400c_mixer_fops = {        &msp3400c_mixer_llseek,        NULL,  /* read */        NULL,  /* write */        NULL,  /* readdir */        NULL,  /* poll */        &msp3400c_mixer_ioctl,        NULL,  /* mmap */        &msp3400c_mixer_open,	NULL,        &msp3400c_mixer_release,        NULL,  /* fsync */        NULL,  /* fasync */        NULL,  /* check_media_change */        NULL,  /* revalidate */        NULL,  /* lock */};#endif/* ----------------------------------------------------------------------- */static int msp3400c_attach(struct i2c_device *device){	struct semaphore sem = MUTEX_LOCKED;	struct msp3400c *msp;	int              rev1,rev2;	LOCK_FLAGS;	device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL);	if (NULL == msp)		return -ENOMEM;	memset(msp,0,sizeof(struct msp3400c));	msp->bus = device->bus;	msp->left   = 65535;	msp->right  = 65535;	msp->bass   = 32768;	msp->treble = 32768;	LOCK_I2C_BUS(msp->bus);	if (-1 == msp3400c_reset(msp->bus)) {		UNLOCK_I2C_BUS(msp->bus);		kfree(msp);		dprintk("msp3400: no chip found\n");		return -1;	}    	rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e);	rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f);	if (0 == rev1 && 0 == rev2) {		UNLOCK_I2C_BUS(msp->bus);		kfree(msp);		printk("msp3400: error while reading chip version\n");		return -1;	}	msp3400c_setmode(msp, MSP_MODE_FM_TERRA);	msp3400c_setvolume(msp->bus, msp->left, msp->right);	msp3400c_setbass(msp->bus, msp->bass);	msp3400c_settreble(msp->bus, msp->treble);    #if 0	/* this will turn on a 1kHz beep - might be useful for debugging... */	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040);#endif	UNLOCK_I2C_BUS(msp->bus);	sprintf(device->name,"MSP34%02d%c-%c%d",		(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);	msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0;	/* timer for stereo checking */	msp->wake_stereo.function = msp3400c_stereo_wake;	msp->wake_stereo.data     = (unsigned long)msp;	/* startup control thread */	MOD_INC_USE_COUNT;	msp->wq     = NULL;	msp->notify = &sem;	kernel_thread(msp3400c_thread, (void *)msp, 0);	down(&sem);	msp->notify = NULL;	wake_up_interruptible(&msp->wq);	printk(KERN_INFO "msp3400: init: chip=%s",device->name);	if (msp->nicam)		printk(", has NICAM support");#ifdef REGISTER_MIXER	down(&mixer_sem);	mspmix = msp;	up(&mixer_sem);#endif	printk("\n");	return 0;}static int msp3400c_detach(struct i2c_device *device){	struct semaphore sem = MUTEX_LOCKED;	struct msp3400c *msp  = (struct msp3400c*)device->data;	LOCK_FLAGS;    #ifdef REGISTER_MIXER	down(&mixer_sem);	mspmix = NULL;	up(&mixer_sem);#endif	/* 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;	}    	LOCK_I2C_BUS(msp->bus);	msp3400c_reset(msp->bus);	UNLOCK_I2C_BUS(msp->bus);	kfree(msp);	MOD_DEC_USE_COUNT;	return 0;}static int msp3400c_command(struct i2c_device *device,		 unsigned int cmd, void *arg){	struct msp3400c *msp  = (struct msp3400c*)device->data;	int             *iarg = (int*)arg;        __u16           *sarg = arg;	LOCK_FLAGS;	switch (cmd) {	case MSP_SET_RADIO:		msp->norm = VIDEO_MODE_RADIO;		msp->watch_stereo=0;		del_timer(&msp->wake_stereo);		LOCK_I2C_BUS(msp->bus);		msp3400c_setmode(msp,MSP_MODE_FM_RADIO);		msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7));		msp3400c_setvolume(msp->bus,msp->left, msp->right);		UNLOCK_I2C_BUS(msp->bus);		break;	case MSP_SET_TVNORM:		msp->norm = *iarg;		break;	case MSP_SWITCH_MUTE:		/* channels switching step one -- mute */		msp->watch_stereo=0;		del_timer(&msp->wake_stereo);		LOCK_I2C_BUS(msp->bus);		msp3400c_setvolume(msp->bus,0,0);		UNLOCK_I2C_BUS(msp->bus);		break;	case MSP_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 MSP_GET_VOLUME:		*sarg = (msp->left > msp->right) ? msp->left : msp->right;		break;	case MSP_SET_VOLUME:		msp->left = msp->right = *sarg;		LOCK_I2C_BUS(msp->bus);		msp3400c_setvolume(msp->bus,msp->left, msp->right);		UNLOCK_I2C_BUS(msp->bus);		break;	case MSP_GET_BASS:		*sarg = msp->bass;		break;	case MSP_SET_BASS:		msp->bass = *sarg;		LOCK_I2C_BUS(msp->bus);		msp3400c_setbass(msp->bus,msp->bass);		UNLOCK_I2C_BUS(msp->bus);		break;	case MSP_GET_TREBLE:		*sarg = msp->treble;		break;	case MSP_SET_TREBLE:		msp->treble = *sarg;		LOCK_I2C_BUS(msp->bus);		msp3400c_settreble(msp->bus,msp->treble);		UNLOCK_I2C_BUS(msp->bus);		break;	case MSP_GET_STEREO:		*sarg = msp->stereo;		break;	case MSP_SET_STEREO:		if (*sarg) {			msp->watch_stereo=0;			del_timer(&msp->wake_stereo);			LOCK_I2C_BUS(msp->bus);			msp3400c_setstereo(msp,*sarg);			UNLOCK_I2C_BUS(msp->bus);		}		break;	case MSP_GET_DC:		LOCK_I2C_BUS(msp->bus);		*sarg = ((int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) +			 (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c));		UNLOCK_I2C_BUS(msp->bus);		break;	default:		return -EINVAL;	}	return 0;}/* ----------------------------------------------------------------------- */struct i2c_driver i2c_driver_msp = {	"msp3400",                    /* name       */	I2C_DRIVERID_MSP3400,         /* ID         */	I2C_MSP3400C, I2C_MSP3400C,   /* addr range */	msp3400c_attach,	msp3400c_detach,	msp3400c_command};#ifdef MODULEint init_module(void)#else     int msp3400c_init(void)#endif{	i2c_register_driver(&i2c_driver_msp);#ifdef REGISTER_MIXER	if ((mixer_num = register_sound_mixer(&msp3400c_mixer_fops, -1)) < 0)		printk(KERN_ERR "msp3400c: cannot allocate mixer device\n");#endif	return 0;}#ifdef MODULEvoid cleanup_module(void){	i2c_unregister_driver(&i2c_driver_msp);#ifdef REGISTER_MIXER	if (mixer_num >= 0)		unregister_sound_mixer(mixer_num);#endif}#endif/* * 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 + -