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

📄 msp3400-driver.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 3 页
字号:
			default:				return -EINVAL;		}		break;	}	case VIDIOC_QUERYCTRL:	{		struct v4l2_queryctrl *qc = arg;		int i;		for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)			if (qc->id && qc->id == msp_qctrl_std[i].id) {				memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));				return 0;			}		if (!state->has_sound_processing)			return -EINVAL;		for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)			if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {				memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));				return 0;			}		return -EINVAL;	}	case VIDIOC_G_CTRL:		return msp_get_ctrl(client, arg);	case VIDIOC_S_CTRL:		return msp_set_ctrl(client, arg);	case VIDIOC_LOG_STATUS:	{		const char *p;		if (state->opmode == OPMODE_AUTOSELECT)			msp_detect_stereo(client);		v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",				client->name, state->rev1, state->rev2);		v4l_info(client, "Audio:    volume %d%s\n",				state->volume, state->muted ? " (muted)" : "");		if (state->has_sound_processing) {			v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",					state->balance, state->bass, state->treble,					state->loudness ? "on" : "off");		}		switch (state->mode) {		case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;		case MSP_MODE_FM_RADIO: p = "FM Radio"; break;		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;		case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;		case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;		case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;		case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break;		case MSP_MODE_BTSC: p = "BTSC"; break;		case MSP_MODE_EXTERN: p = "External input"; break;		default: p = "unknown"; break;		}		if (state->mode == MSP_MODE_EXTERN) {			v4l_info(client, "Mode:     %s\n", p);		} else if (state->opmode == OPMODE_MANUAL) {			v4l_info(client, "Mode:     %s (%s%s)\n", p,				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");		} else {			if (state->opmode == OPMODE_AUTODETECT)				v4l_info(client, "Mode:     %s\n", p);			v4l_info(client, "Standard: %s (%s%s)\n",				msp_standard_std_name(state->std),				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");		}		v4l_info(client, "Audmode:  0x%04x\n", state->audmode);		v4l_info(client, "Routing:  0x%08x (input) 0x%08x (output)\n",				state->routing.input, state->routing.output);		v4l_info(client, "ACB:      0x%04x\n", state->acb);		break;	}	default:		/* unknown */		return -EINVAL;	}	return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,14)static int msp_suspend(struct device * dev, pm_message_t state)#else#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)static int msp_suspend(struct device * dev, pm_message_t state, u32 level)#elsestatic int msp_suspend(struct device * dev, u32 state, u32 level)#endif#endif{	struct i2c_client *client = container_of(dev, struct i2c_client, dev);	v4l_dbg(1, msp_debug, client, "suspend\n");	msp_reset(client);	return 0;}#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,14)static int msp_resume(struct device * dev)#elsestatic int msp_resume(struct device * dev, u32 level)#endif{	struct i2c_client *client = container_of(dev, struct i2c_client, dev);	v4l_dbg(1, msp_debug, client, "resume\n");	msp_wake_thread(client);	return 0;}#endif /* LINUX_VERSION_CODE *//* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)static int msp_attach(struct i2c_adapter *adapter, int address,		      unsigned short flags, int kind)#elsestatic int msp_attach(struct i2c_adapter *adapter, int address, int kind)#endif{	struct i2c_client *client;	struct msp_state *state;	int (*thread_func)(void *data) = NULL;	int msp_hard;	int msp_family;	int msp_revision;	int msp_product, msp_prod_hi, msp_prod_lo;	int msp_rom;	client = kmalloc(sizeof(*client), GFP_KERNEL);	if (client == NULL)		return -ENOMEM;	memset(client, 0, sizeof(*client));	client->addr = address;	client->adapter = adapter;	client->driver = &i2c_driver;#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)	client->flags = I2C_CLIENT_ALLOW_USE;#endif	snprintf(client->name, sizeof(client->name) - 1, "msp3400");	if (msp_reset(client) == -1) {		v4l_dbg(1, msp_debug, client, "msp3400 not found\n");		kfree(client);		return -1;	}	state = kmalloc(sizeof(*state), GFP_KERNEL);	if (state == NULL) {		kfree(client);		return -ENOMEM;	}	i2c_set_clientdata(client, state);	memset(state, 0, sizeof(*state));	state->v4l2_std = V4L2_STD_NTSC;	state->audmode = V4L2_TUNER_MODE_STEREO;	state->volume = 58880;	/* 0db gain */	state->balance = 32768;	/* 0db gain */	state->bass = 32768;	state->treble = 32768;	state->loudness = 0;	state->input = -1;	state->muted = 0;	state->i2s_mode = 0;	init_waitqueue_head(&state->wq);	/* These are the reset input/output positions */	state->routing.input = MSP_INPUT_DEFAULT;	state->routing.output = MSP_OUTPUT_DEFAULT;	state->rev1 = msp_read_dsp(client, 0x1e);	if (state->rev1 != -1)		state->rev2 = msp_read_dsp(client, 0x1f);	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);	if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {		v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n");		kfree(state);		kfree(client);		return -1;	}#if 0	/* this will turn on a 1kHz beep - might be useful for debugging... */	msp_write_dsp(client, 0x0014, 0x1040);#endif	msp_set_audio(client);	msp_family = ((state->rev1 >> 4) & 0x0f) + 3;	msp_product = (state->rev2 >> 8) & 0xff;	msp_prod_hi = msp_product / 10;	msp_prod_lo = msp_product % 10;	msp_revision = (state->rev1 & 0x0f) + '@';	msp_hard = ((state->rev1 >> 8) & 0xff) + '@';	msp_rom = state->rev2 & 0x1f;	snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",			msp_family, msp_product,			msp_revision, msp_hard, msp_rom);	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;	/* Has radio support: was added with revision G */	state->has_radio = msp_revision >= 'G';	/* Has headphones output: not for stripped down products */	state->has_headphones = msp_prod_lo < 5;	/* Has scart2 input: not in stripped down products of the '3' family */	state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7;	/* Has scart3 input: not in stripped down products of the '3' family */	state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5;	/* Has scart4 input: not in pre D revisions, not in stripped D revs */	state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);	/* Has scart2 output: not in stripped down products of the '3' family */	state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5;	/* Has scart2 a volume control? Not in pre-D revisions. */	state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out;	/* Has a configurable i2s out? */	state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;	/* Has subwoofer output: not in pre-D revs and not in stripped down products */	state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;	/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in	   stripped down products */	state->has_sound_processing = msp_prod_lo < 7;	/* Has Virtual Dolby Surround: only in msp34x1 */	state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */	state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;	state->opmode = opmode;	if (state->opmode == OPMODE_AUTO) {		/* MSP revision G and up have both autodetect and autoselect */		if (msp_revision >= 'G')			state->opmode = OPMODE_AUTOSELECT;		/* MSP revision D and up have autodetect */		else if (msp_revision >= 'D')			state->opmode = OPMODE_AUTODETECT;		else			state->opmode = OPMODE_MANUAL;	}	/* hello world :-) */	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);	v4l_info(client, "%s ", client->name);	if (state->has_nicam && state->has_radio)		printk("supports nicam and radio, ");	else if (state->has_nicam)		printk("supports nicam, ");	else if (state->has_radio)		printk("supports radio, ");	printk("mode is ");	/* version-specific initialization */	switch (state->opmode) {	case OPMODE_MANUAL:		printk("manual");		thread_func = msp3400c_thread;		break;	case OPMODE_AUTODETECT:		printk("autodetect");		thread_func = msp3410d_thread;		break;	case OPMODE_AUTOSELECT:		printk("autodetect and autoselect");		thread_func = msp34xxg_thread;		break;	}	printk("\n");	/* startup control thread if needed */	if (thread_func) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)		state->kthread = kthread_run(thread_func, client, "msp34xx");		if (state->kthread == NULL)			v4l_warn(client, "kernel_thread() failed\n");#else		DECLARE_MUTEX_LOCKED(sem);		state->kthread = NULL;		state->notify = &sem;		kernel_thread(thread_func, client, 0);		down(&sem);		state->notify = NULL;#endif		msp_wake_thread(client);	}	/* done */	i2c_attach_client(client);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	MOD_INC_USE_COUNT;#endif	return 0;}static int msp_probe(struct i2c_adapter *adapter){#ifdef I2C_CLASS_TV_ANALOG	if (adapter->class & I2C_CLASS_TV_ANALOG)#else	if (adapter->id == I2C_HW_B_BT848)#endif		return i2c_probe(adapter, &addr_data, msp_attach);	return 0;}static int msp_detach(struct i2c_client *client){	struct msp_state *state = i2c_get_clientdata(client);	int err;	/* shutdown control thread */	if (state->kthread) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		DECLARE_MUTEX_LOCKED(sem);#endif		state->restart = 1;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		/* shutdown control thread */		state->notify = &sem;		state->rmmod = 1;		wake_up_interruptible(&state->wq);		down(&sem);		state->notify = NULL;#else		kthread_stop(state->kthread);#endif	}	msp_reset(client);	err = i2c_detach_client(client);	if (err) {		return err;	}	kfree(state);	kfree(client);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	MOD_DEC_USE_COUNT;#endif	return 0;}/* ----------------------------------------------------------------------- *//* i2c implementation */static struct i2c_driver i2c_driver = {#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))	.owner          = THIS_MODULE,#endif#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)	.name           = "msp3400",	.flags          = I2C_DF_NOTIFY,#endif	.id             = I2C_DRIVERID_MSP3400,	.attach_adapter = msp_probe,	.detach_client  = msp_detach,	.command        = msp_command,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)	.driver = {#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)		.name    = "msp3400",#endif		.suspend = msp_suspend,		.resume  = msp_resume,	},#endif};static int __init msp3400_init_module(void){	return i2c_add_driver(&i2c_driver);}static void __exit msp3400_cleanup_module(void){	i2c_del_driver(&i2c_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 + -