Commit b7ec3212 authored by Deborah Brouwer's avatar Deborah Brouwer Committed by Mauro Carvalho Chehab
Browse files

media: bttv: convert to vb2



Convert this driver from the old videobuf framework to videobuf2.

Signed-off-by: default avatarDeborah Brouwer <deborah.brouwer@collabora.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent f5f17f0c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ config VIDEO_BT848
	tristate "BT848 Video For Linux"
	depends on PCI && I2C && VIDEO_DEV
	select I2C_ALGOBIT
	select VIDEOBUF_DMA_SG
	select VIDEOBUF2_DMA_SG
	depends on RC_CORE
	depends on MEDIA_RADIO_SUPPORT
	select VIDEO_TUNER
+8 −0
Original line number Diff line number Diff line
@@ -231,7 +231,15 @@

#define BT848_INT_ETBF         (1<<23)

#define BT848_RISC_VIDEO 1
#define BT848_RISC_TOP 2
#define BT848_RISC_VBI 4

#define BT848_INT_RISCS   (0xf<<28)
#define BT848_INT_RISCS_VIDEO   (BT848_RISC_VIDEO << 28)
#define BT848_INT_RISCS_TOP   (BT848_RISC_TOP << 28)
#define BT848_INT_RISCS_VBI   (BT848_RISC_VBI << 28)

#define BT848_INT_RISC_EN (1<<27)
#define BT848_INT_RACK    (1<<25)
#define BT848_INT_FIELD   (1<<24)
+257 −572

File changed.

Preview size limit exceeded, changes collapsed.

