]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/media/video/ivtv/ivtv-vbi.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / media / video / ivtv / ivtv-vbi.c
index e1c347e5ebd8b25101475b5b9fc4d5f558ab449f..2dfa957b0fd5c3dc03d8c69e6e6cfbcc7d906bfc 100644 (file)
@@ -92,54 +92,97 @@ static int odd_parity(u8 c)
        return c & 1;
 }
 
-void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
+static void ivtv_write_vbi_line(struct ivtv *itv,
+                               const struct v4l2_sliced_vbi_data *d,
+                               struct vbi_cc *cc, int *found_cc)
 {
        struct vbi_info *vi = &itv->vbi;
-       struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
-       int found_cc = 0;
-       size_t i;
-
-       for (i = 0; i < cnt; i++) {
-               const struct v4l2_sliced_vbi_data *d = sliced + i;
 
-               if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
-                       if (d->field) {
-                               cc.even[0] = d->data[0];
-                               cc.even[1] = d->data[1];
-                       } else {
-                               cc.odd[0] = d->data[0];
-                               cc.odd[1] = d->data[1];
-                       }
-                       found_cc = 1;
+       if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
+               if (d->field) {
+                       cc->even[0] = d->data[0];
+                       cc->even[1] = d->data[1];
+               } else {
+                       cc->odd[0] = d->data[0];
+                       cc->odd[1] = d->data[1];
                }
-               else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
-                       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);
-                       }
+               *found_cc = 1;
+       } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
+               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) {
-                       int wss = d->data[0] | d->data[1] << 8;
+       } else if (d->id == V4L2_SLICED_WSS_625 &&
+                  d->line == 23 && d->field == 0) {
+               int wss = d->data[0] | d->data[1] << 8;
 
-                       if (vi->wss_payload != wss) {
-                               vi->wss_payload = wss;
-                               set_bit(IVTV_F_I_UPDATE_WSS, &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 && vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
-               vi->cc_payload[vi->cc_payload_idx++] = cc;
+}
+
+static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc)
+{
+       struct vbi_info *vi = &itv->vbi;
+
+       if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
+               memcpy(&vi->cc_payload[vi->cc_payload_idx], cc,
+                      sizeof(struct vbi_cc));
+               vi->cc_payload_idx++;
                set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
        }
 }
 
+static void ivtv_write_vbi(struct ivtv *itv,
+                          const struct v4l2_sliced_vbi_data *sliced,
+                          size_t cnt)
+{
+       struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+       int found_cc = 0;
+       size_t i;
+
+       for (i = 0; i < cnt; i++)
+               ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+
+       if (found_cc)
+               ivtv_write_vbi_cc_lines(itv, &cc);
+}
+
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+                        const struct v4l2_sliced_vbi_data __user *sliced,
+                        size_t cnt)
+{
+       struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+       int found_cc = 0;
+       size_t i;
+       struct v4l2_sliced_vbi_data d;
+       ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data);
+
+       for (i = 0; i < cnt; i++) {
+               if (copy_from_user(&d, sliced + i,
+                                  sizeof(struct v4l2_sliced_vbi_data))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+       }
+
+       if (found_cc)
+               ivtv_write_vbi_cc_lines(itv, &cc);
+
+       return ret;
+}
+
 static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
 {
        int line = 0;