📄 tuner-core.c
字号:
if (!dvb_attach(tda9887_attach, &t->fe, t->i2c->adapter, t->i2c->addr)) goto attach_failed; break; case TUNER_XC5000: { struct dvb_tuner_ops *xc_tuner_ops; xc5000_cfg.i2c_address = t->i2c->addr; xc5000_cfg.if_khz = 5380; if (!dvb_attach(xc5000_attach, &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; xc_tuner_ops = &t->fe.ops.tuner_ops; if (xc_tuner_ops->init) xc_tuner_ops->init(&t->fe); break; } default: if (!dvb_attach(simple_tuner_attach, &t->fe, t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; } if ((NULL == analog_ops->set_params) && (fe_tuner_ops->set_analog_params)) { t->name = fe_tuner_ops->info.name; t->fe.analog_demod_priv = t; memcpy(analog_ops, &tuner_core_ops, sizeof(struct analog_demod_ops)); } else { t->name = analog_ops->info.name; } tuner_dbg("type set to %s\n", t->name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; /* xc2028/3028 and xc5000 requires a firmware to be set-up later trying to set a frequency here will just fail FIXME: better to move set_freq to the tuner code. This is needed on analog tuners for PLL to properly work */ if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000) set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq); tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); tuner_i2c_address_check(t); return;attach_failed: tuner_dbg("Tuner attach for type = %d failed.\n", t->type); t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return;}/* * This function apply tuner config to tuner specified * by tun_setup structure. I addr is unset, then admin status * and tun addr status is more precise then current status, * it's applied. Otherwise status and type are applied only to * tuner with exactly the same addr.*/static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup){ struct tuner *t = i2c_get_clientdata(c); if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && (t->mode_mask & tun_setup->mode_mask))) || (tun_setup->addr == c->addr)) { set_type(c, tun_setup->type, tun_setup->mode_mask, tun_setup->config, tun_setup->tuner_callback); } else tuner_dbg("set addr discarded for type %i, mask %x. " "Asked to change tuner at addr 0x%02x, with mask %x\n", t->type, t->mode_mask, tun_setup->addr, tun_setup->mode_mask);}static inline int check_mode(struct tuner *t, char *cmd){ if ((1 << t->mode & t->mode_mask) == 0) {#if 0 tuner_dbg("Cmd %s rejected for mode %i\n", cmd,t->mode);#endif return -EINVAL; } switch (t->mode) { case V4L2_TUNER_RADIO: tuner_dbg("Cmd %s accepted for radio\n", cmd); break; case V4L2_TUNER_ANALOG_TV: tuner_dbg("Cmd %s accepted for analog TV\n", cmd); break; case V4L2_TUNER_DIGITAL_TV: tuner_dbg("Cmd %s accepted for digital TV\n", cmd); break; } return 0;}/* get more precise norm info from insmod option */static int tuner_fixup_std(struct tuner *t){ if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { case '6': tuner_dbg ("insmod fixup: PAL => PAL-60\n"); t->std = V4L2_STD_PAL_60; break; case 'b': case 'B': case 'g': case 'G': tuner_dbg ("insmod fixup: PAL => PAL-BG\n"); t->std = V4L2_STD_PAL_BG; break; case 'i': case 'I': tuner_dbg ("insmod fixup: PAL => PAL-I\n"); t->std = V4L2_STD_PAL_I; break; case 'd': case 'D': case 'k': case 'K': tuner_dbg ("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; case 'M': case 'm': tuner_dbg ("insmod fixup: PAL => PAL-M\n"); t->std = V4L2_STD_PAL_M; break; case 'N': case 'n': if (pal[1] == 'c' || pal[1] == 'C') { tuner_dbg("insmod fixup: PAL => PAL-Nc\n"); t->std = V4L2_STD_PAL_Nc; } else { tuner_dbg ("insmod fixup: PAL => PAL-N\n"); t->std = V4L2_STD_PAL_N; } break; case '-': /* default parameter, do nothing */ break; default: tuner_warn ("pal= argument not recognised\n"); break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { case 'b': case 'B': case 'g': case 'G': case 'h': case 'H': tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n"); t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; break; case 'd': case 'D': case 'k': case 'K': tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n"); t->std = V4L2_STD_SECAM_DK; break; case 'l': case 'L': if ((secam[1]=='C')||(secam[1]=='c')) { tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n"); t->std = V4L2_STD_SECAM_LC; } else { tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; } break; case '-': /* default parameter, do nothing */ break; default: tuner_warn ("secam= argument not recognised\n"); break; } } if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { switch (ntsc[0]) { case 'm': case 'M': tuner_dbg("insmod fixup: NTSC => NTSC-M\n"); t->std = V4L2_STD_NTSC_M; break; case 'j': case 'J': tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); t->std = V4L2_STD_NTSC_M_JP; break; case 'k': case 'K': tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n"); t->std = V4L2_STD_NTSC_M_KR; break; case '-': /* default parameter, do nothing */ break; default: tuner_info("ntsc= argument not recognised\n"); break; } } return 0;}static void tuner_status(struct dvb_frontend *fe){ struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; const char *p; switch (t->mode) { case V4L2_TUNER_RADIO: p = "radio"; break; case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break; case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break; default: p = "undefined"; break; } if (t->mode == V4L2_TUNER_RADIO) { freq = t->radio_freq / 16000; freq_fraction = (t->radio_freq % 16000) * 100 / 16000; } else { freq = t->tv_freq / 16; freq_fraction = (t->tv_freq % 16) * 100 / 16; } tuner_info("Tuner mode: %s\n", p); tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; if (fe_tuner_ops->get_status) { u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); if (tuner_status & TUNER_STATUS_LOCKED) tuner_info("Tuner is locked.\n"); if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } if (analog_ops->has_signal) tuner_info("Signal strength: %d\n", analog_ops->has_signal(fe)); if (analog_ops->is_stereo) tuner_info("Stereo: %s\n", analog_ops->is_stereo(fe) ? "yes" : "no");}/* ---------------------------------------------------------------------- *//* * Switch tuner to other mode. If tuner support both tv and radio, * set another frequency to some value (This is needed for some pal * tuners to avoid locking). Otherwise, just put second tuner in * standby mode. */static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd){ struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; if (mode == t->mode) return 0; t->mode = mode; if (check_mode(t, cmd) == -EINVAL) { t->mode = T_STANDBY; if (analog_ops->standby) analog_ops->standby(&t->fe); return -EINVAL; } return 0;}#define switch_v4l2() if (!t->using_v4l2) \ tuner_dbg("switching to v4l2\n"); \ t->using_v4l2 = 1;static inline int check_v4l2(struct tuner *t){ /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for TV, v4l1 for radio), until that is fixed this code is disabled. Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2) first. */#if 0 if (t->using_v4l2) { tuner_dbg ("ignore v4l1 call\n"); return EINVAL; }#endif return 0;}static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg){ struct tuner *t = i2c_get_clientdata(client); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; if (tuner_debug > 1) { v4l_i2c_print_ioctl(client,cmd); printk("\n"); } switch (cmd) { /* --- configuration --- */ case TUNER_SET_TYPE_ADDR: tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", ((struct tuner_setup *)arg)->type, ((struct tuner_setup *)arg)->addr, ((struct tuner_setup *)arg)->mode_mask, ((struct tuner_setup *)arg)->config); set_addr(client, (struct tuner_setup *)arg); break; case AUDC_SET_RADIO: if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO") == -EINVAL) return 0; if (t->radio_freq) set_freq(client, t->radio_freq); break; case TUNER_SET_STANDBY: if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL) return 0; t->mode = T_STANDBY; if (analog_ops->standby) analog_ops->standby(&t->fe); break;#ifdef CONFIG_VIDEO_ALLOW_V4L1 case VIDIOCSAUDIO: if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL) return 0; if (check_v4l2(t) == -EINVAL) return 0; /* Should be implemented, since bttv calls it */ tuner_dbg("VIDIOCSAUDIO not implemented.\n"); break; case VIDIOCSCHAN: { static const v4l2_std_id map[] = { [VIDEO_MODE_PAL] = V4L2_STD_PAL, [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M, [VIDEO_MODE_SECAM] = V4L2_STD_SECAM, [4 /* bttv */ ] = V4L2_STD_PAL_M, [5 /* bttv */ ] = V4L2_STD_PAL_N, [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, }; struct video_channel *vc = arg; if (check_v4l2(t) == -EINVAL) return 0; if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==-EINVAL) return 0; if (vc->norm < ARRAY_SIZE(map)) t->std = map[vc->norm]; tuner_fixup_std(t); if (t->tv_freq) set_tv_freq(client, t->tv_freq); return 0; } case VIDIOCSFREQ: { unsigned long *v = arg; if (check_mode(t, "VIDIOCSFREQ") == -EINVAL) return 0; if (check_v4l2(t) == -EINVAL) return 0; set_freq(client, *v); return 0; } case VIDIOCGTUNER: { struct video_tuner *vt = arg; if (check_mode(t, "VIDIOCGTUNER") == -EINVAL) return 0; if (check_v4l2(t) == -EINVAL) return 0; if (V4L2_TUNER_RADIO == t->mode) { if (fe_tuner_ops->get_status) { u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); if (tuner_status & TUNER_STATUS_STEREO) vt->flags |= VIDEO_TUNER_STEREO_ON; else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { if (analog_ops->is_stereo) { if (analog_ops->is_stereo(&t->fe)) vt->flags |= VIDEO_TUNER_STEREO_ON; else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } } if (analog_ops->has_signal) vt->signal = analog_ops->has_signal(&t->fe); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ vt->rangelow = radio_range[0] * 16000; vt->rangehigh = radio_range[1] * 16000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -