V4L/DVB (6116): ivtv: VBI cleanups and fixes
[linux-2.6.git] / drivers / media / video / ivtv / ivtv-vbi.c
index 5d8a40f..c151bcf 100644 (file)
@@ -23,8 +23,7 @@
 #include "ivtv-queue.h"
 #include "ivtv-vbi.h"
 
-static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
-                 u8 vps4, u8 vps5)
+static void ivtv_set_vps(struct ivtv *itv, int enabled)
 {
        struct v4l2_sliced_vbi_data data;
 
@@ -33,15 +32,15 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps
        data.id = V4L2_SLICED_VPS;
        data.field = 0;
        data.line = enabled ? 16 : 0;
-       data.data[4] = vps1;
-       data.data[10] = vps2;
-       data.data[11] = vps3;
-       data.data[12] = vps4;
-       data.data[13] = vps5;
+       data.data[2] = itv->vbi.vps_payload.data[0];
+       data.data[8] = itv->vbi.vps_payload.data[1];
+       data.data[9] = itv->vbi.vps_payload.data[2];
+       data.data[10] = itv->vbi.vps_payload.data[3];
+       data.data[11] = itv->vbi.vps_payload.data[4];
        ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
 }
 
-static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4)
+static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
 {
        struct v4l2_sliced_vbi_data data;
 
@@ -50,13 +49,13 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 c
        data.id = V4L2_SLICED_CAPTION_525;
        data.field = 0;
        data.line = (mode & 1) ? 21 : 0;
-       data.data[0] = cc1;
-       data.data[1] = cc2;
+       data.data[0] = cc->odd[0];
+       data.data[1] = cc->odd[1];
        ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
        data.field = 1;
        data.line = (mode & 2) ? 21 : 0;
-       data.data[0] = cc3;
-       data.data[1] = cc4;
+       data.data[0] = cc->even[0];
+       data.data[1] = cc->even[1];
        ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
 }
 
@@ -92,62 +91,50 @@ static int odd_parity(u8 c)
        return c & 1;
 }
 
-static void passthrough_vbi_data(struct ivtv *itv, int cnt)
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
 {
-       int wss = 0;
-       u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
-       u8 vps[13];
+       struct vbi_info *vi = &itv->vbi;
+       struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
        int found_cc = 0;
-       int found_wss = 0;
-       int found_vps = 0;
-       int cc_pos = itv->vbi.cc_pos;
-       int i;
+       size_t i;
 
        for (i = 0; i < cnt; i++) {
-               struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i;
+               const struct v4l2_sliced_vbi_data *d = sliced + i;
 
                if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
-                       found_cc = 1;
                        if (d->field) {
-                               cc[2] = d->data[0];
-                               cc[3] = d->data[1];
+                               cc.even[0] = d->data[0];
+                               cc.even[1] = d->data[1];
                        } else {
-                               cc[0] = d->data[0];
-                               cc[1] = d->data[1];
+                               cc.odd[0] = d->data[0];
+                               cc.odd[1] = d->data[1];
                        }
+                       found_cc = 1;
                }
                else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
-                       memcpy(vps, d->data, sizeof(vps));
-                       found_vps = 1;
+                       struct vbi_vps vps;
+
+                       vps.data[0] = d->data[2];
+                       vps.data[1] = d->data[8];
+                       vps.data[2] = d->data[9];
+                       vps.data[3] = d->data[10];
+                       vps.data[4] = d->data[11];
+                       if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
+                               vi->vps_payload = vps;
+                               set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+                       }
                }
                else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
-                       wss = d->data[0] | d->data[1] << 8;
-                       found_wss = 1;
-               }
-       }
+                       int wss = d->data[0] | d->data[1] << 8;
 
-       if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
-               itv->vbi.wss = wss;
-               itv->vbi.wss_found = found_wss;
-               set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
-       }
-
-       if (found_vps || itv->vbi.vps_found) {
-               itv->vbi.vps[0] = vps[2];
-               itv->vbi.vps[1] = vps[8];
-               itv->vbi.vps[2] = vps[9];
-               itv->vbi.vps[3] = vps[10];
-               itv->vbi.vps[4] = vps[11];
-               itv->vbi.vps_found = found_vps;
-               set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+                       if (vi->wss_payload != wss) {
+                               vi->wss_payload = wss;
+                               set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+                       }
+               }
        }
-
-       if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
-               itv->vbi.cc_data_odd[cc_pos] = cc[0];
-               itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
-               itv->vbi.cc_data_even[cc_pos] = cc[2];
-               itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
-               itv->vbi.cc_pos = cc_pos + 2;
+       if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
+               vi->cc_payload[vi->cc_payload_idx++] = cc;
                set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
        }
 }
@@ -271,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
        return line * sizeof(itv->vbi.sliced_dec_data[0]);
 }
 
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
-{
-       /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
-       const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
-       u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
-       int found_cc = 0;
-       int cc_pos = itv->vbi.cc_pos;
-
-       while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
-               switch (p->id) {
-               case V4L2_SLICED_CAPTION_525:
-                       if (p->line == 21) {
-                               found_cc = 1;
-                               if (p->field) {
-                                       cc[2] = p->data[0];
-                                       cc[3] = p->data[1];
-                               } else {
-                                       cc[0] = p->data[0];
-                                       cc[1] = p->data[1];
-                               }
-                       }
-                       break;
-
-               case V4L2_SLICED_VPS:
-                       if (p->line == 16 && p->field == 0) {
-                               itv->vbi.vps[0] = p->data[2];
-                               itv->vbi.vps[1] = p->data[8];
-                               itv->vbi.vps[2] = p->data[9];
-                               itv->vbi.vps[3] = p->data[10];
-                               itv->vbi.vps[4] = p->data[11];
-                               itv->vbi.vps_found = 1;
-                               set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
-                       }
-                       break;
-
-               case V4L2_SLICED_WSS_625:
-                       if (p->line == 23 && p->field == 0) {
-                               /* No lock needed for WSS */
-                               itv->vbi.wss = p->data[0] | (p->data[1] << 8);
-                               itv->vbi.wss_found = 1;
-                               set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
-                       }
-                       break;
-
-               default:
-                       break;
-               }
-               count -= sizeof(*p);
-               p++;
-       }
-
-       if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
-               itv->vbi.cc_data_odd[cc_pos] = cc[0];
-               itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
-               itv->vbi.cc_data_even[cc_pos] = cc[2];
-               itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
-               itv->vbi.cc_pos = cc_pos + 2;
-               set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
-       }
-
-       return (const char __user *)p - ubuf;
-}
-
 /* Compress raw VBI format, removes leading SAV codes and surplus space after the
    field.
    Returns new compressed size. */
@@ -482,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
                memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
                buf->bytesused = cnt;
 
-               passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0]));
+               ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
+                              cnt / sizeof(itv->vbi.sliced_dec_data[0]));
                return;
        }
 }
 
-void ivtv_disable_vbi(struct ivtv *itv)
+void ivtv_disable_cc(struct ivtv *itv)
 {
-       clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
-       clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+       struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+
        clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
-       ivtv_set_wss(itv, 0, 0);
-       ivtv_set_cc(itv, 0, 0, 0, 0, 0);
-       ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
-       itv->vbi.vps_found = itv->vbi.wss_found = 0;
-       itv->vbi.wss = 0;
-       itv->vbi.cc_pos = 0;
+       ivtv_set_cc(itv, 0, &cc);
+       itv->vbi.cc_payload_idx = 0;
 }
 
 
 void ivtv_vbi_work_handler(struct ivtv *itv)
 {
+       struct vbi_info *vi = &itv->vbi;
        struct v4l2_sliced_vbi_data data;
+       struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
 
        /* Lock */
        if (itv->output_mode == OUT_PASSTHROUGH) {
-               /* Note: currently only the saa7115 is used in a PVR350,
-                  so these commands are for now saa7115 specific. */
                if (itv->is_50hz) {
                        data.id = V4L2_SLICED_WSS_625;
                        data.field = 0;
 
                        if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
                                ivtv_set_wss(itv, 1, data.data[0] & 0xf);
-                               itv->vbi.wss_no_update = 0;
-                       } else if (itv->vbi.wss_no_update == 4) {
+                               vi->wss_missing_cnt = 0;
+                       } else if (vi->wss_missing_cnt == 4) {
                                ivtv_set_wss(itv, 1, 0x8);  /* 4x3 full format */
                        } else {
-                               itv->vbi.wss_no_update++;
+                               vi->wss_missing_cnt++;
                        }
                }
                else {
-                       u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
                        int mode = 0;
 
                        data.id = V4L2_SLICED_CAPTION_525;
                        data.field = 0;
                        if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
                                mode |= 1;
-                               c1 = data.data[0];
-                               c2 = data.data[1];
+                               cc.odd[0] = data.data[0];
+                               cc.odd[1] = data.data[1];
                        }
                        data.field = 1;
                        if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
                                mode |= 2;
-                               c3 = data.data[0];
-                               c4 = data.data[1];
+                               cc.even[0] = data.data[0];
+                               cc.even[1] = data.data[1];
                        }
                        if (mode) {
-                               itv->vbi.cc_no_update = 0;
-                               ivtv_set_cc(itv, mode, c1, c2, c3, c4);
-                       } else if (itv->vbi.cc_no_update == 4) {
-                               ivtv_set_cc(itv, 0, 0, 0, 0, 0);
+                               vi->cc_missing_cnt = 0;
+                               ivtv_set_cc(itv, mode, &cc);
+                       } else if (vi->cc_missing_cnt == 4) {
+                               ivtv_set_cc(itv, 0, &cc);
                        } else {
-                               itv->vbi.cc_no_update++;
+                               vi->cc_missing_cnt++;
                        }
                }
                return;
        }
 
        if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
-               /* Lock */
-               ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
+               ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
        }
 
-       if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
-               if (itv->vbi.cc_pos == 0) {
-                       ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80);
+       if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
+               if (vi->cc_payload_idx == 0) {
+                       clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+                       ivtv_set_cc(itv, 3, &cc);
                }
-               while (itv->vbi.cc_pos) {
-                       u8 cc_odd0 = itv->vbi.cc_data_odd[0];
-                       u8 cc_odd1 = itv->vbi.cc_data_odd[1];
-                       u8 cc_even0 = itv->vbi.cc_data_even[0];
-                       u8 cc_even1 = itv->vbi.cc_data_even[1];
-
-                       memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2);
-                       memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
-                       itv->vbi.cc_pos -= 2;
-                       if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
+               while (vi->cc_payload_idx) {
+                       cc = vi->cc_payload[0];
+
+                       memcpy(vi->cc_payload, vi->cc_payload + 1,
+                                       sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
+                       vi->cc_payload_idx--;
+                       if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
                                continue;
 
-                       /* Send to Saa7127 */
-                       ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
-                       if (itv->vbi.cc_pos == 0)
-                               set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+                       ivtv_set_cc(itv, 3, &cc);
                        break;
                }
        }
 
        if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
-               /* Lock */
-               ivtv_set_vps(itv, itv->vbi.vps_found,
-                       itv->vbi.vps[0], itv->vbi.vps[1],
-                       itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
+               ivtv_set_vps(itv, 1);
        }
 }