📄 msp3400-kthreads.c
字号:
{ struct msp_state *state = i2c_get_clientdata(client); int val; int rxsubchans = state->rxsubchans; int newnicam = state->nicam_on; int update = 0; switch (state->mode) { case MSP_MODE_FM_TERRA: val = msp_read_dsp(client, 0x18); if (val > 32767) val -= 65536; v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val); if (val > 8192) { rxsubchans = V4L2_TUNER_SUB_STEREO; } else if (val < -4096) { rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } else { rxsubchans = V4L2_TUNER_SUB_MONO; } newnicam = 0; break; case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: val = msp_read_dem(client, 0x23); v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n", val & 1, (val & 0x1e) >> 1); if (val & 1) { /* nicam synced */ switch ((val & 0x1e) >> 1) { case 0: case 8: rxsubchans = V4L2_TUNER_SUB_STEREO; break; case 1: case 9: rxsubchans = V4L2_TUNER_SUB_MONO; break; case 2: case 10: rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; default: rxsubchans = V4L2_TUNER_SUB_MONO; break; } newnicam = 1; } else { newnicam = 0; rxsubchans = V4L2_TUNER_SUB_MONO; } break; } if (rxsubchans != state->rxsubchans) { update = 1; v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n", state->rxsubchans, rxsubchans); state->rxsubchans = rxsubchans; } if (newnicam != state->nicam_on) { update = 1; v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n", state->nicam_on, newnicam); state->nicam_on = newnicam; } return update;}/* * A kernel thread for msp3400 control -- we don't want to block the * in the ioctl while doing the sound carrier & stereo detect *//* stereo/multilang monitoring */static void watch_stereo(struct i2c_client *client){ struct msp_state *state = i2c_get_clientdata(client); if (msp_detect_stereo(client)) { msp_set_audmode(client); } if (msp_once) state->watch_stereo = 0;}int msp3400c_thread(void *data){ struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); struct msp3400c_carrier_detect *cd; int count, max1, max2, val1, val2, val, this;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) msp_setup_thread(state);#endif v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); for (;;) { v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if (state->rmmod || signal_pending(current))#else if (kthread_should_stop())#endif break; if (state->radio || MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); state->scan_in_progress = 0; state->rxsubchans = V4L2_TUNER_SUB_STEREO; msp_set_audio(client); continue; } /* mute audio */ state->scan_in_progress = 1; msp_set_audio(client); msp3400c_set_mode(client, MSP_MODE_AM_DETECT); val1 = val2 = 0; max1 = max2 = -1; state->watch_stereo = 0; state->nicam_on = 0; /* wait for tuner to settle down after a channel change */ if (msp_sleep(state, 200)) goto restart; /* carrier detect pass #1 -- main carrier */ cd = msp3400c_carrier_detect_main; count = ARRAY_SIZE(msp3400c_carrier_detect_main); if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { /* autodetect doesn't work well with AM ... */ max1 = 3; count = 0; v4l_dbg(1, msp_debug, client, "AM sound override\n"); } for (this = 0; this < count; this++) { msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); if (msp_sleep(state,100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val1 < val) val1 = val, max1 = this; v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name); } /* carrier detect pass #2 -- second (stereo) carrier */ switch (max1) { case 1: /* 5.5 */ cd = msp3400c_carrier_detect_55; count = ARRAY_SIZE(msp3400c_carrier_detect_55); break; case 3: /* 6.5 */ cd = msp3400c_carrier_detect_65; count = ARRAY_SIZE(msp3400c_carrier_detect_65); break; case 0: /* 4.5 */ case 2: /* 6.0 */ default: cd = NULL; count = 0; break; } if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { /* autodetect doesn't work well with AM ... */ cd = NULL; count = 0; max2 = 0; } for (this = 0; this < count; this++) { msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); if (msp_sleep(state,100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val2 < val) val2 = val, max2 = this; v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name); } /* program the msp3400 according to the results */ state->main = msp3400c_carrier_detect_main[max1].cdo; switch (max1) { case 1: /* 5.5 */ if (max2 == 0) { /* B/G FM-stereo */ state->second = msp3400c_carrier_detect_55[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); state->watch_stereo = 1; } else if (max2 == 1 && state->has_nicam) { /* B/G NICAM */ state->second = msp3400c_carrier_detect_55[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); state->nicam_on = 1; state->watch_stereo = 1; } else { goto no_second; } break; case 2: /* 6.0 */ /* PAL I NICAM */ state->second = MSP_CARRIER(6.552); msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); state->nicam_on = 1; state->watch_stereo = 1; break; case 3: /* 6.5 */ if (max2 == 1 || max2 == 2) { /* D/K FM-stereo */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); state->watch_stereo = 1; } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { /* L NICAM or AM-mono */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_AM_NICAM); state->watch_stereo = 1; } else if (max2 == 0 && state->has_nicam) { /* D/K NICAM */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); state->nicam_on = 1; state->watch_stereo = 1; } else { goto no_second; } break; case 0: /* 4.5 */ default: no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); break; } msp3400c_set_carrier(client, state->second, state->main); /* unmute */ state->scan_in_progress = 0; msp3400c_set_audmode(client); msp_set_audio(client); if (msp_debug) msp3400c_print_mode(client); /* monitor tv audio mode, the first time don't wait so long to get a quick stereo/bilingual result */ count = 3; while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; if (count) count--; watch_stereo(client); } } v4l_dbg(1, msp_debug, client, "thread: exit\n");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) state->kthread = NULL; if (state->notify != NULL) up(state->notify);#endif return 0;}int msp3410d_thread(void *data){ struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); int val, i, std, count;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) msp_setup_thread(state);#endif v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); for (;;) { v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); msp_sleep(state,-1); v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if (state->rmmod || signal_pending(current))#else if (kthread_should_stop())#endif break; if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; } /* mute audio */ state->scan_in_progress = 1; msp_set_audio(client); /* start autodetect. Note: autodetect is not supported for NTSC-M and radio, hence we force the standard in those cases. */ if (state->radio) std = 0x40; else std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; state->watch_stereo = 0; state->nicam_on = 0; /* wait for tuner to settle down after a channel change */ if (msp_sleep(state, 200)) goto restart; if (msp_debug) v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n", msp_standard_std_name(std), std); if (std != 1) { /* programmed some specific mode */ val = std; } else { /* triggered autodetect */ msp_write_dem(client, 0x20, std); for (;;) { if (msp_sleep(state, 100)) goto restart; /* check results */ val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; v4l_dbg(2, msp_debug, client, "detection still in progress\n"); } } for (i = 0; msp_stdlist[i].name != NULL; i++) if (msp_stdlist[i].retval == val) break; v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", msp_standard_std_name(val), val); state->main = msp_stdlist[i].main; state->second = msp_stdlist[i].second; state->std = val; state->rxsubchans = V4L2_TUNER_SUB_MONO; if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { /* autodetection has failed, let backup */ v4l_dbg(1, msp_debug, client, "autodetection failed," " switching to backup standard: %s (0x%04x)\n", msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); state->std = val = 0x0009; msp_write_dem(client, 0x20, val); } /* set stereo */ switch (val) { case 0x0008: /* B/G NICAM */ case 0x000a: /* I NICAM */ case 0x000b: /* D/K NICAM */ if (val == 0x000a) state->mode = MSP_MODE_FM_NICAM2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -