I�aki Garc�a Etxebarria wrote:
> 
> > Hi,
> Hi,
> 
> > After installing bttv-0.7.46 I get uresolved symbols in btaudio.o
> > After installing the bttv2 driver I get unresolved symbols in bttv.o and
> > bttv2.o.
> I've had the same problems with a test8 kernel.
> The attached patch fixes it for me.
> 
> BTW, which program has been used for testing VBI support in the bttv2 driver?
> AleVT 1.6.0 doesn't work for me.
> 
> Regards,
> I�aki

Thanks for the patch - I just want to test it on 2.2 series kernels, and
if it works, I will include it. (Perhaps you should also forward it to
Gerd, as this will affect bttv too).

Below is a patch to get alevt working with bttv2.  It is not fully v4l2
compliant yet, but at least it works!

-justin
diff -urN alevt-1.6.0/vbi.c alevt-1.6.0.wks/vbi.c
--- alevt-1.6.0/vbi.c   Wed Oct 11 19:39:19 2000
+++ alevt-1.6.0.wks/vbi.c       Wed Oct 25 19:00:06 2000
@@ -11,6 +11,10 @@
 #include "fdset.h"
 #include "hamm.h"
 #include "lang.h"
+#include <linux/fs.h>
+#include <linux/videodev.h>
+#include <errno.h>
+#include <sys/mman.h>
 
 #define FAC    (1<<16)         // factor for fix-point arithmetic
 
@@ -24,34 +28,6 @@
 #define BTTV_VERSION           _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
 #define BTTV_VBISIZE           _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
 
-/***** v4l2 vbi-api *****/
-
-struct v4l2_vbi_format
-{
-    u32 sampling_rate;         /* in 1 Hz */
-    u32 offset;                        /* sampling starts # samples after rising hs */
-    u32 samples_per_line;
-    u32 sample_format;         /* V4L2_VBI_SF_* */
-    s32 start[2];
-    u32 count[2];
-    u32 flags;                 /* V4L2_VBI_* */
-    u32 reserved2;             /* must be zero */
-};
-
-struct v4l2_format
-{
-    u32        type;                   /* V4L2_BUF_TYPE_* */
-    union
-    {
-       struct v4l2_vbi_format vbi;     /*  VBI data  */
-       u8 raw_data[200];               /* user-defined */
-    } fmt;
-};
-
-#define V4L2_VBI_SF_UBYTE      1
-#define V4L2_BUF_TYPE_VBI       0x00000009
-#define VIDIOC_G_FMT           _IOWR('V',  4, struct v4l2_format)
-
 /***** end of api definitions *****/
 
 
@@ -357,8 +333,7 @@
 
     i = hi[5] - hi[1]; // length of 4 periods (8 bits)
     if (i < vbi->bp8bl || i > vbi->bp8bh)
-       return -1;      // bad frequency
-
+       return -2;      // bad frequency
     /* AGC and sync-reference */
     min = 255, max = 0, sync = 0;
     for (i = hi[4]; i < hi[5]; ++i)
@@ -375,6 +350,7 @@
     for (i = 4*bpb + vbi->pll_adj*bpb/10; i < 16*bpb; i += bpb)
        if (p[i/FAC] > thr && p[(i+bpb)/FAC] > thr) // two ones is enough...
        {
+           fprintf(stderr, "startbyte\n");
            /* got it... */
            memset(data, 0, sizeof(data));
 
@@ -383,7 +359,7 @@
                    data[n/8] |= 1 << (n%8);
 
            if (data[0] != 0x27)        // really 11100100? (rev order!)
-               return -1;
+               return -3;
 
            if (i = vt_line(vbi, data+1))
                if (i < 0)
@@ -392,7 +368,7 @@
                    pll_add(vbi, 1, i);
            return 0;
        }
-    return -1;
+    return -4;
 }
 
 