+149 −135
Original line number Diff line number Diff line
@@ -67,8 +67,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
	/* scan lines */
	sg = sglist;
	for (line = 0; line < store_lines; line++) {
		if ((btv->opt_vcr_hack) &&
		    (line >= (store_lines - VCR_HACK_LINES)))
		if ((line >= (store_lines - VCR_HACK_LINES)) &&
		    (btv->opt_vcr_hack ||
		    (V4L2_FIELD_HAS_BOTH(btv->field) ||
		     btv->field == V4L2_FIELD_ALTERNATE)))
			continue;
		while (offset && offset >= sg_dma_len(sg)) {
			offset -= sg_dma_len(sg);
@@ -363,13 +365,6 @@ bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
static void bttv_set_risc_status(struct bttv *btv)
{
	unsigned long cmd = BT848_RISC_JUMP;
	/*
	 * The value of btv->loop_irq sets or resets the RISC_STATUS for video
	 * and/or vbi by setting the value of bits [23:16] in the first dword
	 * of the JUMP instruction:
	 * video risc: set (1) and reset (~1)
	 * vbi risc: set(4) and reset (~4)
	 */
	if (btv->loop_irq) {
		cmd |= BT848_RISC_IRQ;
		cmd |= (btv->loop_irq  & 0x0f) << 16;
@@ -410,7 +405,8 @@ static void bttv_start_dma(struct bttv *btv)
	if (btv->dma_on)
		return;
	btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
	btor(0x3, BT848_GPIO_DMA_CTL);
	btor(BT848_GPIO_DMA_CTL_RISC_ENABLE | BT848_GPIO_DMA_CTL_FIFO_ENABLE,
	     BT848_GPIO_DMA_CTL);
	btv->dma_on = 1;
}

@@ -418,7 +414,8 @@ static void bttv_stop_dma(struct bttv *btv)
{
	if (!btv->dma_on)
		return;
	btand(~0x3, BT848_GPIO_DMA_CTL);
	btand(~(BT848_GPIO_DMA_CTL_RISC_ENABLE |
		BT848_GPIO_DMA_CTL_FIFO_ENABLE), BT848_GPIO_DMA_CTL);
	btv->dma_on = 0;
}

@@ -509,17 +506,50 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
	return 0;
}

void
bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)
{
	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
	int r = 0;
	unsigned int offset;
	unsigned int bpl = 2044; /* max. vbipack */
	unsigned int padding = VBI_BPL - bpl;
	unsigned int skip_lines0 = 0;
	unsigned int skip_lines1 = 0;
	unsigned int min_vdelay = MIN_VDELAY;

	const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;
	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
	struct scatterlist *list = sgt->sgl;

	if (btv->vbi_fmt.fmt.count[0] > 0)
		skip_lines0 = max(0, (btv->vbi_fmt.fmt.start[0] -
					tvnorm->vbistart[0]));
	if (btv->vbi_fmt.fmt.count[1] > 0)
		skip_lines1 = max(0, (btv->vbi_fmt.fmt.start[1] -
					tvnorm->vbistart[1]));

	if (btv->vbi_fmt.fmt.count[0] > 0) {
		r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, padding,
				     skip_lines0, btv->vbi_fmt.fmt.count[0]);
		if (r)
			return r;
	}

	videobuf_waiton(q, &buf->vb, 0, 0);
	videobuf_dma_unmap(q->dev, dma);
	videobuf_dma_free(dma);
	btcx_riscmem_free(btv->c.pci,&buf->bottom);
	btcx_riscmem_free(btv->c.pci,&buf->top);
	buf->vb.state = VIDEOBUF_NEEDS_INIT;
	if (btv->vbi_fmt.fmt.count[1] > 0) {
		offset = btv->vbi_fmt.fmt.count[0] * VBI_BPL;
		r = bttv_risc_packed(btv, &buf->bottom, list, offset, bpl,
				     padding, skip_lines1,
				     btv->vbi_fmt.fmt.count[1]);
		if (r)
			return r;
	}

	if (btv->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
		min_vdelay += btv->vbi_fmt.end - tvnorm->cropcap.bounds.top;

	/* For bttv_buffer_activate_vbi(). */
	buf->geo.vdelay = min_vdelay;

	return r;
}

int
@@ -539,8 +569,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
	if (vbi) {
		unsigned int crop, vdelay;

		vbi->vb.state = VIDEOBUF_ACTIVE;
		list_del(&vbi->vb.queue);
		list_del(&vbi->list);

		/* VDELAY is start of video, end of VBI capturing. */
		crop = btread(BT848_E_CROP);
@@ -581,16 +610,13 @@ bttv_buffer_activate_video(struct bttv *btv,
	/* video capture */
	if (NULL != set->top  &&  NULL != set->bottom) {
		if (set->top == set->bottom) {
			set->top->vb.state    = VIDEOBUF_ACTIVE;
			if (set->top->vb.queue.next)
				list_del(&set->top->vb.queue);
			if (set->top->list.next)
				list_del(&set->top->list);
		} else {
			set->top->vb.state    = VIDEOBUF_ACTIVE;
			set->bottom->vb.state = VIDEOBUF_ACTIVE;
			if (set->top->vb.queue.next)
				list_del(&set->top->vb.queue);
			if (set->bottom->vb.queue.next)
				list_del(&set->bottom->vb.queue);
			if (set->top->list.next)
				list_del(&set->top->list);
			if (set->bottom->list.next)
				list_del(&set->bottom->list);
		}
		bttv_apply_geo(btv, &set->top->geo, 1);
		bttv_apply_geo(btv, &set->bottom->geo,0);
@@ -603,9 +629,8 @@ bttv_buffer_activate_video(struct bttv *btv,
		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
		      ~0x0f, BT848_COLOR_CTL);
	} else if (NULL != set->top) {
		set->top->vb.state  = VIDEOBUF_ACTIVE;
		if (set->top->vb.queue.next)
			list_del(&set->top->vb.queue);
		if (set->top->list.next)
			list_del(&set->top->list);
		bttv_apply_geo(btv, &set->top->geo,1);
		bttv_apply_geo(btv, &set->top->geo,0);
		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
@@ -614,9 +639,8 @@ bttv_buffer_activate_video(struct bttv *btv,
		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
	} else if (NULL != set->bottom) {
		set->bottom->vb.state = VIDEOBUF_ACTIVE;
		if (set->bottom->vb.queue.next)
			list_del(&set->bottom->vb.queue);
		if (set->bottom->list.next)
			list_del(&set->bottom->list);
		bttv_apply_geo(btv, &set->bottom->geo,1);
		bttv_apply_geo(btv, &set->bottom->geo,0);
		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
@@ -637,58 +661,54 @@ bttv_buffer_activate_video(struct bttv *btv,
int
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
{
	int r = 0;
	const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;
	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);

	dprintk("%d: buffer field: %s  format: 0x%08x  size: %dx%d\n",
		btv->c.nr, v4l2_field_names[buf->vb.field],
		btv->fmt->fourcc, buf->vb.width, buf->vb.height);
	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
	struct scatterlist *list = sgt->sgl;
	unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;

	/* packed pixel modes */
	if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {
		int bpl = (btv->fmt->depth >> 3) * buf->vb.width;
		int bpf = bpl * (buf->vb.height >> 1);

		bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
			      V4L2_FIELD_HAS_BOTH(buf->vb.field),
			      tvnorm, &btv->crop[!!btv->do_crop].rect);
		int bpl = (btv->fmt->depth >> 3) * btv->width;
		int bpf = bpl * (btv->height >> 1);

		switch (buf->vb.field) {
		bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
			      V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,
			      &btv->crop[!!btv->do_crop].rect);
		switch (buf->vbuf.field) {
		case V4L2_FIELD_TOP:
			bttv_risc_packed(btv,&buf->top,dma->sglist,
					 /* offset */ 0,bpl,
					 /* padding */ 0,/* skip_lines */ 0,
					 buf->vb.height);
			r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
					     0, btv->height);
			break;
		case V4L2_FIELD_BOTTOM:
			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
					 0,bpl,0,0,buf->vb.height);
			r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,
					     0, 0, btv->height);
			break;
		case V4L2_FIELD_INTERLACED:
			bttv_risc_packed(btv,&buf->top,dma->sglist,
					 0,bpl,bpl,0,buf->vb.height >> 1);
			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
					 bpl,bpl,bpl,0,buf->vb.height >> 1);
			r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,
					     bpl, 0, btv->height >> 1);
			r = bttv_risc_packed(btv, &buf->bottom, list, bpl,
					     bpl, bpl, 0, btv->height >> 1);
			break;
		case V4L2_FIELD_SEQ_TB:
			bttv_risc_packed(btv,&buf->top,dma->sglist,
					 0,bpl,0,0,buf->vb.height >> 1);
			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
					 bpf,bpl,0,0,buf->vb.height >> 1);
			r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
					     0, btv->height >> 1);
			r = bttv_risc_packed(btv, &buf->bottom, list, bpf,
					     bpl, 0, 0, btv->height >> 1);
			break;
		default:
			WARN_ON(1);
			return -EINVAL;
		}
	}

	/* planar modes */
	if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {
		int uoffset, voffset;
		int ypadding, cpadding, lines;

		/* calculate chroma offsets */
		uoffset = buf->vb.width * buf->vb.height;
		voffset = buf->vb.width * buf->vb.height;
		uoffset = btv->width * btv->height;
		voffset = btv->width * btv->height;
		if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {
			/* Y-Cr-Cb plane order */
			uoffset >>= btv->fmt->hshift;
@@ -700,93 +720,87 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
			voffset >>= btv->fmt->vshift;
			voffset  += uoffset;
		}

		switch (buf->vb.field) {
		switch (buf->vbuf.field) {
		case V4L2_FIELD_TOP:
			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
				      buf->vb.height,/* both_fields */ 0,
				      tvnorm, &btv->crop[!!btv->do_crop].rect);
			bttv_risc_planar(btv, &buf->top, dma->sglist,
					 0,buf->vb.width,0,buf->vb.height,
					 uoffset, voffset, btv->fmt->hshift,
			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
				      0, tvnorm,
				      &btv->crop[!!btv->do_crop].rect);
			r = bttv_risc_planar(btv, &buf->top, list, 0,
					     btv->width, 0, btv->height,
					     uoffset, voffset,
					     btv->fmt->hshift,
					     btv->fmt->vshift, 0);
			break;
		case V4L2_FIELD_BOTTOM:
			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
				      buf->vb.height,0,
				      tvnorm, &btv->crop[!!btv->do_crop].rect);
			bttv_risc_planar(btv, &buf->bottom, dma->sglist,
					 0,buf->vb.width,0,buf->vb.height,
					 uoffset, voffset, btv->fmt->hshift,
			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
				      0, tvnorm,
				      &btv->crop[!!btv->do_crop].rect);
			r = bttv_risc_planar(btv, &buf->bottom, list, 0,
					     btv->width, 0, btv->height,
					     uoffset, voffset,
					     btv->fmt->hshift,
					     btv->fmt->vshift, 0);
			break;
		case V4L2_FIELD_INTERLACED:
			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
				      buf->vb.height,1,
				      tvnorm, &btv->crop[!!btv->do_crop].rect);
			lines    = buf->vb.height >> 1;
			ypadding = buf->vb.width;
			cpadding = buf->vb.width >> btv->fmt->hshift;
			bttv_risc_planar(btv,&buf->top,
					 dma->sglist,
					 0,buf->vb.width,ypadding,lines,
			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
				      1, tvnorm,
				      &btv->crop[!!btv->do_crop].rect);
			lines = btv->height >> 1;
			ypadding = btv->width;
			cpadding = btv->width >> btv->fmt->hshift;
			r = bttv_risc_planar(btv, &buf->top, list, 0,
					     btv->width, ypadding, lines,
					     uoffset, voffset,
					     btv->fmt->hshift,
					 btv->fmt->vshift,
					 cpadding);
			bttv_risc_planar(btv,&buf->bottom,
					 dma->sglist,
					 ypadding,buf->vb.width,ypadding,lines,
					 uoffset+cpadding,
					     btv->fmt->vshift, cpadding);

			r = bttv_risc_planar(btv, &buf->bottom, list,
					     ypadding, btv->width, ypadding,
					     lines,  uoffset + cpadding,
					     voffset + cpadding,
					     btv->fmt->hshift,
					 btv->fmt->vshift,
					 cpadding);
					     btv->fmt->vshift, cpadding);
			break;
		case V4L2_FIELD_SEQ_TB:
			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
				      buf->vb.height,1,
				      tvnorm, &btv->crop[!!btv->do_crop].rect);
			lines    = buf->vb.height >> 1;
			ypadding = buf->vb.width;
			cpadding = buf->vb.width >> btv->fmt->hshift;
			bttv_risc_planar(btv,&buf->top,
					 dma->sglist,
					 0,buf->vb.width,0,lines,
					 uoffset >> 1,
					 voffset >> 1,
			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
				      1, tvnorm,
				      &btv->crop[!!btv->do_crop].rect);
			lines = btv->height >> 1;
			ypadding = btv->width;
			cpadding = btv->width >> btv->fmt->hshift;
			r = bttv_risc_planar(btv, &buf->top, list, 0,
					     btv->width, 0, lines,
					     uoffset >> 1, voffset >> 1,
					     btv->fmt->hshift,
					 btv->fmt->vshift,
					 0);
			bttv_risc_planar(btv,&buf->bottom,
					 dma->sglist,
					 lines * ypadding,buf->vb.width,0,lines,
					     btv->fmt->vshift, 0);
			r = bttv_risc_planar(btv, &buf->bottom, list,
					     lines * ypadding,
					     btv->width, 0, lines,
					     lines * ypadding + (uoffset >> 1),
					     lines * ypadding + (voffset >> 1),
					     btv->fmt->hshift,
					 btv->fmt->vshift,
					 0);
					     btv->fmt->vshift, 0);
			break;
		default:
			WARN_ON(1);
			return -EINVAL;
		}
	}

	/* raw data */
	if (btv->fmt->flags & FORMAT_FLAGS_RAW) {
		/* build risc code */
		buf->vb.field = V4L2_FIELD_SEQ_TB;
		buf->vbuf.field = V4L2_FIELD_SEQ_TB;
		bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,
			      1, tvnorm, &btv->crop[!!btv->do_crop].rect);
		bttv_risc_packed(btv, &buf->top,  dma->sglist,
				 /* offset */ 0, RAW_BPL, /* padding */ 0,
				 /* skip_lines */ 0, RAW_LINES);
		bttv_risc_packed(btv, &buf->bottom, dma->sglist,
				 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
		r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,
				     RAW_LINES);
		r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,
				     RAW_BPL, 0, 0, RAW_LINES);
	}

	/* copy format info */
	buf->btformat = btv->fmt->btformat;
	buf->btswap   = btv->fmt->btswap;
	return 0;

	return r;
}
+97 −157
Original line number Diff line number Diff line
@@ -34,16 +34,6 @@
   to be about 244.  */
#define VBI_OFFSET 244

/* 2048 for compatibility with earlier driver versions. The driver
   really stores 1024 + tvnorm->vbipack * 4 samples per line in the
   buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
   is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
   four bytes of the VBI image. */
#define VBI_BPL 2048

/* Compatibility. */
#define VBI_DEFLINES 16

static unsigned int vbibufs = 4;
static unsigned int vbi_debug;

@@ -67,165 +57,123 @@ do { \
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm                                                      */

static int vbi_buffer_setup(struct videobuf_queue *q,
			    unsigned int *count, unsigned int *size)
static int queue_setup_vbi(struct vb2_queue *q, unsigned int *num_buffers,
			   unsigned int *num_planes, unsigned int sizes[],
			   struct device *alloc_devs[])
{
	struct bttv_fh *fh = q->priv_data;
	struct bttv *btv = fh->btv;

	if (0 == *count)
		*count = vbibufs;

	*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
	struct bttv *btv = vb2_get_drv_priv(q);
	unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);

	dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
		fh->vbi_fmt.fmt.samples_per_line,
		fh->vbi_fmt.fmt.start[0],
		fh->vbi_fmt.fmt.start[1],
		fh->vbi_fmt.fmt.count[0],
		fh->vbi_fmt.fmt.count[1]);
	if (*num_planes)
		return sizes[0] < size ? -EINVAL : 0;
	*num_planes = 1;
	sizes[0] = size;

	return 0;
}

