V4L/DVB (10439): cx18: Clean-up and enable sliced VBI handling
authorAndy Walls <awalls@radix.net>
Sat, 31 Jan 2009 03:33:02 +0000 (00:33 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 30 Mar 2009 15:42:38 +0000 (12:42 -0300)
Removed legacy ivtv state variables, added comments, and cleaned
up sliced VBI related code.  Enabled sliced VBI.

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-vbi.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-cards.h
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-vbi.c

index 091f0cac06333aa1f74f0e506ec0d1d05d4c1d5a..1d197649446e803a4399fe0da5a17acfe8b296b7 100644 (file)
@@ -169,9 +169,14 @@ static void cx18_av_initialize(struct cx18 *cx)
        /* Set VGA_TRACK_RANGE to 0x20 */
        cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
 
-       /* Enable VBI capture */
-       cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
-       /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
+       /*
+        * 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
+        * blanking intervals
+        */
+       cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010252e);
 
        /* Set the video input.
           The setting in MODE_CTRL gets lost when we do the above setup */
index 1527ea4f6b06b83be93e4cdadc6eb9d73537c677..72325d774a605ad679335c7104dba33a04afdeca 100644 (file)
 
 #include "cx18-driver.h"
 
+/*
+ * For sliced VBI output, we set up to use VIP-1.1, 10-bit mode,
+ * NN counts 4 bytes Dwords, an IDID of 0x00 0x80 or one with the VBI line #.
+ * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
+ * (should!) look like:
+ *     4 byte EAV code:          0xff 0x00 0x00 0xRP
+ *     unknown number of possible idle bytes
+ *     3 byte Anc data preamble: 0x00 0xff 0xff
+ *     1 byte data identifier:   ne010iii (parity bits, 010, DID bits)
+ *     1 byte secondary data id: nessssss (parity bits, SDID bits)
+ *     1 byte data word count:   necccccc (parity bits, NN Dword count)
+ *     2 byte Internal DID:      0x00 0x80 (programmed value)
+ *     4*NN data bytes
+ *     1 byte checksum
+ *     Fill bytes needed to fil out to 4*NN bytes of payload
+ *
+ * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
+ * in the vertical blanking interval are:
+ *     0xb0 (Task         0 VerticalBlank HorizontalBlank 0 0 0 0)
+ *     0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
+ *
+ * Since the V bit is only allowed to toggle in the EAV RP code, just
+ * before the first active region line and for active lines, they are:
+ *     0x90 (Task         0 0 HorizontalBlank 0 0 0 0)
+ *     0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
+ *
+ * The user application DID bytes we care about are:
+ *     0x91 (1 0 010        0 !ActiveLine AncDataPresent)
+ *     0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
+ *
+ */
+static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
+
+struct vbi_anc_data {
+       /* u8 eav[4]; */
+       /* u8 idle[]; Variable number of idle bytes */
+       u8 preamble[3];
+       u8 did;
+       u8 sdid;
+       u8 data_count;
+       u8 idid[2];
+       u8 payload[1]; /* 4*data_count of payload */
+       /* u8 checksum; */
+       /* u8 fill[]; Variable number of fill bytes */
+};
+
 static int odd_parity(u8 c)
 {
        c ^= (c >> 4);
@@ -96,7 +142,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
                        0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
                        0, V4L2_SLICED_WSS_625, 0,      /* 4 */
                        V4L2_SLICED_CAPTION_525,        /* 6 */
-                       0, 0, V4L2_SLICED_VPS, 0, 0,    /* 9 */
+                       V4L2_SLICED_VPS, 0, 0, 0, 0,    /* 7 - unlike cx25840 */
                        0, 0, 0, 0
                };
                int is_pal = !(state->std & V4L2_STD_525_60);
