V4L/DVB (10446): cx18: Finally get sliced VBI working - for 525 line 60 Hz systems...
authorAndy Walls <awalls@radix.net>
Mon, 9 Feb 2009 01:40:04 +0000 (22:40 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 30 Mar 2009 15:42:39 +0000 (12:42 -0300)
Sliced VBI, in the manner that ivtv implements it as a separate data stream,
now works for 525 line 60 Hz systems like NTSC-M.  It may work for 625 line
50 Hz systems, but I have more engineering work to do, to verify it is operating
properly.  Sliced data insertion into the MPEG PS should be working, but is
untested.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-av-vbi.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-vbi.c

index 1d197649446e803a4399fe0da5a17acfe8b296b7..a3bd2c95f582d91bbfb8b7c3fd45f0593a151fb2 100644 (file)
@@ -172,11 +172,11 @@ static void cx18_av_initialize(struct cx18 *cx)
        /*
         * Initial VBI setup
         * VIP-1.1, 10 bit mode, enable Raw, disable sliced,
-        * don't clamp raw samples when codes are in use, 4 byte user D-words,
-        * programmed IDID, RP code V bit transition on VBLANK, data during
+        * don't clamp raw samples when codes are in use, 1 byte user D-words,
+        * IDID0 has line #, RP code V bit transition on VBLANK, data during
         * blanking intervals
         */
-       cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010252e);
+       cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e);
 
        /* Set the video input.
           The setting in MODE_CTRL gets lost when we do the above setup */
@@ -218,6 +218,7 @@ void cx18_av_std_setup(struct cx18 *cx)
                cx18_av_write(cx, 0x49f, 0x14);
 
        if (std & V4L2_STD_625_50) {
+               /* FIXME - revisit these for Sliced VBI */
                hblank = 132;
                hactive = 720;
                burst = 93;
@@ -241,13 +242,34 @@ void cx18_av_std_setup(struct cx18 *cx)
                        sc = 672351;
                }
        } else {
+               /*
+                * The following relationships of half line counts should hold:
+                * 525 = vsync + vactive + vblank656
+                * 12 = vblank656 - vblank
+                *
+                * vsync:     always 6 half-lines of vsync pulses
+                * vactive:   half lines of active video
+                * vblank656: half lines, after line 3, of blanked video
+                * vblank:    half lines, after line 9, of blanked video
+                *
+                * vblank656 starts counting from the falling edge of the first
+                *      vsync pulse (start of line 4)
+                * vblank starts counting from the after the 6 vsync pulses and
+                *      6 equalization pulses (start of line 10)
+                *
+                * For 525 line systems the driver will extract VBI information
+                * from lines 10 through 21.  To avoid the EAV RP code from
+                * toggling at the start of hblank at line 22, where sliced VBI
+                * data from line 21 is stuffed, also treat line 22 as blanked.
+                */
+               vblank656 = 38; /* lines  4 through  22 */
+               vblank = 26;    /* lines 10 through  22 */
+               vactive = 481;  /* lines 23 through 262.5 */
+
                hactive = 720;
                hblank = 122;
-               vactive = 487;
                luma_lpf = 1;
                uv_lpf = 1;
-               vblank = 26;
-               vblank656 = 26;
 
                src_decimation = 0x21f;
                if (std == V4L2_STD_PAL_60) {
@@ -330,14 +352,14 @@ void cx18_av_std_setup(struct cx18 *cx)
        cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
        cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
 
-       /* Sets VBI parameters */
        if (std & V4L2_STD_625_50) {
-               cx18_av_write(cx, 0x47f, 0x01);
-               state->vbi_line_offset = 5;
+               state->slicer_line_delay = 1;
+               state->slicer_line_offset = (6 + state->slicer_line_delay - 2);
        } else {
-               cx18_av_write(cx, 0x47f, 0x00);
-               state->vbi_line_offset = 8;
+               state->slicer_line_delay = 0;
+               state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
        }
+       cx18_av_write(cx, 0x47f, state->slicer_line_delay);
 }
 
 /* ----------------------------------------------------------------------- */
index cf68a6039091a7dc684249ef5953ba651aec985c..d83760cae5406bbc895ccc55efd652f4a0ef1765 100644 (file)
@@ -79,11 +79,28 @@ struct cx18_av_state {
        enum cx18_av_audio_input aud_input;
        u32 audclk_freq;
        int audmode;
-       int vbi_line_offset;
        int default_volume;
        u32 id;
        u32 rev;
        int is_initialized;
+
+       /*
+        * The VBI slicer starts operating and counting lines, begining at
+        * slicer line count of 1, at D lines after the deassertion of VRESET
+        * This staring field line, S, is 6 or 10 for 625 or 525 line systems.
+        * Sliced ancillary data captured on VBI slicer line M is sent at the
+        * beginning of the next VBI slicer line, VBI slicer line count N = M+1.
+        * Thus when the VBI slicer reports a VBI slicer line number with
+        * ancillary data, the IDID0 byte indicates VBI slicer line N.
+        * The actual field line that the captured data comes from is
+        * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
+        *
+        * D is the slicer_line_delay value programmed into register 0x47f.
+        * (S+D-2) is the slicer_line_offset used to convert slicer reported
+        * line counts to actual field lines.
+        */
+       int slicer_line_delay;
+       int slicer_line_offset;
 };
 
 
index b5763372a316c766c0e317d30310ee16a0c22042..43267d1afb92816ab2b85c96ed30586774112052 100644 (file)
@@ -182,7 +182,6 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
        case VIDIOC_S_FMT:
        {
                int is_pal = !(state->std & V4L2_STD_525_60);
-               int vbi_offset = is_pal ? 1 : 0;
                int i, x;
                u8 lcr[24];
 
@@ -199,7 +198,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
                        cx18_av_std_setup(cx);
 
                        /* VBI Offset */
-                       cx18_av_write(cx, 0x47f, vbi_offset);
+                       cx18_av_write(cx, 0x47f, state->slicer_line_delay);
                        cx18_av_write(cx, 0x404, 0x2e);
                        break;
                }
@@ -213,7 +212,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
                /* Sliced VBI */
                cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
                cx18_av_write(cx, 0x406, 0x13);
-               cx18_av_write(cx, 0x47f, vbi_offset);
+               cx18_av_write(cx, 0x47f, state->slicer_line_delay);
 
                /* Force impossible lines to 0 */
                if (is_pal) {
@@ -261,7 +260,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
                }
 
                cx18_av_write(cx, 0x43c, 0x16);
-               cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
+               /* FIXME - should match vblank set in cx18_av_std_setup() */
+               cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
                break;
        }
 