static int vbi_buffer_prepare(struct videobuf_queue *q,
			      struct videobuf_buffer *vb,
			      enum v4l2_field field)
static void buf_queue_vbi(struct vb2_buffer *vb)
{
	struct bttv_fh *fh = q->priv_data;
	struct bttv *btv = fh->btv;
	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
	const struct bttv_tvnorm *tvnorm;
	unsigned int skip_lines0, skip_lines1, min_vdelay;
	int redo_dma_risc;
	int rc;

	buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
		return -EINVAL;

	tvnorm = fh->vbi_fmt.tvnorm;

	/* There's no VBI_VDELAY register, RISC must skip the lines
	   we don't want. With default parameters we skip zero lines
	   as earlier driver versions did. The driver permits video
	   standard changes while capturing, so we use vbi_fmt.tvnorm
	   instead of btv->tvnorm to skip zero lines after video
	   standard changes as well. */

	skip_lines0 = 0;
	skip_lines1 = 0;

	if (fh->vbi_fmt.fmt.count[0] > 0)
		skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
				      - tvnorm->vbistart[0]));
	if (fh->vbi_fmt.fmt.count[1] > 0)
		skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
				      - tvnorm->vbistart[1]));

	redo_dma_risc = 0;

	if (btv->vbi_skip[0] != skip_lines0 ||
	    btv->vbi_skip[1] != skip_lines1 ||
	    btv->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
	    btv->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
		btv->vbi_skip[0] = skip_lines0;
		btv->vbi_skip[1] = skip_lines1;
		btv->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
		btv->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
		redo_dma_risc = 1;
	}

	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
		redo_dma_risc = 1;
		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
			goto fail;
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct vb2_queue *vq = vb->vb2_queue;
	struct bttv *btv = vb2_get_drv_priv(vq);
	struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
	unsigned long flags;

	spin_lock_irqsave(&btv->s_lock, flags);
	if (list_empty(&btv->vcapture)) {
		btv->loop_irq = BT848_RISC_VBI;
		if (vb2_is_streaming(&btv->capq))
			btv->loop_irq |= BT848_RISC_VIDEO;
		bttv_set_dma(btv, BT848_CAP_CTL_CAPTURE_VBI_ODD |
			     BT848_CAP_CTL_CAPTURE_VBI_EVEN);
	}

	if (redo_dma_risc) {
		unsigned int bpl, padding, offset;
		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);

		bpl = 2044; /* max. vbipack */
		padding = VBI_BPL - bpl;

		if (fh->vbi_fmt.fmt.count[0] > 0) {
			rc = bttv_risc_packed(btv, &buf->top,
					      dma->sglist,
					      /* offset */ 0, bpl,
					      padding, skip_lines0,
					      fh->vbi_fmt.fmt.count[0]);
			if (0 != rc)
				goto fail;
	list_add_tail(&buf->list, &btv->vcapture);
	spin_unlock_irqrestore(&btv->s_lock, flags);
}

		if (fh->vbi_fmt.fmt.count[1] > 0) {
			offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
static int buf_prepare_vbi(struct vb2_buffer *vb)
{
	int ret = 0;
	struct vb2_queue *vq = vb->vb2_queue;
	struct bttv *btv = vb2_get_drv_priv(vq);
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
	unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);

	if (vb2_plane_size(vb, 0) < size)
		return -EINVAL;
	vb2_set_plane_payload(vb, 0, size);
	buf->vbuf.field = V4L2_FIELD_NONE;
	ret = bttv_buffer_risc_vbi(btv, buf);

			rc = bttv_risc_packed(btv, &buf->bottom,
					      dma->sglist,
					      offset, bpl,
					      padding, skip_lines1,
					      fh->vbi_fmt.fmt.count[1]);
			if (0 != rc)
				goto fail;
		}
	return ret;
}

	/* VBI capturing ends at VDELAY, start of video capturing,
	   no matter where the RISC program ends. VDELAY minimum is 2,
	   bounds.top is the corresponding first field line number
	   times two. VDELAY counts half field lines. */
	min_vdelay = MIN_VDELAY;
	if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
		min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;

	/* For bttv_buffer_activate_vbi(). */
	buf->geo.vdelay = min_vdelay;

	buf->vb.state = VIDEOBUF_PREPARED;
	buf->vb.field = field;
	dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
		vb, &buf->top, &buf->bottom,
		v4l2_field_names[buf->vb.field]);
	return 0;