@@ -220,47 +266,53 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
        case VIDIOC_INT_DECODE_VBI_LINE:
        {
                struct v4l2_decode_vbi_line *vbi = arg;
-               u8 *p = vbi->p;
-               int id1, id2, l, err = 0;
-
-               if (p[0] || p[1] != 0xff || p[2] != 0xff ||
-                   (p[3] != 0x55 && p[3] != 0x91)) {
+               u8 *p;
+               struct vbi_anc_data *anc = (struct vbi_anc_data *) vbi->p;
+               int did, sdid, l, err = 0;
+
+               /*
+                * Check for the ancillary data header for sliced VBI
+                */
+               if (anc->preamble[0] ||
+                   anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
+                   (anc->did != sliced_vbi_did[0] &&
+                    anc->did != sliced_vbi_did[1])) {
                        vbi->line = vbi->type = 0;
                        break;
                }
 
-               p += 4;
-               id1 = p[-1];
-               id2 = p[0] & 0xf;
-               l = p[2] & 0x3f;
+               did = anc->did;
+               sdid = anc->sdid & 0xf;
+               l = anc->idid[0] & 0x3f;
                l += state->vbi_line_offset;
-               p += 4;
+               p = anc->payload;
 
-               switch (id2) {
+               /* Decode the SDID set by the slicer */
+               switch (sdid) {
                case 1:
-                       id2 = V4L2_SLICED_TELETEXT_B;
+                       sdid = V4L2_SLICED_TELETEXT_B;
                        break;
                case 4:
-                       id2 = V4L2_SLICED_WSS_625;
+                       sdid = V4L2_SLICED_WSS_625;
                        break;
                case 6:
-                       id2 = V4L2_SLICED_CAPTION_525;
+                       sdid = V4L2_SLICED_CAPTION_525;
                        err = !odd_parity(p[0]) || !odd_parity(p[1]);
                        break;
-               case 9:
-                       id2 = V4L2_SLICED_VPS;
+               case 7: /* Differs from cx25840 */
+                       sdid = V4L2_SLICED_VPS;
                        if (decode_vps(p, p) != 0)
                                err = 1;
                        break;
                default:
-                       id2 = 0;
+                       sdid = 0;
                        err = 1;
                        break;
                }
 
-               vbi->type = err ? 0 : id2;
+               vbi->type = err ? 0 : sdid;
                vbi->line = err ? 0 : l;
-               vbi->is_second_field = err ? 0 : (id1 == 0x55);
+               vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
                vbi->p = p;
                break;
        }
index a0d4d2e49d1b9f533988d4279f7586bfd523ec20..6e2105ac2bc4bf62ec76fbfca825486e2f56486a 100644 (file)
@@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
 static const struct cx18_card cx18_card_hvr1600_esmt = {
        .type = CX18_CARD_HVR_1600_ESMT,
        .name = "Hauppauge HVR-1600",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Simultaneous Digital and Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_muxer = CX18_HW_CS5345,
@@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
 static const struct cx18_card cx18_card_hvr1600_samsung = {
        .type = CX18_CARD_HVR_1600_SAMSUNG,
        .name = "Hauppauge HVR-1600 (Preproduction)",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Simultaneous Digital and Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_muxer = CX18_HW_CS5345,
@@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
 static const struct cx18_card cx18_card_h900 = {
        .type = CX18_CARD_COMPRO_H900,
        .name = "Compro VideoMate H900",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_all = CX18_HW_TUNER,
@@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
 static const struct cx18_card cx18_card_cnxt_raptor_pal = {
        .type = CX18_CARD_CNXT_RAPTOR_PAL,
        .name = "Conexant Raptor PAL/SECAM",
-       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
+       .comment = "Analog TV capture supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_muxer = CX18_HW_GPIO,
index 6fa7bcb42dded2376e8b6ade7d29efba1d4c5de9..f8ee29f102d42c50d0b8948bae43b49831e0a6d9 100644 (file)
@@ -49,8 +49,7 @@
 /* V4L2 capability aliases */
 #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
                          V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
-                         V4L2_CAP_VBI_CAPTURE)
-/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+                         V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
 
 struct cx18_card_video_input {
        u8  video_type;         /* video input type */
index 17edf305d6499e7abcfc53b88c21627315f05443..6af4d5c190e1cad7ed0439d33b081a1835d6358f 100644 (file)
@@ -178,8 +178,8 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
                int i;
 
                for (i = 0; i < CX18_VBI_FRAMES; i++) {
-                       /* Yuck, hardcoded. Needs to be a define */
-                       cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+                       cx->vbi.sliced_mpeg_data[i] =
+                              kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
                        if (cx->vbi.sliced_mpeg_data[i] == NULL) {
                                while (--i >= 0) {
                                        kfree(cx->vbi.sliced_mpeg_data[i]);
index 062f1910e8ddc6fad908c08cec229c7b123ad763..842ce636e45cf92e5378bb182603c69a7421701e 100644 (file)
@@ -586,7 +586,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
                (cx->params.video_temporal_filter_mode << 1) |
                (cx->params.video_median_filter_type << 2);
        cx->params.port = CX2341X_PORT_MEMORY;
-       cx->params.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3;
+       cx->params.capabilities =
+         CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3 | CX2341X_CAP_HAS_SLICED_VBI;
        init_waitqueue_head(&cx->cap_w);
        init_waitqueue_head(&cx->mb_apu_waitq);
        init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -596,49 +597,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
        cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
 
-       /*
-        * The VBI line sizes depend on the pixel clock and the horiz rate
-        *
-        * (1/Fh)*(2*Fp) = Samples/line
-        *     = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
-        *
-        *  Sliced VBI is sent as ancillary data during horizontal blanking
-        *  Raw VBI is sent as active video samples during vertcal blanking
-        *
-        *  We use a  BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
-        *  length of 720 pixels @ 4:2:2 sampling.  Thus...
-        *
-        *  For systems that use a 15.734 kHz horizontal rate, such as
-        *  NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
-        *
-        *  (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
-        *  4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
-        *
-        *  For systems that use a 15.625 kHz horizontal rate, such as
-        *  PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
-        *
-        *  (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
-        *  4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
-        *
-        */
-
-       /* FIXME: init these based on tuner std & modify when std changes */
-       /* CX18-AV-Core number of VBI samples output per horizontal line */
-       cx->vbi.raw_decoder_line_size = 1444;   /* 4 byte SAV + 2 * 720 */
-       cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
-
-       /* CX18-AV-Core VBI samples/line possibly rounded up */
-       cx->vbi.raw_size = 1444;   /* Real max size is 1444 */
-       cx->vbi.sliced_size = 284; /* Real max size is  284 */
-
-       /*
-        * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
-        * Task Field VerticalBlank HorizontalBlank 0 0 0 0
-        */
-       cx->vbi.raw_decoder_sav_odd_field = 0x20;     /*   V  */
-       cx->vbi.raw_decoder_sav_even_field = 0x60;    /*  FV  */
-       cx->vbi.sliced_decoder_sav_odd_field = 0xB0;  /* T VH - actually EAV */
-       cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
        return 0;
 }
 
@@ -671,7 +629,6 @@ 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;
-       /* FIXME - 8 is NTSC value, investigate */
        cx->av_state.vbi_line_offset = 8;
 }
 
@@ -936,7 +893,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
         * suboptimal, as the CVBS and SVideo inputs could use a different std
         * and the buffer could end up being too small in that case.
         */
-       vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
+       vbi_buf_size = vbi_active_samples * (cx->is_60hz ? 24 : 36) / 2;
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
 
        if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
index d95c6ace2b96935306dee2774123fc2a6eb8881a..a41d9c4178f085c7a1172fcb15f67d58202fb3ae 100644 (file)
@@ -319,59 +319,121 @@ struct cx18_open_id {
 /* forward declaration of struct defined in cx18-cards.h */
 struct cx18_card;
 
+/*
+ * A note about "sliced" VBI data as implemented in this driver:
+ *
+ * Currently we collect the sliced VBI in the form of Ancillary Data
+ * packets, inserted by the AV core decoder/digitizer/slicer in the
+ * horizontal blanking region of the VBI lines, in "raw" mode as far as
+ * the Encoder is concerned.  We don't ever tell the Encoder itself
+ * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode)
+ *
+ * We then process the ancillary data ourselves to send the sliced data
+ * to the user application directly or build up MPEG-2 private stream 1
+ * packets to splice into (only!) MPEG-2 PS streams for the user app.
+ *
+ * (That's how ivtv essentially does it.)
+ *
+ * The Encoder should be able to extract certain sliced VBI data for
+ * us and provide it in a separate stream or splice it into any type of
+ * MPEG PS or TS stream, but this isn't implemented yet.
+ */
+
+/*
+ * Number of "raw" VBI samples per horizontal line we tell the Encoder to
+ * grab from the decoder/digitizer/slicer output for raw or sliced VBI.
+ * It depends on the pixel clock and the horiz rate:
+ *
+ * (1/Fh)*(2*Fp) = Samples/line
+ *     = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+ *
+ *  Sliced VBI data is sent as ancillary data during horizontal blanking
+ *  Raw VBI is sent as active video samples during vertcal blanking
+ *
+ *  We use a  BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+ *  length of 720 pixels @ 4:2:2 sampling.  Thus...
+ *
+ *  For systems that use a 15.734 kHz horizontal rate, such as
+ *  NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+ *
+ *  (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+ *  4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ *  For systems that use a 15.625 kHz horizontal rate, such as
+ *  PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+ *
+ *  (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+ *  4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+ */
+static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */
+static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */
+static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */
 
 #define CX18_VBI_FRAMES 32
 
-/* VBI data */
 struct vbi_info {
-       u32 enc_size;
-       u32 frame;
-       u8 cc_data_odd[256];
-       u8 cc_data_even[256];
-       int cc_pos;
-       u8 cc_no_update;
-       u8 vps[5];
-       u8 vps_found;
-       int wss;
-       u8 wss_found;
-       u8 wss_no_update;
-       u32 raw_decoder_line_size;
-       u8 raw_decoder_sav_odd_field;
-       u8 raw_decoder_sav_even_field;
-       u32 sliced_decoder_line_size;
-       u8 sliced_decoder_sav_odd_field;
-       u8 sliced_decoder_sav_even_field;
+       /* Current state of v4l2 VBI settings for this device */
        struct v4l2_format in;
-       /* convenience pointer to sliced struct in vbi_in union */
-       struct v4l2_sliced_vbi_format *sliced_in;
-       u32 service_set_in;
-       int insert_mpeg;
+       struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
+       u32 count;    /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
+       u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
 
-       /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
-          One for /dev/vbi0 and one for /dev/vbi8 */
-       struct v4l2_sliced_vbi_data sliced_data[36];
+       u32 frame; /* Count of VBI buffers/frames received from Encoder */
 
-       /* Buffer for VBI data inserted into MPEG stream.
-          The first byte is a dummy byte that's never used.
-          The next 16 bytes contain the MPEG header for the VBI data,
-          the remainder is the actual VBI data.
-          The max size accepted by the MPEG VBI reinsertion turns out
-          to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
-          where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
-          a single line header byte and 2 * 18 is the number of VBI lines per frame.
+       /*
+        * Vars for creation and insertion of MPEG Private Stream 1 packets
+        * of sliced VBI data into an MPEG PS
+        */
 
-          However, it seems that the data must be 1K aligned, so we have to
-          pad the data until the 1 or 2 K boundary.
+       /* Boolean: create and insert Private Stream 1 packets into the PS */
+       int insert_mpeg;
+
+       /*
+        * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+        * Used in cx18-vbi.c only for collecting sliced data, and as a source
+        * during conversion of sliced VBI data into MPEG Priv Stream 1 packets.
+        * We don't need to save state here, but the array may have been a bit
+        * too big (2304 bytes) to alloc from the stack.
+        */
+       struct v4l2_sliced_vbi_data sliced_data[36];
 
-          This pointer array will allocate 2049 bytes to store each VBI frame. */
+       /*
+        * A ring buffer of driver-generated MPEG-2 PS
+        * Program Pack/Private Stream 1 packets for sliced VBI data insertion
+        * into the MPEG PS stream.
+        *
+        * In each sliced_mpeg_data[] buffer is:
+        *      16 byte MPEG-2 PS Program Pack Header
+        *      16 byte MPEG-2 Private Stream 1 PES Header
+        *       4 byte magic number: "itv0" or "ITV0"
+        *       4 byte first  field line mask, if "itv0"
+        *       4 byte second field line mask, if "itv0"
+        *      36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data
+        *
+        *      Each line in the payload is
+        *       1 byte line header derived from the SDID (WSS, CC, VPS, etc.)
+        *      42 bytes of line data
+        *
+        * That's a maximum 1552 bytes of payload in the Private Stream 1 packet
+        * which is the payload size a PVR-350 (CX23415) MPEG decoder will
+        * accept for VBI data. So, including the headers, it's a maximum 1584
+        * bytes total.
+        */
+#define CX18_SLICED_MPEG_DATA_MAXSZ    1584
+       /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */
+#define CX18_SLICED_MPEG_DATA_BUFSZ    (CX18_SLICED_MPEG_DATA_MAXSZ+8)
        u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
        u32 sliced_mpeg_size[CX18_VBI_FRAMES];
-       struct cx18_buffer sliced_mpeg_buf;
+
+       /* Count of Program Pack/Program Stream 1 packets inserted into PS */
        u32 inserted_frame;
 
-       u32 start[2], count;
-       u32 raw_size;
-       u32 sliced_size;
+       /*
+        * A dummy driver stream transfer buffer with a copy of the next
+        * sliced_mpeg_data[] buffer for output to userland apps.
+        * Only used in cx18-fileops.c, but its state needs to persist at times.
+        */
+       struct cx18_buffer sliced_mpeg_buf;
 };
 
 /* Per cx23418, per I2C bus private algo callback data */
index 23006f7d9159f619f569d322eb91331eefdaaa59..0b1dbc67e1ab89c13dca10a2fe740d2ee62b5707 100644 (file)
@@ -176,6 +176,8 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
        *err = 0;
        while (1) {
                if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+                       /* Process pending program info updates and pending
+                          VBI data */
 
                        if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
                                cx->dualwatch_jiffies = jiffies;
@@ -260,6 +262,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
                len = ucount;
        if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
            !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
+               /*
+                * Try to find a good splice point in the PS, just before
+                * an MPEG-2 Program Pack start code, and provide only
+                * up to that point to the user, so it's easy to insert VBI data
+                * the next time around.
+                */
+               /* FIXME - This only works for an MPEG-2 PS, not a TS */
+               /*
+                * An MPEG-2 Program Stream (PS) is a series of
+                * MPEG-2 Program Packs terminated by an
+                * MPEG Program End Code after the last Program Pack.
+                * A Program Pack may hold a PS System Header packet and any
+                * number of Program Elementary Stream (PES) Packets
+                */
                const char *start = buf->buf + buf->readpos;
                const char *p = start + 1;
                const u8 *q;
@@ -267,38 +283,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
                int stuffing, i;
 
                while (start + len > p) {
+                       /* Scan for a 0 to find a potential MPEG-2 start code */
                        q = memchr(p, 0, start + len - p);
                        if (q == NULL)
                                break;
                        p = q + 1;
+                       /*
+                        * Keep looking if not a
+                        * MPEG-2 Pack header start code:  0x00 0x00 0x01 0xba
+                        * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0
+                        */
                        if ((char *)q + 15 >= buf->buf + buf->bytesused ||
                            q[1] != 0 || q[2] != 1 || q[3] != ch)
                                continue;
+
+                       /* If expecting the primary video PES */
                        if (!cx->search_pack_header) {
+                               /* Continue if it couldn't be a PES packet */
                                if ((q[6] & 0xc0) != 0x80)
                                        continue;
-                               if (((q[7] & 0xc0) == 0x80 &&
-                                    (q[9] & 0xf0) == 0x20) ||
-                                   ((q[7] & 0xc0) == 0xc0 &&
-                                    (q[9] & 0xf0) == 0x30)) {
-                                       ch = 0xba;
+                               /* Check if a PTS or PTS & DTS follow */
+                               if (((q[7] & 0xc0) == 0x80 &&  /* PTS only */
+                                    (q[9] & 0xf0) == 0x20) || /* PTS only */
+                                   ((q[7] & 0xc0) == 0xc0 &&  /* PTS & DTS */
+                                    (q[9] & 0xf0) == 0x30)) { /* DTS follows */
+                                       /* Assume we found the video PES hdr */
+                                       ch = 0xba; /* next want a Program Pack*/
                                        cx->search_pack_header = 1;
-                                       p = q + 9;
+                                       p = q + 9; /* Skip this video PES hdr */
                                }
                                continue;
                        }
+
+                       /* We may have found a Program Pack start code */
+
+                       /* Get the count of stuffing bytes & verify them */
                        stuffing = q[13] & 7;
                        /* all stuffing bytes must be 0xff */
                        for (i = 0; i < stuffing; i++)
                                if (q[14 + i] != 0xff)
                                        break;
-                       if (i == stuffing &&
-                           (q[4] & 0xc4) == 0x44 &&
-                           (q[12] & 3) == 3 &&
-                           q[14 + stuffing] == 0 &&
+                       if (i == stuffing && /* right number of stuffing bytes*/
+                           (q[4] & 0xc4) == 0x44 && /* marker check */
+                           (q[12] & 3) == 3 &&  /* marker check */
+                           q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
                            q[15 + stuffing] == 0 &&
                            q[16 + stuffing] == 1) {
-                               cx->search_pack_header = 0;
+                               /* We declare we actually found a Program Pack*/
+                               cx->search_pack_header = 0; /* expect vid PES */
                                len = (char *)q - start;
                                cx18_setup_sliced_vbi_buf(cx);
                                break;
index 20467fce52513516837e983dd7823e8570b67dd5..1adb97220920fa44ba31f822ab51a1f7306cceb8 100644 (file)
@@ -102,6 +102,19 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
        }
 }
 
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+       int f, l;
+       u16 set = 0;
+
+       for (f = 0; f < 2; f++) {
+               for (l = 0; l < 24; l++) {
+                       fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+                       set |= fmt->service_lines[f][l];
+               }
+       }
+       return set != 0;
+}
 
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 {
@@ -150,7 +163,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
 
        vbifmt->sampling_rate = 27000000;
        vbifmt->offset = 248;
-       vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+       vbifmt->samples_per_line = vbi_active_samples - 4;
        vbifmt->sample_format = V4L2_PIX_FMT_GREY;
        vbifmt->start[0] = cx->vbi.start[0];
        vbifmt->start[1] = cx->vbi.start[1];
@@ -164,7 +177,17 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       return -EINVAL;
+       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+
+       cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
+       vbifmt->service_set = cx18_get_service_set(vbifmt);
+       return 0;
 }
 
 static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
@@ -194,7 +217,18 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       return -EINVAL;
+       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       vbifmt->reserved[0] = 0;
+       vbifmt->reserved[1] = 0;
+
+       if (vbifmt->service_set)
+               cx18_expand_service_set(vbifmt, cx->is_50hz);
+       check_service_set(vbifmt, cx->is_50hz);
+       vbifmt->service_set = cx18_get_service_set(vbifmt);
+       return 0;
 }
 
 static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
@@ -250,7 +284,28 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       return -EINVAL;
+       struct cx18_open_id *id = fh;
+       struct cx18 *cx = id->cx;
+       int ret;
+       struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+       ret = v4l2_prio_check(&cx->prio, &id->prio);
+       if (ret)
+               return ret;
+
+       ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
+       if (ret)
+               return ret;
+
+       if (check_service_set(vbifmt, cx->is_50hz) == 0)
+               return -EINVAL;
+
+       if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
+               return -EBUSY;
+       cx->vbi.in.type =  V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+       memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+       return 0;
 }
 
 static int cx18_g_chip_ident(struct file *file, void *fh,
@@ -548,7 +603,6 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
        cx->vbi.count = cx->is_50hz ? 18 : 12;
        cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
        cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
-       cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
        CX18_DEBUG_INFO("Switching standard to %llx.\n",
                        (unsigned long long) cx->std);
 
@@ -599,6 +653,19 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_sliced_vbi_cap *cap)
 {
+       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+       int f, l;
+
+       if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+               for (f = 0; f < 2; f++) {
+                       for (l = 0; l < 24; l++) {
+                               if (valid_service_line(f, l, cx->is_50hz))
+                                       cap->service_lines[f][l] = set;
+                       }
+               }
+               return 0;
+       }
        return -EINVAL;
 }
 
index abc3fe605f0044da3b86ec030173d9ec0ed4902f..a89f7f840d95ea3fe0e69dff067583866dd9e1ea 100644 (file)
@@ -349,10 +349,6 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        /* setup VBI registers */
        cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
 
-       /* determine number of lines and total number of VBI bytes.
-          A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
-          A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
-          header, 42 data bytes + checksum (to be confirmed) */
        if (raw) {
                lines = cx->vbi.count * 2;
        } else {
@@ -361,24 +357,53 @@ static void cx18_vbi_setup(struct cx18_stream *s)
                        lines += 2;
        }
 
-       cx->vbi.enc_size = lines *
-               (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
-
        data[0] = s->handle;
        /* Lines per field */
        data[1] = (lines / 2) | ((lines / 2) << 16);
        /* bytes per line */
-       data[2] = (raw ? cx->vbi.raw_decoder_line_size
-                      : cx->vbi.sliced_decoder_line_size);
+       data[2] = (raw ? vbi_active_samples
+                      : (cx->is_60hz ? vbi_hblank_samples_60Hz
+                                     : vbi_hblank_samples_50Hz));
        /* Every X number of frames a VBI interrupt arrives
           (frames as in 25 or 30 fps) */
        data[3] = 1;
-       /* Setup VBI for the cx25840 digitizer */
+       /*
+        * Set the SAV/EAV RP codes to look for as start/stop points
+        * when in VIP-1.1 mode
+        */
        if (raw) {
+               /*
+                * Start codes for beginning of "active" line in vertical blank
+                * 0x20 (               VerticalBlank                )
+                * 0x60 (     EvenField VerticalBlank                )
+                */
                data[4] = 0x20602060;
+               /*
+                * End codes for end of "active" raw lines and regular lines
+                * 0x30 (               VerticalBlank HorizontalBlank)
+                * 0x70 (     EvenField VerticalBlank HorizontalBlank)
+                * 0x90 (Task                         HorizontalBlank)
+                * 0xd0 (Task EvenField               HorizontalBlank)
+                */
                data[5] = 0x307090d0;
        } else {
+               /*
+                * End codes for active video, we want data in the hblank region
+                * 0xb0 (Task         0 VerticalBlank HorizontalBlank)
+                * 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
+                *
+                * 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:
+                * 0x90 (Task                         HorizontalBlank)
+                * 0xd0 (Task EvenField               HorizontalBlank)
+                */
                data[4] = 0xB0F0B0F0;
+               /*
+                * Start codes for beginning of active line in vertical blank
+                * 0xa0 (Task           VerticalBlank                )
+                * 0xe0 (Task EvenField VerticalBlank                )
+                */
                data[5] = 0xA0E0A0E0;
        }
 
index fb595bd548e898f80d29f6d98982c3dfe8b91def..38d26c42e4cb5399c2f795cef178cae360a701b0 100644 (file)
 #include "cx18-queue.h"
 #include "cx18-av-core.h"
 
+/*
+ * Raster Reference/Protection (RP) bytes, used in Start/End Active
+ * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
+ * of VBI sample or VBI ancilliary data regions in the digitial ratser line.
+ *
+ * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
+ */
+static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 };    /* __V_, _FV_ */
+static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */
+
 static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
 {
        int line = 0;
@@ -34,10 +44,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
        u32 linemask[2] = { 0, 0 };
        unsigned short size;
        static const u8 mpeg_hdr_data[] = {
-               0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
-               0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
-               0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
-               0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+               /* MPEG-2 Program Pack */
+               0x00, 0x00, 0x01, 0xba,             /* Prog Pack start code */
+               0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
+               0x01, 0xd1, 0xd3,                   /* Mux Rate, markers */
+               0xfa, 0xff, 0xff,                   /* Res, Suff cnt, Stuff */
+               /* MPEG-2 Private Stream 1 PES Packet */
+               0x00, 0x00, 0x01, 0xbd,             /* Priv Stream 1 start */
+               0x00, 0x1a,                         /* length */
+               0x84, 0x80, 0x07,                   /* flags, hdr data len */
+               0x21, 0x00, 0x5d, 0x63, 0xa7,       /* PTS, markers */
+               0xff, 0xff                          /* stuffing */
        };
        const int sd = sizeof(mpeg_hdr_data);   /* start of vbi data */
        int idx = cx->vbi.frame % CX18_VBI_FRAMES;
@@ -71,7 +88,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
                memcpy(dst + sd + 4, dst + sd + 12, line * 43);
                size = 4 + ((43 * line + 3) & ~3);
        } else {
-               memcpy(dst + sd, "cx0", 4);
+               memcpy(dst + sd, "itv0", 4);
                memcpy(dst + sd + 4, &linemask[0], 8);
                size = 12 + ((43 * line + 3) & ~3);
        }
@@ -90,10 +107,10 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
    Returns new compressed size. */
 static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
 {
-       u32 line_size = cx->vbi.raw_decoder_line_size;
+       u32 line_size = vbi_active_samples;
        u32 lines = cx->vbi.count;
-       u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
-       u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
+       u8 sav1 = raw_vbi_sav_rp[0];
+       u8 sav2 = raw_vbi_sav_rp[1];
        u8 *q = buf;
        u8 *p;
        int i;
@@ -115,15 +132,16 @@ static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
 /* Compressed VBI format, all found sliced blocks put next to one another
    Returns new compressed size */
 static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
-                              u32 size, u8 sav)
+                              u32 size, u8 eav)
 {
-       u32 line_size = cx->vbi.sliced_decoder_line_size;
        struct v4l2_decode_vbi_line vbi;
        int i;
+       u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
+                                   : vbi_hblank_samples_50Hz;
 
        /* find the first valid line */
        for (i = 0; i < size; i++, buf++) {
-               if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+               if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == eav)
                        break;
        }
 
@@ -133,8 +151,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
        for (i = 0; i < size / line_size; i++) {
                u8 *p = buf + i * line_size;
 
-               /* Look for SAV code  */
-               if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
+               /* Look for EAV code  */
+               if (p[0] != 0xff || p[1] || p[2] || p[3] != eav)
                        continue;
                vbi.p = p + 4;
                cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
@@ -159,6 +177,12 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
        if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
                return;
 
+       /*
+        * Note the CX23418 provides a 12 byte header, in it's raw VBI
+        * buffers to us, that we currently throw away:
+        * 0x3fffffff [4 bytes of something] [4 byte timestamp]
+        */
+
        /* Raw VBI data */
        if (cx18_raw_vbi(cx)) {
                u8 type;
@@ -173,7 +197,7 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
                size = buf->bytesused = compress_raw_buf(cx, p, size);
 
                /* second field of the frame? */
-               if (type == cx->vbi.raw_decoder_sav_even_field) {
+               if (type == raw_vbi_sav_rp[1]) {
                        /* Dirty hack needed for backwards
                           compatibility of old VBI software. */
                        p += size - 4;
@@ -187,14 +211,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
        cx18_buf_swap(buf);
 
        /* first field */
-       lines = compress_sliced_buf(cx, 0, p, size / 2,
-                       cx->vbi.sliced_decoder_sav_odd_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). */
        lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
-                       size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
+                       size / 2 + 32, sliced_vbi_eav_rp[1]);
        /* always return at least one empty line */
        if (lines == 0) {
                cx->vbi.sliced_data[0].id = 0;