@@ -404,16 +380,31 @@
 {
     int n, i;
     u32 seq;
-
-    n = read(vbi->fd, rawbuf, vbi->bufsize);
+    struct v4l2_buffer qbuf;
+    fd_set fds;
+    
+/*    n = -1;
+    while(n<=0)
+    {
+        FD_ZERO(&fds);
+        FD_SET(vbi->fd, &fds);
+        n = select(vbi->fd + 1, &fds, NULL, NULL, NULL);
+        if(n < 0 && errno == EINTR) continue;
+        if(n<0) perror("select");
+    } */
+    qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+    if(ioctl(vbi->fd, VIDIOC_DQBUF, &qbuf)<0)
+    {
+       perror("dqbuf");
+       return;
+    }
+    fprintf(stderr, "%d %d\n", qbuf.index, qbuf.sequence);
+    rawbuf = vbi->bufs[qbuf.index];
 
     if (dl_empty(vbi->clients))
-       return;
+        goto done;
 
-    if (n != vbi->bufsize)
-       return;
-
-    seq = *(u32 *)&rawbuf[n - 4];
+    seq = qbuf.sequence;
     if (vbi->seq+1 != seq)
     {
        out_of_sync(vbi);
@@ -422,9 +413,15 @@
     }
     vbi->seq = seq;
 
-    if (seq > 1)       // the first may contain data from prev channel
-       for (i = 0; i+vbi->bpl <= n; i += vbi->bpl)
-           vbi_line(vbi, rawbuf + i);
+    if (seq > 0)       // the first may contain data from prev channel
+       for (i = 0; i < vbi->bufsize; i += vbi->bpl)
+       {
+           fprintf(stderr, "line %d %d\n", i/vbi->bpl, vbi_line(vbi, rawbuf + i));
+       }
+
+done:
+    if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+       perror("qbuf");
 }
 
 
@@ -498,13 +495,13 @@
     {
        // line too short or offset too large or wrong sample_rate
        error("v4l2: broken vbi format specification");
-       return -1;
+//     return -1;
     }
     if (eoc > 240)
     {
        // the vbi_line routine can hold max 240 values in its work buffer
        error("v4l2: unable to handle these sampling parameters");
-       return -1;
+//     return -1;
     }
 
     vbi->bpb = bpb * FAC + 0.5;
@@ -519,58 +516,69 @@
     return 0;
 }
 
