.vdelay         = 0x20,
                .vbipack        = 255,
                .sram           = 0,
+               /* ITU-R frame line number of the first VBI line
+                  we can capture, of the first and second field. */
+               .vbistart       = { 7,320 },
        },{
                .v4l2_id        = V4L2_STD_NTSC_M,
                .name           = "NTSC",
                .vdelay         = 0x1a,
                .vbipack        = 144,
                .sram           = 1,
+               .vbistart       = { 10, 273 },
        },{
                .v4l2_id        = V4L2_STD_SECAM,
                .name           = "SECAM",
                .vdelay         = 0x20,
                .vbipack        = 255,
                .sram           = 0, /* like PAL, correct? */
+               .vbistart       = { 7, 320 },
        },{
                .v4l2_id        = V4L2_STD_PAL_Nc,
                .name           = "PAL-Nc",
                .vdelay         = 0x1a,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = { 7, 320 },
        },{
                .v4l2_id        = V4L2_STD_PAL_M,
                .name           = "PAL-M",
                .vdelay         = 0x1a,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = { 10, 273 },
        },{
                .v4l2_id        = V4L2_STD_PAL_N,
                .name           = "PAL-N",
                .vdelay         = 0x20,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = { 7, 320},
        },{
                .v4l2_id        = V4L2_STD_NTSC_M_JP,
                .name           = "NTSC-JP",
                .vdelay         = 0x16,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = {10, 273},
        },{
                /* that one hopefully works with the strange timing
                 * which video recorders produce when playing a NTSC
                .vbipack        = 255,
                .vtotal         = 524,
                .sram           = -1,
+               .vbistart       = { 10, 273 },
        }
 };
 static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
                fmt->count[0]         = fmt2.fmt.vbi.count[0];
                fmt->start[1]         = fmt2.fmt.vbi.start[1];
                fmt->count[1]         = fmt2.fmt.vbi.count[1];
-               if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
-                       fmt->flags   |= V4L2_VBI_UNSYNC;
-               if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
-                       fmt->flags   |= V4L2_VBI_INTERLACED;
+               if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
+                       fmt->flags   |= VBI_UNSYNC;
+               if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
+                       fmt->flags   |= VBI_INTERLACED;
                return 0;
        }
        case VIDIOCSVBIFMT:
 
 #include <asm/io.h>
 #include "bttvp.h"
 
+/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
+   bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
+   HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
+   of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
+#define VBI_OFFSET ((64 + 0) * 2)
+
 #define VBI_DEFLINES 16
 #define VBI_MAXLINES 32
 
 void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
 {
        const struct bttv_tvnorm *tvnorm;
-       u32 start0,start1;
-       s32 count0,count1,count;
+       s64 count0,count1,count;
 
        tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
        f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
        f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
        f->fmt.vbi.samples_per_line = 2048;
        f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = 244;
+       f->fmt.vbi.offset           = VBI_OFFSET;
        f->fmt.vbi.flags            = 0;
-       switch (fh->btv->tvnorm) {
-       case 1: /* NTSC */
-               start0 = 10;
-               start1 = 273;
-               break;
-       case 0: /* PAL */
-       case 2: /* SECAM */
-       default:
-               start0 = 7;
-               start1 = 320;
-       }
 
-       count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0;
-       count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1;
-       count  = max(count0,count1);
-       if (count > VBI_MAXLINES)
-               count = VBI_MAXLINES;
-       if (count < 1)
-               count = 1;
+       /* s64 to prevent overflow. */
+       count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
+               - tvnorm->vbistart[0];
+       count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
+               - tvnorm->vbistart[1];
+       count  = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
 
-       f->fmt.vbi.start[0] = start0;
-       f->fmt.vbi.start[1] = start1;
+       f->fmt.vbi.start[0] = tvnorm->vbistart[0];
+       f->fmt.vbi.start[1] = tvnorm->vbistart[1];
        f->fmt.vbi.count[0] = count;
        f->fmt.vbi.count[1] = count;
+
+       f->fmt.vbi.reserved[0] = 0;
+       f->fmt.vbi.reserved[1] = 0;
 }
 
 void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
        f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
        f->fmt.vbi.samples_per_line = 2048;
        f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = 244;
+       f->fmt.vbi.offset           = VBI_OFFSET;
+       f->fmt.vbi.start[0]         = tvnorm->vbistart[0];
+       f->fmt.vbi.start[1]         = tvnorm->vbistart[1];
        f->fmt.vbi.count[0]         = fh->lines;
        f->fmt.vbi.count[1]         = fh->lines;
        f->fmt.vbi.flags            = 0;
-       switch (fh->btv->tvnorm) {
-       case 1: /* NTSC */
-               f->fmt.vbi.start[0] = 10;
-               f->fmt.vbi.start[1] = 273;
-               break;
-       case 0: /* PAL */
-       case 2: /* SECAM */
-       default:
-               f->fmt.vbi.start[0] = 7;
-               f->fmt.vbi.start[1] = 319;
-       }
 }
 
 /* ----------------------------------------------------------------------- */
 
 
 #define UNSET (-1U)
 
+#define clamp(x, low, high) min (max (low, x), high)
+
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm {
        u8    vbipack;
        u16   vtotal;
        int   sram;
+       /* ITU-R frame line number of the first VBI line we can
+          capture, of the first and second field. */
+       u16   vbistart[2];
 };
 extern const struct bttv_tvnorm bttv_tvnorms[];
 
 
                        dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
                        break;
                }
+               if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
+                       err = -EINVAL;
+                       break;
+               }
                memset(fmt, 0, sizeof(*fmt));
                fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
                fmt->sampling_rate    = fmt2->fmt.vbi.sampling_rate;
        {
                struct vbi_format      *fmt = arg;
 
+               if (VIDEO_PALETTE_RAW != fmt->sample_format) {
+                       err = -EINVAL;
+                       break;
+               }
+
                fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
                memset(fmt2, 0, sizeof(*fmt2));
 
 
                if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
                    fmt2->fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
-                   VIDEO_PALETTE_RAW              != fmt->sample_format    ||
+                   fmt2->fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
                    fmt2->fmt.vbi.start[0]         != fmt->start[0]         ||
                    fmt2->fmt.vbi.count[0]         != fmt->count[0]         ||
                    fmt2->fmt.vbi.start[1]         != fmt->start[1]         ||