/* initial frequence the tuner will be tuned to. inverden(lowersaxony,germany)4148isa
channel called "phoenix" */ staticint freq = 4148;
module_param(freq, int, 0644);
MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
/* this array holds the information, which port of the saa7146 each
input actually uses. the mxb uses port 0 for every input */ staticstruct { int hps_source; int hps_sync;
} input_port_selection[MXB_INPUTS] = {
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
};
/* this array holds the information of the audio source (mxb_audios),
which has to be switched corresponding to the video source (mxb_channels) */ staticint video_audio_connect[MXB_INPUTS] =
{ 0, 1, 3, 3 };
int cur_mode; /* current audio mode (mono, stereo, ...) */ int cur_input; /* current input */ int cur_audinput; /* current audio input */ int cur_mute; /* current mute status */ struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
};
#define saa7111a_call(mxb, o, f, args...) \
v4l2_subdev_call(mxb->saa7111a, o, f, ##args) #define tda9840_call(mxb, o, f, args...) \
v4l2_subdev_call(mxb->tda9840, o, f, ##args) #define tea6415c_call(mxb, o, f, args...) \
v4l2_subdev_call(mxb->tea6415c, o, f, ##args) #define tuner_call(mxb, o, f, args...) \
v4l2_subdev_call(mxb->tuner, o, f, ##args) #define call_all(dev, o, f, args...) \
v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
/* bring hardware to a sane state. this has to be done, just in case someone wantstocapturefromthisdevicebeforeithasbeenproperlyinitialized. thecaptureenginewouldbadlyfail,becausenovalidsignalarrivesonthe
saa7146, thus leading to timeouts and stuff. */ staticint mxb_init_done(struct saa7146_dev* dev)
{ struct mxb* mxb = (struct mxb*)dev->ext_priv; struct i2c_msg msg; struct tuner_setup tun_setup;
v4l2_std_id std = V4L2_STD_PAL_BG;
int i, err = 0;
/* mute audio on tea6420s */
tea6420_route(mxb, 6);
/* select video mode in saa7111a */
saa7111a_call(mxb, video, s_std, std);
/* select a tuner type */
tun_setup.mode_mask = T_ANALOG_TV;
tun_setup.addr = ADDR_UNSET;
tun_setup.type = TUNER_PHILIPS_PAL;
tuner_call(mxb, tuner, s_type_addr, &tun_setup); /* tune in some frequency on tuner */
mxb->cur_freq.tuner = 0;
mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
mxb->cur_freq.frequency = freq;
tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
/* set a default video standard */ /* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
saa7111a_call(mxb, core, s_gpio, 1);
saa7111a_call(mxb, video, s_std, std);
tuner_call(mxb, video, s_std, std);
/* switch to tuner-channel on tea6415c */
tea6415c_call(mxb, video, s_routing, 3, 17, 0);
/* select tuner-output on multicable on tea6415c */
tea6415c_call(mxb, video, s_routing, 3, 13, 0);
/* the rest for mxb */
mxb->cur_input = 0;
mxb->cur_audinput = video_audio_connect[mxb->cur_input];
mxb->cur_mute = 1;
/* check if the saa7740 (aka 'sound arena module') is present onthemxb.ifso,wemustinitializeit.duetolackof informationaboutthesaa7740,thevalueswerereverse
engineered. */
msg.addr = 0x1b;
msg.flags = 0;
msg.len = mxb_saa7740_init[0].length;
msg.buf = &mxb_saa7740_init[0].data[0];
err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); if (err == 1) { /* the sound arena module is a pos, that's probably the reason philipsrefusestohandoutadatasheetforthesaa7740... itseemstoscrewupthei2cbus,sowedisablefastirq basedi2ctransactionshereandrelyontheslowandsafe
polling method ... */
extension.flags &= ~SAA7146_USE_I2C_IRQ; for (i = 1; ; i++) { if (-1 == mxb_saa7740_init[i].length) break;
msg.len = mxb_saa7740_init[i].length;
msg.buf = &mxb_saa7740_init[i].data[0];
err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); if (err != 1) {
DEB_D("failed to initialize 'sound arena module'\n"); goto err;
}
}
pr_info("'sound arena module' detected\n");
}
err: /* the rest for saa7146: you should definitely set some basic values
for the input-port handling of the saa7146. */
/* ext->saa has been filled by the core driver */
/* some stuff is done via variables */
saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
input_port_selection[mxb->cur_input].hps_sync);
/* some stuff is done via direct write to the registers */
/* this is ugly, but because of the fact that this is completely
hardware dependend, it should be done directly... */
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, DD1_INIT, 0x02000200);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
return0;
}
/* interrupt-handler. this gets called when irq_mask is != 0.
it must clear the interrupt-bits in irq_mask it has handled */ /* voidmxb_irq_bh(structsaa7146_dev*dev,u32*irq_mask) { structmxb*mxb=(structmxb*)dev->ext_priv; }
*/
/* prepare switching of tea6415c and saa7111a;
have a look at the 'background'-file for further information */ switch (input) { case TUNER:
i = SAA7115_COMPOSITE0;
/* connect tuner-output always to multicable */ if (!err)
err = tea6415c_call(mxb, video, s_routing, 3, 13, 0); break; case AUX3_YC: /* nothing to be done here. aux3_yc is
directly connected to the saa711a */
i = SAA7115_SVIDEO1; break; case AUX3: /* nothing to be done here. aux3 is
directly connected to the saa711a */
i = SAA7115_COMPOSITE1; break; case AUX1:
i = SAA7115_COMPOSITE0;
err = tea6415c_call(mxb, video, s_routing, 1, 17, 0); break;
}
/* switch video in saa7111a */ if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
pr_err("VIDIOC_S_INPUT: could not address saa7111a\n");
mxb->cur_audinput = video_audio_connect[input]; /* switch the audio-source only if necessary */ if (0 == mxb->cur_mute)
tea6420_route(mxb, mxb->cur_audinput); if (mxb->cur_audinput == 0)
mxb_update_audmode(mxb);
/* tune in desired frequency */
tuner_call(mxb, tuner, s_frequency, f); /* let the tuner subdev clamp the frequency to the tuner range */
mxb->cur_freq = *f;
tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq); if (mxb->cur_audinput == 0)
mxb_update_audmode(mxb); return0;
}
/* this function only gets called when the probing was successful */ staticint mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{ struct mxb *mxb; int ret;
DEB_EE("dev:%p\n", dev);
ret = saa7146_vv_init(dev, &vv_data); if (ret) {
ERR("Error in saa7146_vv_init()"); return ret;
}
if (V4L2_STD_PAL_I == standard->id) {
v4l2_std_id std = V4L2_STD_PAL_I;
DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n"); /* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
saa7111a_call(mxb, core, s_gpio, 0);
saa7111a_call(mxb, video, s_std, std); if (mxb->cur_input == 0)
tuner_call(mxb, video, s_std, std);
} else {
v4l2_std_id std = V4L2_STD_PAL_BG;
if (mxb->cur_input)
std = standard->id;
DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n"); /* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
saa7111a_call(mxb, core, s_gpio, 1);
saa7111a_call(mxb, video, s_std, std); if (mxb->cur_input == 0)
tuner_call(mxb, video, s_std, std);
} return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.