static void buf_cleanup_vbi(struct vb2_buffer *vb)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
	struct vb2_queue *vq = vb->vb2_queue;
	struct bttv *btv = vb2_get_drv_priv(vq);

 fail:
	bttv_dma_free(q,btv,buf);
	return rc;
	btcx_riscmem_free(btv->c.pci, &buf->top);
	btcx_riscmem_free(btv->c.pci, &buf->bottom);
}

static void
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
static int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
{
	struct bttv_fh *fh = q->priv_data;
	struct bttv *btv = fh->btv;
	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);

	dprintk("queue %p\n",vb);
	buf->vb.state = VIDEOBUF_QUEUED;
	list_add_tail(&buf->vb.queue,&btv->vcapture);
	if (NULL == btv->cvbi) {
		fh->btv->loop_irq |= 4;
		bttv_set_dma(btv,0x0c);
	int ret;
	int seqnr = 0;
	struct bttv_buffer *buf;
	struct bttv *btv = vb2_get_drv_priv(q);

	btv->framedrop = 0;
	ret = check_alloc_btres_lock(btv, RESOURCE_VBI);
	if (ret == 0) {
		if (btv->field_count)
			seqnr++;
		while (!list_empty(&btv->vcapture)) {
			buf = list_entry(btv->vcapture.next,
					 struct bttv_buffer, list);
			list_del(&buf->list);
			buf->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
			vb2_buffer_done(&buf->vbuf.vb2_buf,
					VB2_BUF_STATE_QUEUED);
		}
		return !ret;
	}
	if (!vb2_is_streaming(&btv->capq)) {
		init_irqreg(btv);
		btv->field_count = 0;
	}
	return !ret;
}

