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 + -
显示快捷键?