-
 static int
 setup_dev(struct vbi *vbi)
 {
     struct v4l2_format v4l2_format[1];
     struct v4l2_vbi_format *vbifmt = &v4l2_format->fmt.vbi;
-
-    if (ioctl(vbi->fd, VIDIOC_G_FMT, v4l2_format) == -1
-       || v4l2_format->type != V4L2_BUF_TYPE_VBI)
+    struct v4l2_requestbuffers req;
+    struct v4l2_buffer qbuf;
+    int i;
+    
+    vbifmt->start[0]=0;
+    vbifmt->start[1]=313;
+    vbifmt->count[0]=16;
+    vbifmt->count[1]=16;
+    ioctl(vbi->fd, VIDIOC_S_FMT, v4l2_format);
+    
+    req.type = V4L2_BUF_TYPE_CAPTURE;
+    req.count = BUFS;
+    if(ioctl(vbi->fd, VIDIOC_REQBUFS, &req)<0)
+    {
+        perror("req");
+        return -1;
+                        
+    }
+    vbi->nbufs = req.count;
+    for(i=0; i<vbi->nbufs; i++)
     {
-       // not a v4l2 device.  assume bttv and create a standard fmt-struct.
-       int size;
-
-       vbifmt->sample_format = V4L2_VBI_SF_UBYTE;
-       vbifmt->sampling_rate = 35468950;
-       vbifmt->samples_per_line = 2048;
-       vbifmt->offset = 244;
-       if ((size = ioctl(vbi->fd, BTTV_VBISIZE, 0)) == -1)
-       {
-           // BSD or older bttv driver.
-           vbifmt->count[0] = 16;
-           vbifmt->count[1] = 16;
-       }
-       else if (size % 2048)
-       {
-           error("broken bttv driver (bad buffer size)");
-           return -1;
-       }
-       else
-       {
-           size /= 2048;
-           vbifmt->count[0] = size/2;
-           vbifmt->count[1] = size - size/2;
-       }
+        qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+        qbuf.index = i;
+        if(ioctl(vbi->fd, VIDIOC_QUERYBUF, &qbuf)<0)
+        {
+            perror("querybuf");
+            return -1;
+        }
+        vbi->bufs[i] = mmap(NULL, qbuf.length, PROT_READ, MAP_SHARED, vbi->fd, 
+qbuf.offset);
+        if((int)vbi->bufs[i]==-1)
+        {
+            perror("mmap");
+            return -1;
+        }
+        if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+        {
+            perror("qbuf");
+            return -1;
+        }
+    }
+    i = V4L2_BUF_TYPE_CAPTURE;
+    if(ioctl(vbi->fd, VIDIOC_STREAMON, &i)<0)
+    {
+        perror("streamon");
+        return -1;
     }
 
+    vbifmt->offset = 240;
+
     if (set_decode_parms(vbi, vbifmt) == -1)
        return -1;
+       
+    fprintf(stderr, "%d %d\n", vbi->bpl, vbi->bufsize);
 
     if (vbi->bpl < 1 || vbi->bufsize < vbi->bpl || vbi->bufsize % vbi->bpl != 0)
     {
        error("strange size of vbi buffer (%d/%d)", vbi->bufsize, vbi->bpl);
        return -1;
-    }
-
-    // grow buffer if necessary
-    if (rawbuf_size < vbi->bufsize)
-    {
-       if (rawbuf)
-           free(rawbuf);
-       if (not(rawbuf = malloc(rawbuf_size = vbi->bufsize)))
-           out_of_mem(rawbuf_size); // old buffer already freed.  abort.
     }
 
     return 0;
diff -urN alevt-1.6.0/vbi.c~ alevt-1.6.0.wks/vbi.c~
--- alevt-1.6.0/vbi.c~  Thu Jan  1 02:00:00 1970
+++ alevt-1.6.0.wks/vbi.c~      Wed Oct 25 18:58:38 2000
@@ -0,0 +1,673 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include "os.h"
+#include "vt.h"
+#include "misc.h"
+#include "vbi.h"
+#include "fdset.h"
+#include "hamm.h"
+#include "lang.h"
+#include <linux/fs.h>
+#include <linux/videodev.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#define FAC    (1<<16)         // factor for fix-point arithmetic
+
+static u8 *rawbuf;             // one common buffer for raw vbi data.
+static int rawbuf_size;                // its current size
+
+
+/***** bttv api *****/
+
+#define BASE_VIDIOCPRIVATE     192
+#define BTTV_VERSION           _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+#define BTTV_VBISIZE           _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
+
+/***** end of api definitions *****/
+
+
+
+static void
+out_of_sync(struct vbi *vbi)
+{
+    int i;
+
+    // discard all in progress pages
+    for (i = 0; i < 8; ++i)
+       vbi->rpage[i].page->flags &= ~PG_ACTIVE;
+}
+
+
+// send an event to all clients
+
+static void
+vbi_send(struct vbi *vbi, int type, int i1, int i2, int i3, void *p1)
+{
+    struct vt_event ev[1];
+    struct vbi_client *cl, *cln;
+
+    ev->resource = vbi;
+    ev->type = type;
+    ev->i1 = i1;
+    ev->i2 = i2;
+    ev->i3 = i3;
+    ev->p1 = p1;
+
+    for (cl = $ vbi->clients->first; cln = $ cl->node->next; cl = cln)
+       cl->handler(cl->data, ev);
+}
+
+static void
+vbi_send_page(struct vbi *vbi, struct raw_page *rvtp, int page)
+{
+    struct vt_page *cvtp = 0;
+
+    if (rvtp->page->flags & PG_ACTIVE)
+    {
+       if (rvtp->page->pgno % 256 != page)
+       {
+           rvtp->page->flags &= ~PG_ACTIVE;
+           enhance(rvtp->enh, rvtp->page);
+           if (vbi->cache)
+               cvtp = vbi->cache->op->put(vbi->cache, rvtp->page);
+           vbi_send(vbi, EV_PAGE, 0, 0, 0, cvtp ?: rvtp->page);
+       }
+    }
+}
+
+// fine tune pll
+// this routines tries to adjust the sampling point of the decoder.
+// it collects parity and hamming errors and moves the sampling point
+// a 10th of a bitlength left or right.
+
+#define PLL_SAMPLES    4       // number of err vals to collect
+#define PLL_ERROR      4       // if this err val is crossed, readjust
+//#define PLL_ADJUST   4       // max/min adjust (10th of bitlength)
+
+static void
+pll_add(struct vbi *vbi, int n, int err)
+{
+    if (vbi->pll_fixed)
+       return;
+
+    if (err > PLL_ERROR*2/3)   // limit burst errors
+       err = PLL_ERROR*2/3;
+
+    vbi->pll_err += err;
+    vbi->pll_cnt += n;
+    if (vbi->pll_cnt < PLL_SAMPLES)
+       return;
+
+    if (vbi->pll_err > PLL_ERROR)
+    {
+       if (vbi->pll_err > vbi->pll_lerr)
+           vbi->pll_dir = -vbi->pll_dir;
+       vbi->pll_lerr = vbi->pll_err;
+
+       vbi->pll_adj += vbi->pll_dir;
+       if (vbi->pll_adj < -PLL_ADJUST || vbi->pll_adj > PLL_ADJUST)
+       {
+           vbi->pll_adj = 0;
+           vbi->pll_dir = -1;
+           vbi->pll_lerr = 0;
+       }
+
+       if (debug)
+           printf("pll_adj = %2d\n", vbi->pll_adj);
+    }
+    vbi->pll_cnt = 0;
+    vbi->pll_err = 0;
+}
+
+void
+vbi_pll_reset(struct vbi *vbi, int fine_tune)
+{
+    vbi->pll_fixed = fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST;
+
+    vbi->pll_err = 0;
+    vbi->pll_lerr = 0;
+    vbi->pll_cnt = 0;
+    vbi->pll_dir = -1;
+    vbi->pll_adj = 0;
+    if (vbi->pll_fixed)
+       vbi->pll_adj = fine_tune;
+    if (debug)
+       if (vbi->pll_fixed)
+           printf("pll_reset (fixed@%d)\n", vbi->pll_adj);
+       else
+           printf("pll_reset (auto)\n");
+}
+
+// process one videotext packet
+
+static int
+vt_line(struct vbi *vbi, u8 *p)
+{
+    struct vt_page *cvtp;
+    struct raw_page *rvtp;
+    int hdr, mag, mag8, pkt, i;
+    int err = 0;
+
+    hdr = hamm16(p, &err);
+    if (err & 0xf000)
+       return -4;
+
+    mag = hdr & 7;
+    mag8 = mag?: 8;
+    pkt = (hdr >> 3) & 0x1f;
+    p += 2;
+
+    rvtp = vbi->rpage + mag;
+    cvtp = rvtp->page;
+
+    switch (pkt)
+    {
+       case 0:
+       {
+           int b1, b2, b3, b4;
+
+           b1 = hamm16(p, &err);       // page number
+           b2 = hamm16(p+2, &err);     // subpage number + flags
+           b3 = hamm16(p+4, &err);     // subpage number + flags
+           b4 = hamm16(p+6, &err);     // language code + more flags
+
+           if (vbi->ppage->page->flags & PG_MAGSERIAL)
+               vbi_send_page(vbi, vbi->ppage, b1);
+           vbi_send_page(vbi, rvtp, b1);
+
+           if (err & 0xf000)
+               return 4;
+
+           cvtp->errors = (err >> 8) + chk_parity(p + 8, 32);;
+           cvtp->pgno = mag8 * 256 + b1;
+           cvtp->subno = (b2 + b3 * 256) & 0x3f7f;
+           cvtp->lang = "\0\4\2\6\1\5\3\7"[b4 >> 5] + (latin1 ? 0 : 8);
+           cvtp->flags = b4 & 0x1f;
+           cvtp->flags |= b3 & 0xc0;
+           cvtp->flags |= (b2 & 0x80) >> 2;
+           cvtp->lines = 1;
+           cvtp->flof = 0;
+           vbi->ppage = rvtp;
+
+           pll_add(vbi, 1, cvtp->errors);
+
+           conv2latin(p + 8, 32, cvtp->lang);
+           vbi_send(vbi, EV_HEADER, cvtp->pgno, cvtp->subno, cvtp->flags, p);
+
+           if (b1 == 0xff)
+               return 0;
+
+           cvtp->flags |= PG_ACTIVE;
+           init_enhance(rvtp->enh);
+           memcpy(cvtp->data[0]+0, p, 40);
+           memset(cvtp->data[0]+40, ' ', sizeof(cvtp->data)-40);
+           return 0;
+       }
+
+       case 1 ... 24:
+       {
+           pll_add(vbi, 1, err = chk_parity(p, 40));
+
+           if (~cvtp->flags & PG_ACTIVE)
+               return 0;
+
+           cvtp->errors += err;
+           cvtp->lines |= 1 << pkt;
+           conv2latin(p, 40, cvtp->lang);
+           memcpy(cvtp->data[pkt], p, 40);
+           return 0;
+       }
+       case 26:
+       {
+           int d, t[13];
+
+           if (~cvtp->flags & PG_ACTIVE)
+               return 0;
+
+           d = hamm8(p, &err);
+           if (err & 0xf000)
+               return 4;
+
+           for (i = 0; i < 13; ++i)
+               t[i] = hamm24(p + 1 + 3*i, &err);
+           if (err & 0xf000)
+               return 4;
+
+           //printf("enhance on %x/%x\n", cvtp->pgno, cvtp->subno);
+           add_enhance(rvtp->enh, d, t);
+           return 0;
+       }
+       case 27:
+       {
+           // FLOF data (FastText)
+           int b1,b2,b3,x;
+           
+           if (~cvtp->flags & PG_ACTIVE)
+               return 0; // -1 flushes all pages.  we may never resync again :(
+
+           b1 = hamm8(p, &err);
+           b2 = hamm8(p + 37, &err);
+           if (err & 0xf000)
+               return 4;
+           if (b1 != 0 || not(b2 & 8))
+               return 0;
+
+           for (i = 0; i < 6; ++i)
+           {
+               err = 0;
+               b1 = hamm16(p+1+6*i, &err);
+               b2 = hamm16(p+3+6*i, &err);
+               b3 = hamm16(p+5+6*i, &err);
+               if (err & 0xf000)
+                   return 1;
+               x = (b2 >> 7) | ((b3 >> 5) & 0x06);
+               cvtp->link[i].pgno = ((mag ^ x) ?: 8) * 256 + b1;
+               cvtp->link[i].subno = (b2 + b3 * 256) & 0x3f7f;
+           }
+           cvtp->flof = 1;
+           return 0;
+       }
+       case 30:
+       {
+           if (mag8 != 8)
+               return 0;
+
+           p[0] = hamm8(p, &err);              // designation code
+           p[1] = hamm16(p+1, &err);           // initial page
+           p[3] = hamm16(p+3, &err);           // initial subpage + mag
+           p[5] = hamm16(p+5, &err);           // initial subpage + mag
+           if (err & 0xf000)
+               return 4;
+
+           err += chk_parity(p+20, 20);
+           conv2latin(p+20, 20, 0);
+
+           vbi_send(vbi, EV_XPACKET, mag8, pkt, err, p);
+           return 0;
+       }
+       default:
+           // unused at the moment...
+           //vbi_send(vbi, EV_XPACKET, mag8, pkt, err, p);
+           return 0;
+    }
+    return 0;
+}
+
+
+
+// process one raw vbi line
+
+static int
+vbi_line(struct vbi *vbi, u8 *p)
+{
+    u8 data[43], min, max;
+    int dt[256], hi[6], lo[6];
+    int i, n, sync, thr;
+    int bpb = vbi->bpb;
+
+    /* remove DC. edge-detector */
+    for (i = vbi->soc; i < vbi->eoc; ++i)
+       dt[i] = p[i+bpb/FAC] - p[i];    // amplifies the edges best.
+
+    /* set barrier */
+    for (i = vbi->eoc; i < vbi->eoc+16; i += 2)
+       dt[i] = 100, dt[i+1] = -100;
+
+    /* find 6 rising and falling edges */
+    for (i = vbi->soc, n = 0; n < 6; ++n)
+    {
+       while (dt[i] < 32)
+           i++;
+       hi[n] = i;
+       while (dt[i] > -32)
+           i++;
+       lo[n] = i;
+    }
+    if (i >= vbi->eoc)
+       return -1;      // not enough periods found
+
+    i = hi[5] - hi[1]; // length of 4 periods (8 bits)
+    if (i < vbi->bp8bl || i > vbi->bp8bh)
+       return -2;      // bad frequency
+
+    /* AGC and sync-reference */
+    min = 255, max = 0, sync = 0;
+    for (i = hi[4]; i < hi[5]; ++i)
+       if (p[i] > max)
+           max = p[i], sync = i;
+    for (i = lo[4]; i < lo[5]; ++i)
+       if (p[i] < min)
+           min = p[i];
+    thr = (min + max) / 2;
+
+    p += sync;
+
+    /* search start-byte 11100100 */
+    for (i = 4*bpb + vbi->pll_adj*bpb/10; i < 16*bpb; i += bpb)
+       if (p[i/FAC] > thr && p[(i+bpb)/FAC] > thr) // two ones is enough...
+       {
+           fprintf(stderr, "startbyte\n");
+           /* got it... */
+           memset(data, 0, sizeof(data));
+
+           for (n = 0; n < 43*8; ++n, i += bpb)
+               if (p[i/FAC] > thr)
+                   data[n/8] |= 1 << (n%8);
+
+           if (data[0] != 0x27)        // really 11100100? (rev order!)
+               return -3;
+
+           if (i = vt_line(vbi, data+1))
+               if (i < 0)
+                   pll_add(vbi, 2, -i);
+               else
+                   pll_add(vbi, 1, i);
+           return 0;
+       }
+    return -4;
+}
+
+
+
+// called when new vbi data is waiting
+
+static void
+vbi_handler(struct vbi *vbi, int fd)
+{
+    int n, i;
+    u32 seq;
+    struct v4l2_buffer qbuf;
+    fd_set fds;
+    
+/*    n = -1;
+    while(n<=0)
+    {
+        FD_ZERO(&fds);
+        FD_SET(vbi->fd, &fds);
+        n = select(vbi->fd + 1, &fds, NULL, NULL, NULL);
+        if(n < 0 && errno == EINTR) continue;
+        if(n<0) perror("select");
+    } */
+    qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+    if(ioctl(vbi->fd, VIDIOC_DQBUF, &qbuf)<0)
+    {
+       perror("dqbuf");
+       return;
+    }
+    fprintf(stderr, "%d %d\n", qbuf.index, qbuf.sequence);
+    rawbuf = vbi->bufs[qbuf.index];
+
+    if (dl_empty(vbi->clients))
+        goto done;
+
+    seq = qbuf.sequence;
+    if (vbi->seq+1 != seq)
+    {
+       out_of_sync(vbi);
+       if (seq < 3 && vbi->seq >= 3)
+           vbi_reset(vbi);
+    }
+    vbi->seq = seq;
+
+    if (seq > 0)       // the first may contain data from prev channel
+       for (i = 0; i < vbi->bufsize; i += vbi->bpl)
+       {
+           fprintf(stderr, "line %d %d\n", i/vbi->bpl, vbi_line(vbi, rawbuf + i));
+       }
+
+done:
+    if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+       perror("qbuf");
+}
+
+
+
+int
+vbi_add_handler(struct vbi *vbi, void *handler, void *data)
+{
+    struct vbi_client *cl;
+
+    if (not(cl = malloc(sizeof(*cl))))
+       return -1;
+    cl->handler = handler;
+    cl->data = data;
+    dl_insert_last(vbi->clients, cl->node);
+    return 0;
+}
+
+
+
+void
+vbi_del_handler(struct vbi *vbi, void *handler, void *data)
+{
+    struct vbi_client *cl;
+
+    for (cl = $ vbi->clients->first; cl->node->next; cl = $ cl->node->next)
+       if (cl->handler == handler && cl->data == data)
+       {
+           dl_remove(cl->node);
+           break;
+       }
+    return;
+}
+
+
+
+static int
+set_decode_parms(struct vbi *vbi, struct v4l2_vbi_format *p)
+{
+    double fs;         // sampling rate
+    double bpb;                // bytes per bit
+    int soc, eoc;      // start/end of clock run-in
+    int bpl;           // bytes per line
+
+    if (p->sample_format != V4L2_VBI_SF_UBYTE)
+    {
+       error("v4l2: unsupported vbi data format");
+       return -1;
+    }
+
+    // some constants from the standard:
+    //   horizontal frequency                  fh = 15625Hz
+    //   teletext bitrate                      ft = 444*fh = 6937500Hz
+    //   teletext identification sequence      10101010 10101010 11100100
+    //   13th bit of seq rel to falling hsync  12us -1us +0.4us
+    // I search for the clock run-in (10101010 10101010) from 12us-1us-12.5/ft
+    // (earliest first bit) to 12us+0.4us+3.5/ft (latest last bit)
+    //   earlist first bit                     tf = 12us-1us-12.5/ft = 9.2us
+    //   latest last bit                       tl = 12us+0.4us+3.5/ft = 12.9us
+    //   total number of used bits             n = (2+1+2+40)*8 = 360
+
+    bpl = p->samples_per_line;
+    fs = p->sampling_rate;
+    bpb = fs/6937500.0;
+    soc = (int)(9.2e-6*fs) - (int)p->offset;
+    eoc = (int)(12.9e-6*fs) - (int)p->offset;
+    if (soc < 0)
+       soc = 0;
+    if (eoc > bpl - (int)(43*8*bpb))
+       eoc = bpl - (int)(43*8*bpb);
+    if (eoc - soc < (int)(16*bpb))
+    {
+       // line too short or offset too large or wrong sample_rate
+       error("v4l2: broken vbi format specification");
+//     return -1;
+    }
+    if (eoc > 240)
+    {
+       // the vbi_line routine can hold max 240 values in its work buffer
+       error("v4l2: unable to handle these sampling parameters");
+//     return -1;
+    }
+
+    vbi->bpb = bpb * FAC + 0.5;
+    vbi->soc = soc;
+    vbi->eoc = eoc;
+    vbi->bp8bl = 0.97 * 8*bpb; // -3% tolerance
+    vbi->bp8bh = 1.03 * 8*bpb; // +3% tolerance
+
+    vbi->bpl = bpl;
+    vbi->bufsize = bpl * (p->count[0] + p->count[1]);
+
+    return 0;
+}
+
+static int
+setup_dev(struct vbi *vbi)
+{
+    struct v4l2_format v4l2_format[1];
+    struct v4l2_vbi_format *vbifmt = &v4l2_format->fmt.vbi;
+    struct v4l2_requestbuffers req;
+    struct v4l2_buffer qbuf;
+    int i;
+    
+    vbifmt->start[0]=0;
+    vbifmt->start[1]=313;
+    vbifmt->count[0]=16;
+    vbifmt->count[1]=16;
+    ioctl(vbi->fd, VIDIOC_S_FMT, v4l2_format);
+    
+    req.type = V4L2_BUF_TYPE_CAPTURE;
+    req.count = BUFS;
+    if(ioctl(vbi->fd, VIDIOC_REQBUFS, &req)<0)
+    {
+        perror("req");
+        return -1;
+                        
+    }
+    vbi->nbufs = req.count;
+    for(i=0; i<vbi->nbufs; i++)
+    {
+        qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+        qbuf.index = i;
+        if(ioctl(vbi->fd, VIDIOC_QUERYBUF, &qbuf)<0)
+        {
+            perror("querybuf");
+            return -1;
+        }
+        vbi->bufs[i] = mmap(NULL, qbuf.length, PROT_READ, MAP_SHARED, vbi->fd, 
+qbuf.offset);
+        if((int)vbi->bufs[i]==-1)
+        {
+            perror("mmap");
+            return -1;
+        }
+        if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+        {
+            perror("qbuf");
+            return -1;
+        }
+    }
+    i = V4L2_BUF_TYPE_CAPTURE;
+    if(ioctl(vbi->fd, VIDIOC_STREAMON, &i)<0)
+    {
+        perror("streamon");
+        return -1;
+    }
+
+    vbifmt->offset = 240;
+
+    if (set_decode_parms(vbi, vbifmt) == -1)
+       return -1;
+       
+    fprintf(stderr, "%d %d\n", vbi->bpl, vbi->bufsize);
+
+    if (vbi->bpl < 1 || vbi->bufsize < vbi->bpl || vbi->bufsize % vbi->bpl != 0)
+    {
+       error("strange size of vbi buffer (%d/%d)", vbi->bufsize, vbi->bpl);
+       return -1;
+    }
+
+    return 0;
+}
+
+
+
+struct vbi *
+vbi_open(char *vbi_name, struct cache *ca, int fine_tune, int big_buf)
+{
+    static int inited = 0;
+    struct vbi *vbi;
+    
+    if (not inited)
+       lang_init();
+    inited = 1;
+
+    if (not(vbi = malloc(sizeof(*vbi))))
+    {
+       error("out of memory");
+       goto fail1;
+    }
+
+    if ((vbi->fd = open(vbi_name, O_RDONLY)) == -1)
+    {
+       ioerror(vbi_name);
+       goto fail2;
+    }
+
+    if (big_buf != -1)
+       error("-oldbttv/-newbttv is obsolete.  option ignored.");
+
+    if (setup_dev(vbi) == -1)
+       goto fail3;
+
+    vbi->cache = ca;
+
+    dl_init(vbi->clients);
+    vbi->seq = 0;
+    out_of_sync(vbi);
+    vbi->ppage = vbi->rpage;
+
+    vbi_pll_reset(vbi, fine_tune);
+    fdset_add_fd(fds, vbi->fd, vbi_handler, vbi);
+    return vbi;
+
+fail3:
+    close(vbi->fd);
+fail2:
+    free(vbi);
+fail1:
+    return 0;
+}
+
+
+
+void
+vbi_close(struct vbi *vbi)
+{
+    fdset_del_fd(fds, vbi->fd);
+    if (vbi->cache)
+       vbi->cache->op->close(vbi->cache);
+    close(vbi->fd);
+    free(vbi);
+}
+
+
+struct vt_page *
+vbi_query_page(struct vbi *vbi, int pgno, int subno)
+{
+    struct vt_page *vtp = 0;
+
+    if (vbi->cache)
+       vtp = vbi->cache->op->get(vbi->cache, pgno, subno);
+    if (vtp == 0)
+    {
+       // EV_PAGE will come later...
+       return 0;
+    }
+
+    vbi_send(vbi, EV_PAGE, 1, 0, 0, vtp);
+    return vtp;
+}
+
+void
+vbi_reset(struct vbi *vbi)
+{
+    if (vbi->cache)
+       vbi->cache->op->reset(vbi->cache);
+    vbi_send(vbi, EV_RESET, 0, 0, 0, 0);
+}
diff -urN alevt-1.6.0/vbi.h alevt-1.6.0.wks/vbi.h
--- alevt-1.6.0/vbi.h   Thu Sep 21 20:48:13 2000
+++ alevt-1.6.0.wks/vbi.h       Wed Oct 25 18:57:56 2000
@@ -14,6 +14,8 @@
     struct enhance enh[1];
 };
 
+#define BUFS 4
+
 struct vbi
 {
     int fd;
@@ -21,6 +23,8 @@
     struct dl_head clients[1];
     // raw buffer management
     int bufsize;               // nr of bytes sent by this device
+    int nbufs;
+    unsigned char *bufs[BUFS];
     int bpl;                   // bytes per line
     u32 seq;
     // page assembly

Reply via email to