@@ -286,7 +286,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
                did = anc->did;
                sdid = anc->sdid & 0xf;
                l = anc->idid[0] & 0x3f;
-               l += state->vbi_line_offset;
+               l += state->slicer_line_offset;
                p = anc->payload;
 
                /* Decode the SDID set by the slicer */
index 3cf8ddb633b42eea5ac341c19a9c1a327334a61a..2a45bbc757e8889bc665f85931422ccfc41cc227 100644 (file)
@@ -633,7 +633,9 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
        cx->av_state.aud_input = CX18_AV_AUDIO8;
        cx->av_state.audclk_freq = 48000;
        cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
-       cx->av_state.vbi_line_offset = 8;
+       cx->av_state.slicer_line_delay = 0;
+       cx->av_state.slicer_line_offset =
+               (10 + cx->av_state.slicer_line_delay - 2);
 }
 
 static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
index a8dcc0f171d1fa778974a75f19d94d63c96aeff0..778aa0c0f9b545dff009dbb7d79401cdd693fe40 100644 (file)
@@ -360,9 +360,16 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        if (raw) {
                lines = cx->vbi.count * 2;
        } else {
-               lines = cx->is_60hz ? 24 : 38;
-               if (cx->is_60hz)
-                       lines += 2;
+               /*
+                * For 525/60 systems, according to the VIP 2 & BT.656 std:
+                * The EAV RP code's Field bit toggles on line 4, a few lines
+                * after the Vertcal Blank bit has already toggled.
+                * Tell the encoder to capture 21-4+1=18 lines per field,
+                * since we want lines 10 through 21.
+                *
+                * FIXME - revisit for 625/50 systems
+                */
+               lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
        }
 
        data[0] = s->handle;
@@ -402,9 +409,13 @@ static void cx18_vbi_setup(struct cx18_stream *s)
                 *
                 * Since the V bit is only allowed to toggle in the EAV RP code,
                 * just before the first active region line, these two
-                * are problematic and we have to ignore them:
+                * are problematic:
                 * 0x90 (Task                         HorizontalBlank)
                 * 0xd0 (Task EvenField               HorizontalBlank)
+                *
+                * We have set the digitzer to consider the first active line
+                * as part of VerticalBlank as well so we don't have to look for
+                * these problem codes nor lose the last line of sliced data.
                 */
                data[4] = 0xB0F0B0F0;
                /*
index 52082d4a179e8de8c3576a0178dffe82a7eee3b6..8e6f4d4aff9ae6491817bd0f5070c2d89fdbc0aa 100644 (file)
@@ -221,13 +221,22 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
 
        pts = (be32_to_cpu(q[0] == 0x3fffffff)) ? be32_to_cpu(q[2]) : 0;
 
+       /*
+        * For calls to compress_sliced_buf(), ensure there are an integral
+        * number of lines by shifting the real data up over the 12 bytes header
+        * that got stuffed in.
+        * FIXME - there's a smarter way to do this with pointers, but for some
+        * reason I can't get it to work correctly right now.
+        */
+       memcpy(p, &buf->buf[12], size-12);
+
        /* first field */
-       /* compress_sliced_buf() will skip the 12 bytes of header */
        lines = compress_sliced_buf(cx, 0, p, size / 2, sliced_vbi_eav_rp[0]);
-       /* second field */
-       /* experimentation shows that the second half does not always
-          begin at the exact address. So start a bit earlier
-          (hence 32). */
+       /*
+        * second field
+        * In case the second half does not always begin at the exact address,
+        * start a bit earlier (hence 32).
+        */
        lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
                        size / 2 + 32, sliced_vbi_eav_rp[1]);
        /* always return at least one empty line */