media: bttv: convert to vb2

Convert this driver from the old videobuf framework to videobuf2.

Signed-off-by: Deborah Brouwer <deborah.brouwer@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
Deborah Brouwer 2023-07-14 19:16:09 -07:00 committed by Mauro Carvalho Chehab
parent f5f17f0cb5
commit b7ec3212a7
6 changed files with 546 additions and 900 deletions

View file

@ -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

View file

@ -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)

File diff suppressed because it is too large Load diff

View file

@ -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;
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;
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;
}
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);
int bpl = (btv->fmt->depth >> 3) * btv->width;
int bpf = bpl * (btv->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);
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,
btv->fmt->vshift, 0);
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,
btv->fmt->vshift, 0);
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,
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,
voffset+cpadding,
btv->fmt->hshift,
btv->fmt->vshift,
cpadding);
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);
r = bttv_risc_planar(btv, &buf->bottom, list,
ypadding, btv->width, ypadding,
lines, uoffset + cpadding,
voffset + cpadding,
btv->fmt->hshift,
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,
btv->fmt->hshift,
btv->fmt->vshift,
0);
bttv_risc_planar(btv,&buf->bottom,
dma->sglist,
lines * ypadding,buf->vb.width,0,lines,
lines * ypadding + (uoffset >> 1),
lines * ypadding + (voffset >> 1),
btv->fmt->hshift,
btv->fmt->vshift,
0);
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);
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);
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;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
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;
}

View file

@ -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;
struct bttv *btv = vb2_get_drv_priv(q);
unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
if (0 == *count)
*count = vbibufs;
*size = IMAGE_SIZE(&fh->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;
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;
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
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);
}
list_add_tail(&buf->list, &btv->vcapture);
spin_unlock_irqrestore(&btv->s_lock, flags);
}
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);
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;
}
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;
}
if (fh->vbi_fmt.fmt.count[1] > 0) {
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
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;
}
}
/* 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;
fail:
bttv_dma_free(q,btv,buf);
return rc;
return ret;
}
static void
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
static void buf_cleanup_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);
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);
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);
}
btcx_riscmem_free(btv->c.pci, &buf->top);
btcx_riscmem_free(btv->c.pci, &buf->bottom);
}
static void vbi_buffer_release(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);
int ret;
int seqnr = 0;
struct bttv_buffer *buf;
struct bttv *btv = vb2_get_drv_priv(q);
dprintk("free %p\n",vb);
bttv_dma_free(q,fh->btv,buf);
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;
}
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,
static void stop_streaming_vbi(struct vb2_queue *q)
{
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 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:

View file

@ -26,7 +26,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf2-dma-sg.h>
#include <media/tveeprom.h>
#include <media/rc-core.h>
#include <media/i2c/ir-kbd-i2c.h>
@ -142,7 +142,8 @@ struct bttv_geometry {
struct bttv_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
struct vb2_v4l2_buffer vbuf;
struct list_head list;
/* bttv specific */
int btformat;
@ -171,6 +172,8 @@ struct bttv_vbi_fmt {
};
/* bttv-vbi.c */
extern const struct vb2_ops bttv_vbi_qops;
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
struct bttv_crop {
@ -187,28 +190,6 @@ struct bttv_crop {
__s32 max_scaled_height;
};
struct bttv_fh {
/* This must be the first field in this struct */
struct v4l2_fh fh;
struct bttv *btv;
int resources;
enum v4l2_buf_type type;
/* video capture */
struct videobuf_queue cap;
const struct bttv_format *fmt;
int width;
int height;
/* vbi capture */
struct videobuf_queue vbi;
/* Current VBI capture window as seen through this fh (cannot
be global for compatibility with earlier drivers). Protected
by struct bttv.lock and struct bttv_fh.vbi.lock. */
struct bttv_vbi_fmt vbi_fmt;
};
/* ---------------------------------------------------------- */
/* bttv-risc.c */
@ -229,22 +210,27 @@ int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
int bttv_buffer_activate_video(struct bttv *btv,
struct bttv_buffer_set *set);
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf);
int bttv_buffer_activate_vbi(struct bttv *btv,
struct bttv_buffer *vbi);
void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
struct bttv_buffer *buf);
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
/*
* 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
#define VBI_DEFLINES 16
int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
extern const struct videobuf_queue_ops bttv_vbi_qops;
/* ---------------------------------------------------------- */
/* bttv-gpio.c */
@ -269,6 +255,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
extern unsigned int bttv_verbose;
extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
int check_alloc_btres_lock(struct bttv *btv, int bit);
void free_btres_lock(struct bttv *btv, int bits);
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
#define dprintk(fmt, ...) \
@ -390,7 +378,7 @@ struct bttv {
v4l2_std_id std;
int hue, contrast, bright, saturation;
struct v4l2_framebuffer fbuf;
unsigned int field_count;
__u32 field_count;
/* various options */
int opt_combfilter;
@ -441,12 +429,21 @@ struct bttv {
unsigned int irq_me;
unsigned int users;
struct bttv_fh init;
struct v4l2_fh fh;
enum v4l2_buf_type type;
enum v4l2_field field;
int field_last;
/* video capture */
struct vb2_queue capq;
const struct bttv_format *fmt;
int width;
int height;
/* vbi capture */
struct vb2_queue vbiq;
struct bttv_vbi_fmt vbi_fmt;
unsigned int vbi_skip[2];
unsigned int vbi_count[2];
/* Application called VIDIOC_S_SELECTION. */
@ -489,6 +486,8 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
#endif
void init_irqreg(struct bttv *btv);
#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr))
#define btread(adr) readl(btv->bt848_mmio+(adr))