msp3400-driver.c

来自「linux2.6.16版本」· C语言 代码 · 共 1,275 行 · 第 1/3 页

C
1,275
字号
	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 msp_state *state  = i2c_get_clientdata(client);	switch (state->opmode) {	case OPMODE_MANUAL:	case OPMODE_AUTODETECT:		autodetect_stereo(client);		break;	case OPMODE_AUTOSELECT:		msp34xxg_detect_stereo(client);		break;	}}static struct v4l2_queryctrl msp_qctrl_std[] = {	{		.id            = V4L2_CID_AUDIO_VOLUME,		.name          = "Volume",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 58880,		.flags         = 0,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_MUTE,		.name          = "Mute",		.minimum       = 0,		.maximum       = 1,		.step          = 1,		.default_value = 1,		.flags         = 0,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},};static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {	{		.id            = V4L2_CID_AUDIO_BALANCE,		.name          = "Balance",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 32768,		.flags         = 0,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_BASS,		.name          = "Bass",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_TREBLE,		.name          = "Treble",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_LOUDNESS,		.name          = "Loudness",		.minimum       = 0,		.maximum       = 1,		.step          = 1,		.default_value = 1,		.flags         = 0,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},};static void msp_any_set_audmode(struct i2c_client *client, int audmode){	struct msp_state *state = i2c_get_clientdata(client);	switch (state->opmode) {	case OPMODE_MANUAL:	case OPMODE_AUTODETECT:		state->watch_stereo = 0;		msp3400c_setstereo(client, audmode);		break;	case OPMODE_AUTOSELECT:		msp34xxg_set_audmode(client, audmode);		break;	}}static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl){	struct msp_state *state = i2c_get_clientdata(client);	switch (ctrl->id) {	case V4L2_CID_AUDIO_VOLUME:		ctrl->value = state->volume;		break;	case V4L2_CID_AUDIO_MUTE:		ctrl->value = state->muted;		break;	case V4L2_CID_AUDIO_BALANCE:		if (!state->has_sound_processing)			return -EINVAL;		ctrl->value = state->balance;		break;	case V4L2_CID_AUDIO_BASS:		if (!state->has_sound_processing)			return -EINVAL;		ctrl->value = state->bass;		break;	case V4L2_CID_AUDIO_TREBLE:		if (!state->has_sound_processing)			return -EINVAL;		ctrl->value = state->treble;		break;	case V4L2_CID_AUDIO_LOUDNESS:		if (!state->has_sound_processing)			return -EINVAL;		ctrl->value = state->loudness;		break;	default:		return -EINVAL;	}	return 0;}static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl){	struct msp_state *state = i2c_get_clientdata(client);	switch (ctrl->id) {	case V4L2_CID_AUDIO_VOLUME:		state->volume = ctrl->value;		if (state->volume == 0)			state->balance = 32768;		break;	case V4L2_CID_AUDIO_MUTE:		if (ctrl->value < 0 || ctrl->value >= 2)			return -ERANGE;		state->muted = ctrl->value;		break;	case V4L2_CID_AUDIO_BASS:		if (!state->has_sound_processing)			return -EINVAL;		state->bass = ctrl->value;		break;	case V4L2_CID_AUDIO_TREBLE:		if (!state->has_sound_processing)			return -EINVAL;		state->treble = ctrl->value;		break;	case V4L2_CID_AUDIO_LOUDNESS:		if (!state->has_sound_processing)			return -EINVAL;		state->loudness = ctrl->value;		break;	case V4L2_CID_AUDIO_BALANCE:		if (!state->has_sound_processing)			return -EINVAL;		state->balance = ctrl->value;		break;	default:		return -EINVAL;	}	msp_set_audio(client);	return 0;}static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg){	struct msp_state *state = i2c_get_clientdata(client);	u16 *sarg = arg;	int scart = 0;	if (msp_debug >= 2)		v4l_i2c_print_ioctl(client, cmd);	switch (cmd) {	case AUDC_SET_INPUT:		if (*sarg == state->input)			break;		state->input = *sarg;		switch (*sarg) {		case AUDIO_RADIO:			/* Hauppauge uses IN2 for the radio */			state->mode = MSP_MODE_FM_RADIO;			scart       = SCART_IN2;			break;		case AUDIO_EXTERN_1:			/* IN1 is often used for external input ... */			state->mode = MSP_MODE_EXTERN;			scart       = SCART_IN1;			break;		case AUDIO_EXTERN_2:			/* ... sometimes it is IN2 through ;) */			state->mode = MSP_MODE_EXTERN;			scart       = SCART_IN2;			break;		case AUDIO_TUNER:			state->mode = -1;			break;		default:			if (*sarg & AUDIO_MUTE)				msp_set_scart(client, SCART_MUTE, 0);			break;		}		if (scart) {			state->rxsubchans = V4L2_TUNER_SUB_STEREO;			state->audmode = V4L2_TUNER_MODE_STEREO;			msp_set_scart(client, scart, 0);			msp_write_dsp(client, 0x000d, 0x1900);			if (state->opmode != OPMODE_AUTOSELECT)				msp3400c_setstereo(client, state->audmode);		}		msp_wake_thread(client);		break;	case AUDC_SET_RADIO:		if (state->radio)			return 0;		state->radio = 1;		v4l_dbg(1, msp_debug, client, "switching to radio mode\n");		state->watch_stereo = 0;		switch (state->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));			msp_set_audio(client);			break;		case OPMODE_AUTODETECT:		case OPMODE_AUTOSELECT:			/* 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;		va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;		if (state->has_sound_processing)			va->flags |= VIDEO_AUDIO_BALANCE |				VIDEO_AUDIO_BASS |				VIDEO_AUDIO_TREBLE;		if (state->muted)			va->flags |= VIDEO_AUDIO_MUTE;		va->volume = state->volume;		va->balance = state->volume ? state->balance : 32768;		va->bass = state->bass;		va->treble = state->treble;		if (state->radio)			break;		if (state->opmode == OPMODE_AUTOSELECT)			msp_any_detect_stereo(client);		va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);		break;	}	case VIDIOCSAUDIO:	{		struct video_audio *va = arg;		state->muted = (va->flags & VIDEO_AUDIO_MUTE);		state->volume = va->volume;		state->balance = va->balance;		state->bass = va->bass;		state->treble = va->treble;		msp_set_audio(client);		if (va->mode != 0 && state->radio == 0)			msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));		break;	}	case VIDIOCSCHAN:	{		struct video_channel *vc = arg;		int update = 0;		v4l2_std_id std;		if (state->radio)			update = 1;		state->radio = 0;		if (vc->norm == VIDEO_MODE_PAL)			std = V4L2_STD_PAL;		else if (vc->norm == VIDEO_MODE_SECAM)			std = V4L2_STD_SECAM;		else			std = V4L2_STD_NTSC;		if (std != state->v4l2_std) {			state->v4l2_std = std;			update = 1;		}		if (update)			msp_wake_thread(client);		break;	}	case VIDIOCSFREQ:	case VIDIOC_S_FREQUENCY:	{		/* new channel -- kick audio carrier scan */		msp_wake_thread(client);		break;	}	/* msp34xx specific */	case MSP_SET_MATRIX:	{		struct msp_matrix *mspm = arg;		msp_set_scart(client, mspm->input, mspm->output);		break;	}	/* --- v4l2 ioctls --- */	case VIDIOC_S_STD:	{		v4l2_std_id *id = arg;		int update = state->radio || state->v4l2_std != *id;		state->v4l2_std = *id;		state->radio = 0;		if (update)			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 (state->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 */			state->mode = MSP_MODE_FM_RADIO;			scart       = SCART_IN2;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?