MODULE_PARM_DESC(radio, "The TV card supports radio, default is 0 (no)");
MODULE_PARM_DESC(bigendian, "byte order of the framebuffer, default is native endian");
MODULE_PARM_DESC(bttv_verbose, "verbose startup messages, default is 1 (yes)");
MODULE_PARM_DESC(bttv_gpio, "log gpio changes, default is 0 (no)");
MODULE_PARM_DESC(bttv_debug, "debug messages, default is 0 (no)");
MODULE_PARM_DESC(irq_debug, "irq handler debug messages, default is 0 (no)");
MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
MODULE_PARM_DESC(gbuffers, "number of capture buffers. range 2-32, default 8");
MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 0x208000");
MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default is 1 (yes) for compatibility with older applications");
MODULE_PARM_DESC(automute, "mute audio on bad/missing video signal, default is 1 (yes)");
MODULE_PARM_DESC(chroma_agc, "enables the AGC of chroma signal, default is 0 (no)");
MODULE_PARM_DESC(agc_crush, "enables the luminance AGC crush, default is 1 (yes)");
MODULE_PARM_DESC(whitecrush_upper, "sets the white crush upper value, default is 207");
MODULE_PARM_DESC(whitecrush_lower, "sets the white crush lower value, default is 127");
MODULE_PARM_DESC(vcr_hack, "enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
MODULE_PARM_DESC(irq_iswitch, "switch inputs in irq handler");
MODULE_PARM_DESC(uv_ratio, "ratio between u and v gains, default is 50");
MODULE_PARM_DESC(full_luma_range, "use the full luma range, default is 0 (no)");
MODULE_PARM_DESC(coring, "set the luma coring level, default is 0 (no)");
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
MODULE_LICENSE("GPL");
MODULE_VERSION(BTTV_VERSION);
/* ----------------------------------------------------------------------- */ /* static data */
/* special timing tables from conexant... */ static u8 SRAM_Table[][60] =
{ /* PAL digital input over GPIO[7:0] */
{
45, // 45 bytes following
0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
0x37,0x00,0xAF,0x21,0x00
}, /* NTSC digital input over GPIO[7:0] */
{
51, // 51 bytes following
0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
0x00,
}, // TGB_NTSC392 // quartzsight // This table has been modified to be used for Fusion Rev D
{
0x2A, // size of table = 42
0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
0x20, 0x00
}
};
/* minhdelayx1 first video pixel we can capture on a line and hdelayx1 start of active video, both relative to rising edge of /HRESET pulse (0H) in 1 / fCLKx1. swidth width of active video and totalwidth total line width, both in 1 / fCLKx1. sqwidth total line width in square pixels. vdelay start of active video in 2 * field lines relative to trailing edge of /VRESET pulse (VDELAY register). sheight height of active video in 2 * field lines. extraheight Added to sheight for cropcap.bounds.height only videostart0 ITU-R frame line number of the line corresponding
to vdelay in the first field. */ #define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
vdelay, sheight, extraheight, videostart0) \
.cropcap.bounds.left = minhdelayx1, \ /* * 2 because vertically we count field lines times two, */ \ /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
.cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ /* 4 is a safety margin at the end of the line. */ \
.cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
.cropcap.bounds.height = (sheight) + (extraheight) + (vdelay) - \
MIN_VDELAY, \
.cropcap.defrect.left = hdelayx1, \
.cropcap.defrect.top = (videostart0) * 2, \
.cropcap.defrect.width = swidth, \
.cropcap.defrect.height = sheight, \
.cropcap.pixelaspect.numerator = totalwidth, \
.cropcap.pixelaspect.denominator = sqwidth,
1) The resource must be allocated when we enter buffer prepare functions and remain allocated while buffers are in the DMA queue. 2) This is a single frame read. 3) This is a continuous read, implies VIDIOC_STREAMON.
Note this driver permits video input and standard changes regardless if resources are allocated.
*/
/* is it free? */ if (btv->resources & xbits) { /* no, someone else uses it */ goto fail;
}
if ((bit & VIDEO_RESOURCES)
&& 0 == (btv->resources & VIDEO_RESOURCES)) { /* Do crop - use current, don't - use default parameters. */
__s32 top = btv->crop[!!btv->do_crop].rect.top;
if (btv->vbi_end > top) goto fail;
/* We cannot capture the same line as video and VBI data.
Claim scan lines crop[].rect.top to bottom. */
btv->crop_start = top;
} elseif (bit & VBI_RESOURCES) {
__s32 end = btv->vbi_fmt.end;
/* VBI capturing ends at VDELAY, start of video capturing, no matter how many lines the VBI RISC program expects. When video capturing is off, it shall no longer "preempt" VBI capturing,
so we set VDELAY to maximum. */
crop = btread(BT848_E_CROP) | 0xc0;
btwrite(crop, BT848_E_CROP);
btwrite(0xfe, BT848_E_VDELAY_LO);
btwrite(crop, BT848_O_CROP);
btwrite(0xfe, BT848_O_VDELAY_LO);
}
void free_btres_lock(struct bttv *btv, int bits)
{ if ((btv->resources & bits) != bits) { /* trying to free resources not allocated by us ... */
pr_err("BUG! (btres)\n");
}
btv->resources &= ~bits;
bits = btv->resources;
if (0 == (bits & VIDEO_RESOURCES))
disclaim_video_lines(btv);
if (0 == (bits & VBI_RESOURCES))
disclaim_vbi_lines(btv);
}
/* ----------------------------------------------------------------------- */ /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
if (btv->pll.pll_ofreq == btv->pll.pll_current) {
dprintk("%d: PLL: no change required\n", btv->c.nr); return;
}
if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { /* no PLL needed */ if (btv->pll.pll_current == 0) return; if (bttv_verbose)
pr_info("%d: PLL can sleep, using XTAL (%d)\n",
btv->c.nr, btv->pll.pll_ifreq);
btwrite(0x00,BT848_TGCTRL);
btwrite(0x00,BT848_PLL_XCI);
btv->pll.pll_current = 0; return;
}
if (bttv_verbose)
pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n",
btv->c.nr,
btv->pll.pll_ifreq, btv->pll.pll_ofreq);
set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
for (i=0; i<10; i++) { /* Let other people run while the PLL stabilizes */
msleep(10);
if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
btwrite(0,BT848_DSTATUS);
} else {
btwrite(0x08,BT848_TGCTRL);
btv->pll.pll_current = btv->pll.pll_ofreq; if (bttv_verbose)
pr_info("PLL set ok\n"); return;
}
}
btv->pll.pll_current = -1; if (bttv_verbose)
pr_info("Setting PLL failed\n"); return;
}
/* used to switch between the bt848's analog/digital video capture modes */ staticvoid bt848A_set_timing(struct bttv *btv)
{ int i, len; int table_idx = bttv_tvnorms[btv->tvnorm].sram; int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
if (btv->input == btv->dig) {
dprintk("%d: load digital timing table (table_idx=%d)\n",
btv->c.nr,table_idx);
if (bttv_gpio)
bttv_gpio_tracking(btv, audio_modes[mute_gpio ? 4 : input]);
}
staticint
audio_mute(struct bttv *btv, int mute)
{ struct v4l2_ctrl *ctrl;
audio_mux_gpio(btv, btv->audio_input, mute);
if (btv->sd_msp34xx) {
ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl)
v4l2_ctrl_s_ctrl(ctrl, mute);
} if (btv->sd_tvaudio) {
ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl)
v4l2_ctrl_s_ctrl(ctrl, mute);
} if (btv->sd_tda7432) {
ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl)
v4l2_ctrl_s_ctrl(ctrl, mute);
} return 0;
}
staticint
audio_input(struct bttv *btv, int input)
{
audio_mux_gpio(btv, input, btv->mute);
if (btv->sd_msp34xx) {
u32 in;
/* Note: the inputs tuner/radio/extern/intern are translated to msp routings. This assumes common behavior for all msp3400 based TV cards. When this assumption fails, then the specific MSP routing must be added to the card table.
For now this is sufficient. */ switch (input) { case TVAUDIO_INPUT_RADIO: /* Some boards need the msp do to the radio demod */ if (btv->radio_uses_msp_demodulator) {
in = MSP_INPUT_DEFAULT; break;
}
in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); break; case TVAUDIO_INPUT_EXTERN:
in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); break; case TVAUDIO_INPUT_INTERN: /* Yes, this is the same input as for RADIO. I doubt if this is ever used. The only board with an INTERN input is the BTTV_BOARD_AVERMEDIA98. I wonder how that was tested. My guess is that the whole INTERN
input does not work. */
in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); break; case TVAUDIO_INPUT_TUNER: default: /* This is the only card that uses TUNER2, and afaik, is the only difference between the VOODOOTV_FM
and VOODOOTV_200 */ if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER); else
in = MSP_INPUT_DEFAULT; break;
}
v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,
in, MSP_OUTPUT_DEFAULT, 0);
} if (btv->sd_tvaudio) {
v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
input, 0, 0);
} return 0;
}
staticvoid
bttv_crop_calc_limits(struct bttv_crop *c)
{ /* Scale factor min. 1:1, max. 16:1. Min. image size
48 x 32. Scaled width must be a multiple of 4. */
if (1) { /* For bug compatibility with VIDIOCGCAP and image
size checks in earlier driver versions. */
c->min_scaled_width = 48;
c->min_scaled_height = 32;
} else {
c->min_scaled_width =
(max_t(unsignedint, 48, c->rect.width >> 4) + 3) & ~3;
c->min_scaled_height =
max_t(unsignedint, 32, c->rect.height >> 4);
}
/* set planar and packed mode trigger points and */ /* set rising edge of inverted GPINTR pin as irq trigger */
btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
BT848_GPIO_DMA_CTL_PLTP1_16|
BT848_GPIO_DMA_CTL_PLTP23_16|
BT848_GPIO_DMA_CTL_GPINTC|
BT848_GPIO_DMA_CTL_GPINTI,
BT848_GPIO_DMA_CTL);
for (i = 0; i < BTTV_TVNORMS; i++) if (id & bttv_tvnorms[i].v4l2_id) break; if (i == BTTV_TVNORMS) return -EINVAL;
btv->std = id;
set_tvnorm(btv, i); return 0;
}
bttv_call_all(btv, tuner, s_frequency, f); /* s_frequency may clamp the frequency, so get the actual
frequency before assigning radio/tv_freq. */
bttv_call_all(btv, tuner, g_frequency, &new_freq); if (new_freq.type == V4L2_TUNER_RADIO) {
radio_enable(btv);
btv->radio_freq = new_freq.frequency; if (btv->has_tea575x) {
btv->tea.freq = btv->radio_freq;
snd_tea575x_set_freq(&btv->tea);
}
} else {
btv->tv_freq = new_freq.frequency;
}
}
/* bt848 has a 12-bit register space */
btwrite(reg->val, reg->reg & 0xfff);
return 0;
} #endif
/* Given cropping boundaries b and the scaled width and height of a single field or frame, which must not exceed hardware limits, this
function adjusts the cropping parameters c. */ staticvoid
bttv_crop_adjust (struct bttv_crop * c, conststruct v4l2_rect * b,
__s32 width,
__s32 height, enum v4l2_field field)
{
__s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
__s32 max_left;
__s32 max_top;
/* Returns an error if scaling to a frame or single field with the given width and height is not possible with the current cropping parameters and width aligned according to width_mask. If adjust_size is TRUE the function may adjust the width and/or height instead, rounding width to (width + width_bias) & width_mask. If adjust_crop is TRUE it may also adjust the current cropping parameters to get closer to the
desired image size. */ staticint
limit_scaled_size_lock(struct bttv *btv, __s32 *width, __s32 *height, enum v4l2_field field, unsignedint width_mask, unsignedint width_bias, int adjust_size, int adjust_crop)
{ conststruct v4l2_rect *b; struct bttv_crop *c;
__s32 min_width;
__s32 min_height;
__s32 max_width;
__s32 max_height; int rc;
/* We cannot scale up. When the scaled image is larger than crop.rect we adjust the crop.rect as required
by the V4L2 spec, hence cropcap.bounds are our limit. */
max_width = min_t(unsignedint, b->width, MAX_HACTIVE);
max_height = b->height;
/* We cannot capture the same line as video and VBI data. Note btv->vbi_end is really a minimum, see
bttv_vbi_try_fmt(). */ if (btv->vbi_end > b->top) {
max_height -= btv->vbi_end - b->top;
rc = -EBUSY; if (min_height > max_height) goto fail;
}
} else {
rc = -EBUSY; if (btv->vbi_end > c->rect.top) goto fail;
fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL;
field = f->fmt.pix.field;
switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: case V4L2_FIELD_ALTERNATE: case V4L2_FIELD_INTERLACED: break; case V4L2_FIELD_SEQ_BT: case V4L2_FIELD_SEQ_TB: if (!(fmt->flags & FORMAT_FLAGS_PLANAR)) {
field = V4L2_FIELD_SEQ_TB; break;
}
fallthrough; default: /* FIELD_ANY case */
height2 = btv->crop[!!btv->do_crop].rect.height >> 1;
field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM; break;
}
/* update our state information */
btv->fmt = fmt;
btv->width = f->fmt.pix.width;
btv->height = f->fmt.pix.height;
btv->field = f->fmt.pix.field; /* * When field is V4L2_FIELD_ALTERNATE, buffers will be either * V4L2_FIELD_TOP or V4L2_FIELD_BOTTOM depending on the value of * field_last. Initialize field_last to V4L2_FIELD_BOTTOM so that * streaming starts with a V4L2_FIELD_TOP buffer.
*/
btv->field_last = V4L2_FIELD_BOTTOM;
/* * No need to lock here: those vars are initialized during board * probe and remains untouched during the rest of the driver lifecycle
*/ if (btv->has_saa6588)
cap->capabilities |= V4L2_CAP_RDS_CAPTURE; if (btv->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER; return 0;
}
staticint bttv_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
{ int index = -1, i;
for (i = 0; i < FORMATS; i++) { if (formats[i].fourcc != -1)
index++; if ((unsignedint)index == f->index) break;
} if (FORMATS == i) return -EINVAL;
if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL;
if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL;
/* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. Note
read() may change vbi_end in check_alloc_btres_lock(). */
retval = -EBUSY;
if (locked_btres(btv, VIDEO_RESOURCES)) return retval;
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.