static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
static void stop_streaming_vbi(struct vb2_queue *q)
{
	struct bttv_fh *fh = q->priv_data;
	struct bttv *btv = fh->btv;
	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);

	dprintk("free %p\n",vb);
	bttv_dma_free(q,fh->btv,buf);
	struct bttv *btv = vb2_get_drv_priv(q);
	unsigned long flags;

	vb2_wait_for_all_buffers(q);
	spin_lock_irqsave(&btv->s_lock, flags);
	free_btres_lock(btv, RESOURCE_VBI);
	if (!vb2_is_streaming(&btv->capq)) {
		/* stop field counter */
		btand(~BT848_INT_VSYNC, BT848_INT_MASK);
	}
	spin_unlock_irqrestore(&btv->s_lock, flags);
}

const struct videobuf_queue_ops bttv_vbi_qops = {
	.buf_setup    = vbi_buffer_setup,
	.buf_prepare  = vbi_buffer_prepare,
	.buf_queue    = vbi_buffer_queue,
	.buf_release  = vbi_buffer_release,
const struct vb2_ops bttv_vbi_qops = {
	.queue_setup    = queue_setup_vbi,
	.buf_queue      = buf_queue_vbi,
	.buf_prepare    = buf_prepare_vbi,
	.buf_cleanup	= buf_cleanup_vbi,
	.start_streaming = start_streaming_vbi,
	.stop_streaming = stop_streaming_vbi,
	.wait_prepare   = vb2_ops_wait_prepare,
	.wait_finish    = vb2_ops_wait_finish,
};

/* ----------------------------------------------------------------------- */
@@ -316,7 +264,6 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)

int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
{
	struct bttv_fh *fh = f;
	struct bttv *btv = video_drvdata(file);
	const struct bttv_tvnorm *tvnorm;
	__s32 start1, end;
@@ -325,7 +272,7 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
	mutex_lock(&btv->lock);

	rc = -EBUSY;
	if (fh->resources & RESOURCE_VBI)
	if (btv->resources & RESOURCE_VBI)
		goto fail;

	tvnorm = &bttv_tvnorms[btv->tvnorm];
@@ -345,17 +292,10 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
	   because vbi_fmt.end counts field lines times two. */
	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;

	mutex_lock(&fh->vbi.vb_lock);

	fh->vbi_fmt.fmt    = frt->fmt.vbi;
	fh->vbi_fmt.tvnorm = tvnorm;
	fh->vbi_fmt.end    = end;
	btv->vbi_fmt.fmt = frt->fmt.vbi;
	btv->vbi_fmt.tvnorm = tvnorm;
	btv->vbi_fmt.end = end;

	mutex_unlock(&fh->vbi.vb_lock);

	rc = 0;

 fail:
Loading