162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci    bttv - Bt848 frame grabber driver
562306a36Sopenharmony_ci    vbi interface
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci    (c) 2002 Gerd Knorr <kraxel@bytesex.org>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci    Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
1062306a36Sopenharmony_ci    Sponsored by OPQ Systems AB
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci*/
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/errno.h>
1862306a36Sopenharmony_ci#include <linux/fs.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/interrupt.h>
2162306a36Sopenharmony_ci#include <linux/kdev_t.h>
2262306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
2362306a36Sopenharmony_ci#include <asm/io.h>
2462306a36Sopenharmony_ci#include "bttvp.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Offset from line sync pulse leading edge (0H) to start of VBI capture,
2762306a36Sopenharmony_ci   in fCLKx2 pixels.  According to the datasheet, VBI capture starts
2862306a36Sopenharmony_ci   VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET
2962306a36Sopenharmony_ci   is 64 fCLKx1 pixels wide.  VBI_HDELAY is set to 0, so this should be
3062306a36Sopenharmony_ci   (64 + 0) * 2 = 128 fCLKx2 pixels.  But it's not!  The datasheet is
3162306a36Sopenharmony_ci   Just Plain Wrong.  The real value appears to be different for
3262306a36Sopenharmony_ci   different revisions of the bt8x8 chips, and to be affected by the
3362306a36Sopenharmony_ci   horizontal scaling factor.  Experimentally, the value is measured
3462306a36Sopenharmony_ci   to be about 244.  */
3562306a36Sopenharmony_ci#define VBI_OFFSET 244
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic unsigned int vbibufs = 4;
3862306a36Sopenharmony_cistatic unsigned int vbi_debug;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cimodule_param(vbibufs,   int, 0444);
4162306a36Sopenharmony_cimodule_param(vbi_debug, int, 0644);
4262306a36Sopenharmony_ciMODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");
4362306a36Sopenharmony_ciMODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#ifdef dprintk
4662306a36Sopenharmony_ci# undef dprintk
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci#define dprintk(fmt, ...)						\
4962306a36Sopenharmony_cido {									\
5062306a36Sopenharmony_ci	if (vbi_debug)							\
5162306a36Sopenharmony_ci		pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__);		\
5262306a36Sopenharmony_ci} while (0)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define IMAGE_SIZE(fmt) \
5562306a36Sopenharmony_ci	(((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */
5862306a36Sopenharmony_ci/* vbi risc code + mm                                                      */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int queue_setup_vbi(struct vb2_queue *q, unsigned int *num_buffers,
6162306a36Sopenharmony_ci			   unsigned int *num_planes, unsigned int sizes[],
6262306a36Sopenharmony_ci			   struct device *alloc_devs[])
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct bttv *btv = vb2_get_drv_priv(q);
6562306a36Sopenharmony_ci	unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (*num_planes)
6862306a36Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
6962306a36Sopenharmony_ci	*num_planes = 1;
7062306a36Sopenharmony_ci	sizes[0] = size;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void buf_queue_vbi(struct vb2_buffer *vb)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
7862306a36Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
7962306a36Sopenharmony_ci	struct bttv *btv = vb2_get_drv_priv(vq);
8062306a36Sopenharmony_ci	struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
8162306a36Sopenharmony_ci	unsigned long flags;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	spin_lock_irqsave(&btv->s_lock, flags);
8462306a36Sopenharmony_ci	if (list_empty(&btv->vcapture)) {
8562306a36Sopenharmony_ci		btv->loop_irq = BT848_RISC_VBI;
8662306a36Sopenharmony_ci		if (vb2_is_streaming(&btv->capq))
8762306a36Sopenharmony_ci			btv->loop_irq |= BT848_RISC_VIDEO;
8862306a36Sopenharmony_ci		bttv_set_dma(btv, BT848_CAP_CTL_CAPTURE_VBI_ODD |
8962306a36Sopenharmony_ci			     BT848_CAP_CTL_CAPTURE_VBI_EVEN);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	list_add_tail(&buf->list, &btv->vcapture);
9262306a36Sopenharmony_ci	spin_unlock_irqrestore(&btv->s_lock, flags);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int buf_prepare_vbi(struct vb2_buffer *vb)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	int ret = 0;
9862306a36Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
9962306a36Sopenharmony_ci	struct bttv *btv = vb2_get_drv_priv(vq);
10062306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
10162306a36Sopenharmony_ci	struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
10262306a36Sopenharmony_ci	unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (vb2_plane_size(vb, 0) < size)
10562306a36Sopenharmony_ci		return -EINVAL;
10662306a36Sopenharmony_ci	vb2_set_plane_payload(vb, 0, size);
10762306a36Sopenharmony_ci	buf->vbuf.field = V4L2_FIELD_NONE;
10862306a36Sopenharmony_ci	ret = bttv_buffer_risc_vbi(btv, buf);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return ret;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic void buf_cleanup_vbi(struct vb2_buffer *vb)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
11662306a36Sopenharmony_ci	struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
11762306a36Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
11862306a36Sopenharmony_ci	struct bttv *btv = vb2_get_drv_priv(vq);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	btcx_riscmem_free(btv->c.pci, &buf->top);
12162306a36Sopenharmony_ci	btcx_riscmem_free(btv->c.pci, &buf->bottom);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	int seqnr = 0;
12762306a36Sopenharmony_ci	struct bttv_buffer *buf;
12862306a36Sopenharmony_ci	struct bttv *btv = vb2_get_drv_priv(q);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	btv->framedrop = 0;
13162306a36Sopenharmony_ci	if (!check_alloc_btres_lock(btv, RESOURCE_VBI)) {
13262306a36Sopenharmony_ci		if (btv->field_count)
13362306a36Sopenharmony_ci			seqnr++;
13462306a36Sopenharmony_ci		while (!list_empty(&btv->vcapture)) {
13562306a36Sopenharmony_ci			buf = list_entry(btv->vcapture.next,
13662306a36Sopenharmony_ci					 struct bttv_buffer, list);
13762306a36Sopenharmony_ci			list_del(&buf->list);
13862306a36Sopenharmony_ci			buf->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
13962306a36Sopenharmony_ci			vb2_buffer_done(&buf->vbuf.vb2_buf,
14062306a36Sopenharmony_ci					VB2_BUF_STATE_QUEUED);
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci		return -EBUSY;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	if (!vb2_is_streaming(&btv->capq)) {
14562306a36Sopenharmony_ci		init_irqreg(btv);
14662306a36Sopenharmony_ci		btv->field_count = 0;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci	return 0;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void stop_streaming_vbi(struct vb2_queue *q)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct bttv *btv = vb2_get_drv_priv(q);
15462306a36Sopenharmony_ci	unsigned long flags;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	vb2_wait_for_all_buffers(q);
15762306a36Sopenharmony_ci	spin_lock_irqsave(&btv->s_lock, flags);
15862306a36Sopenharmony_ci	free_btres_lock(btv, RESOURCE_VBI);
15962306a36Sopenharmony_ci	if (!vb2_is_streaming(&btv->capq)) {
16062306a36Sopenharmony_ci		/* stop field counter */
16162306a36Sopenharmony_ci		btand(~BT848_INT_VSYNC, BT848_INT_MASK);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	spin_unlock_irqrestore(&btv->s_lock, flags);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ciconst struct vb2_ops bttv_vbi_qops = {
16762306a36Sopenharmony_ci	.queue_setup    = queue_setup_vbi,
16862306a36Sopenharmony_ci	.buf_queue      = buf_queue_vbi,
16962306a36Sopenharmony_ci	.buf_prepare    = buf_prepare_vbi,
17062306a36Sopenharmony_ci	.buf_cleanup	= buf_cleanup_vbi,
17162306a36Sopenharmony_ci	.start_streaming = start_streaming_vbi,
17262306a36Sopenharmony_ci	.stop_streaming = stop_streaming_vbi,
17362306a36Sopenharmony_ci	.wait_prepare   = vb2_ops_wait_prepare,
17462306a36Sopenharmony_ci	.wait_finish    = vb2_ops_wait_finish,
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
18062306a36Sopenharmony_ci			__s32 crop_start)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	__s32 min_start, max_start, max_end, f2_offset;
18362306a36Sopenharmony_ci	unsigned int i;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* For compatibility with earlier driver versions we must pretend
18662306a36Sopenharmony_ci	   the VBI and video capture window may overlap. In reality RISC
18762306a36Sopenharmony_ci	   magic aborts VBI capturing at the first line of video capturing,
18862306a36Sopenharmony_ci	   leaving the rest of the buffer unchanged, usually all zero.
18962306a36Sopenharmony_ci	   VBI capturing must always start before video capturing. >> 1
19062306a36Sopenharmony_ci	   because cropping counts field lines times two. */
19162306a36Sopenharmony_ci	min_start = tvnorm->vbistart[0];
19262306a36Sopenharmony_ci	max_start = (crop_start >> 1) - 1;
19362306a36Sopenharmony_ci	max_end = (tvnorm->cropcap.bounds.top
19462306a36Sopenharmony_ci		   + tvnorm->cropcap.bounds.height) >> 1;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (min_start > max_start)
19762306a36Sopenharmony_ci		return -EBUSY;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	WARN_ON(max_start >= max_end);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	f->sampling_rate    = tvnorm->Fsc;
20262306a36Sopenharmony_ci	f->samples_per_line = VBI_BPL;
20362306a36Sopenharmony_ci	f->sample_format    = V4L2_PIX_FMT_GREY;
20462306a36Sopenharmony_ci	f->offset           = VBI_OFFSET;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	for (i = 0; i < 2; ++i) {
20962306a36Sopenharmony_ci		if (0 == f->count[i]) {
21062306a36Sopenharmony_ci			/* No data from this field. We leave f->start[i]
21162306a36Sopenharmony_ci			   alone because VIDIOCSVBIFMT is w/o and EINVALs
21262306a36Sopenharmony_ci			   when a driver does not support exactly the
21362306a36Sopenharmony_ci			   requested parameters. */
21462306a36Sopenharmony_ci		} else {
21562306a36Sopenharmony_ci			s64 start, count;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci			start = clamp(f->start[i], min_start, max_start);
21862306a36Sopenharmony_ci			/* s64 to prevent overflow. */
21962306a36Sopenharmony_ci			count = (s64) f->start[i] + f->count[i] - start;
22062306a36Sopenharmony_ci			f->start[i] = start;
22162306a36Sopenharmony_ci			f->count[i] = clamp(count, (s64) 1,
22262306a36Sopenharmony_ci					    max_end - start);
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		min_start += f2_offset;
22662306a36Sopenharmony_ci		max_start += f2_offset;
22762306a36Sopenharmony_ci		max_end += f2_offset;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (0 == (f->count[0] | f->count[1])) {
23162306a36Sopenharmony_ci		/* As in earlier driver versions. */
23262306a36Sopenharmony_ci		f->start[0] = tvnorm->vbistart[0];
23362306a36Sopenharmony_ci		f->start[1] = tvnorm->vbistart[1];
23462306a36Sopenharmony_ci		f->count[0] = 1;
23562306a36Sopenharmony_ci		f->count[1] = 1;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	f->flags = 0;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	f->reserved[0] = 0;
24162306a36Sopenharmony_ci	f->reserved[1] = 0;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ciint bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct bttv *btv = video_drvdata(file);
24962306a36Sopenharmony_ci	const struct bttv_tvnorm *tvnorm;
25062306a36Sopenharmony_ci	__s32 crop_start;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	mutex_lock(&btv->lock);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	tvnorm = &bttv_tvnorms[btv->tvnorm];
25562306a36Sopenharmony_ci	crop_start = btv->crop_start;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	mutex_unlock(&btv->lock);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ciint bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct bttv *btv = video_drvdata(file);
26662306a36Sopenharmony_ci	const struct bttv_tvnorm *tvnorm;
26762306a36Sopenharmony_ci	__s32 start1, end;
26862306a36Sopenharmony_ci	int rc;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	mutex_lock(&btv->lock);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	rc = -EBUSY;
27362306a36Sopenharmony_ci	if (btv->resources & RESOURCE_VBI)
27462306a36Sopenharmony_ci		goto fail;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	tvnorm = &bttv_tvnorms[btv->tvnorm];
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
27962306a36Sopenharmony_ci	if (0 != rc)
28062306a36Sopenharmony_ci		goto fail;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
28362306a36Sopenharmony_ci		tvnorm->vbistart[0];
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* First possible line of video capturing. Should be
28662306a36Sopenharmony_ci	   max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
28762306a36Sopenharmony_ci	   when capturing both fields. But for compatibility we must
28862306a36Sopenharmony_ci	   pretend the VBI and video capture window may overlap,
28962306a36Sopenharmony_ci	   so end = start + 1, the lowest possible value, times two
29062306a36Sopenharmony_ci	   because vbi_fmt.end counts field lines times two. */
29162306a36Sopenharmony_ci	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	btv->vbi_fmt.fmt = frt->fmt.vbi;
29462306a36Sopenharmony_ci	btv->vbi_fmt.tvnorm = tvnorm;
29562306a36Sopenharmony_ci	btv->vbi_fmt.end = end;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	rc = 0;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci fail:
30062306a36Sopenharmony_ci	mutex_unlock(&btv->lock);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	return rc;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ciint bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	const struct bttv_tvnorm *tvnorm;
30962306a36Sopenharmony_ci	struct bttv *btv = video_drvdata(file);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	frt->fmt.vbi = btv->vbi_fmt.fmt;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	tvnorm = &bttv_tvnorms[btv->tvnorm];
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (tvnorm != btv->vbi_fmt.tvnorm) {
31662306a36Sopenharmony_ci		__s32 max_end;
31762306a36Sopenharmony_ci		unsigned int i;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		/* As in vbi_buffer_prepare() this imitates the
32062306a36Sopenharmony_ci		   behaviour of earlier driver versions after video
32162306a36Sopenharmony_ci		   standard changes, with default parameters anyway. */
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		max_end = (tvnorm->cropcap.bounds.top
32462306a36Sopenharmony_ci			   + tvnorm->cropcap.bounds.height) >> 1;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		for (i = 0; i < 2; ++i) {
32962306a36Sopenharmony_ci			__s32 new_start;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci			new_start = frt->fmt.vbi.start[i] + tvnorm->vbistart[i]
33262306a36Sopenharmony_ci				- btv->vbi_fmt.tvnorm->vbistart[i];
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci			frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
33562306a36Sopenharmony_ci			frt->fmt.vbi.count[i] =
33662306a36Sopenharmony_ci				min((__s32) frt->fmt.vbi.count[i],
33762306a36Sopenharmony_ci					  max_end - frt->fmt.vbi.start[i]);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci			max_end += tvnorm->vbistart[1]
34062306a36Sopenharmony_ci				- tvnorm->vbistart[0];
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	return 0;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_civoid bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	const struct bttv_tvnorm *tvnorm;
34962306a36Sopenharmony_ci	unsigned int real_samples_per_line;
35062306a36Sopenharmony_ci	unsigned int real_count;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	tvnorm = &bttv_tvnorms[norm];
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	f->fmt.sampling_rate    = tvnorm->Fsc;
35562306a36Sopenharmony_ci	f->fmt.samples_per_line = VBI_BPL;
35662306a36Sopenharmony_ci	f->fmt.sample_format    = V4L2_PIX_FMT_GREY;
35762306a36Sopenharmony_ci	f->fmt.offset           = VBI_OFFSET;
35862306a36Sopenharmony_ci	f->fmt.start[0]		= tvnorm->vbistart[0];
35962306a36Sopenharmony_ci	f->fmt.start[1]		= tvnorm->vbistart[1];
36062306a36Sopenharmony_ci	f->fmt.count[0]		= VBI_DEFLINES;
36162306a36Sopenharmony_ci	f->fmt.count[1]		= VBI_DEFLINES;
36262306a36Sopenharmony_ci	f->fmt.flags            = 0;
36362306a36Sopenharmony_ci	f->fmt.reserved[0]      = 0;
36462306a36Sopenharmony_ci	f->fmt.reserved[1]      = 0;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* For compatibility the buffer size must be 2 * VBI_DEFLINES *
36762306a36Sopenharmony_ci	   VBI_BPL regardless of the current video standard. */
36862306a36Sopenharmony_ci	real_samples_per_line   = 1024 + tvnorm->vbipack * 4;
36962306a36Sopenharmony_ci	real_count              = ((tvnorm->cropcap.defrect.top >> 1)
37062306a36Sopenharmony_ci				   - tvnorm->vbistart[0]);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	WARN_ON(real_samples_per_line > VBI_BPL);
37362306a36Sopenharmony_ci	WARN_ON(real_count > VBI_DEFLINES);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	f->tvnorm               = tvnorm;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* See bttv_vbi_fmt_set(). */
37862306a36Sopenharmony_ci	f->end                  = tvnorm->vbistart[0] * 2 + 2;
37962306a36Sopenharmony_ci}
380