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" tristate "BT848 Video For Linux"
depends on PCI && I2C && VIDEO_DEV depends on PCI && I2C && VIDEO_DEV
select I2C_ALGOBIT select I2C_ALGOBIT
select VIDEOBUF_DMA_SG select VIDEOBUF2_DMA_SG
depends on RC_CORE depends on RC_CORE
depends on MEDIA_RADIO_SUPPORT depends on MEDIA_RADIO_SUPPORT
select VIDEO_TUNER select VIDEO_TUNER

View File

@ -231,7 +231,15 @@
#define BT848_INT_ETBF (1<<23) #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 (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_RISC_EN (1<<27)
#define BT848_INT_RACK (1<<25) #define BT848_INT_RACK (1<<25)
#define BT848_INT_FIELD (1<<24) #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 */ /* scan lines */
sg = sglist; sg = sglist;
for (line = 0; line < store_lines; line++) { for (line = 0; line < store_lines; line++) {
if ((btv->opt_vcr_hack) && if ((line >= (store_lines - VCR_HACK_LINES)) &&
(line >= (store_lines - VCR_HACK_LINES))) (btv->opt_vcr_hack ||
(V4L2_FIELD_HAS_BOTH(btv->field) ||
btv->field == V4L2_FIELD_ALTERNATE)))
continue; continue;
while (offset && offset >= sg_dma_len(sg)) { while (offset && offset >= sg_dma_len(sg)) {
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) static void bttv_set_risc_status(struct bttv *btv)
{ {
unsigned long cmd = BT848_RISC_JUMP; 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) { if (btv->loop_irq) {
cmd |= BT848_RISC_IRQ; cmd |= BT848_RISC_IRQ;
cmd |= (btv->loop_irq & 0x0f) << 16; cmd |= (btv->loop_irq & 0x0f) << 16;
@ -410,7 +405,8 @@ static void bttv_start_dma(struct bttv *btv)
if (btv->dma_on) if (btv->dma_on)
return; return;
btwrite(btv->main.dma, BT848_RISC_STRT_ADD); 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; btv->dma_on = 1;
} }
@ -418,7 +414,8 @@ static void bttv_stop_dma(struct bttv *btv)
{ {
if (!btv->dma_on) if (!btv->dma_on)
return; 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; btv->dma_on = 0;
} }
@ -509,17 +506,50 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
return 0; return 0;
} }
void int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)
bttv_dma_free(struct videobuf_queue *q,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); const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;
videobuf_dma_unmap(q->dev, dma); struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
videobuf_dma_free(dma); struct scatterlist *list = sgt->sgl;
btcx_riscmem_free(btv->c.pci,&buf->bottom);
btcx_riscmem_free(btv->c.pci,&buf->top); if (btv->vbi_fmt.fmt.count[0] > 0)
buf->vb.state = VIDEOBUF_NEEDS_INIT; 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 int
@ -539,8 +569,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
if (vbi) { if (vbi) {
unsigned int crop, vdelay; unsigned int crop, vdelay;
vbi->vb.state = VIDEOBUF_ACTIVE; list_del(&vbi->list);
list_del(&vbi->vb.queue);
/* VDELAY is start of video, end of VBI capturing. */ /* VDELAY is start of video, end of VBI capturing. */
crop = btread(BT848_E_CROP); crop = btread(BT848_E_CROP);
@ -581,16 +610,13 @@ bttv_buffer_activate_video(struct bttv *btv,
/* video capture */ /* video capture */
if (NULL != set->top && NULL != set->bottom) { if (NULL != set->top && NULL != set->bottom) {
if (set->top == set->bottom) { if (set->top == set->bottom) {
set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->list.next)
if (set->top->vb.queue.next) list_del(&set->top->list);
list_del(&set->top->vb.queue);
} else { } else {
set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->list.next)
set->bottom->vb.state = VIDEOBUF_ACTIVE; list_del(&set->top->list);
if (set->top->vb.queue.next) if (set->bottom->list.next)
list_del(&set->top->vb.queue); list_del(&set->bottom->list);
if (set->bottom->vb.queue.next)
list_del(&set->bottom->vb.queue);
} }
bttv_apply_geo(btv, &set->top->geo, 1); bttv_apply_geo(btv, &set->top->geo, 1);
bttv_apply_geo(btv, &set->bottom->geo,0); 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), btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
~0x0f, BT848_COLOR_CTL); ~0x0f, BT848_COLOR_CTL);
} else if (NULL != set->top) { } else if (NULL != set->top) {
set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->list.next)
if (set->top->vb.queue.next) list_del(&set->top->list);
list_del(&set->top->vb.queue);
bttv_apply_geo(btv, &set->top->geo,1); bttv_apply_geo(btv, &set->top->geo,1);
bttv_apply_geo(btv, &set->top->geo,0); bttv_apply_geo(btv, &set->top->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, 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->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else if (NULL != set->bottom) { } else if (NULL != set->bottom) {
set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->bottom->list.next)
if (set->bottom->vb.queue.next) list_del(&set->bottom->list);
list_del(&set->bottom->vb.queue);
bttv_apply_geo(btv, &set->bottom->geo,1); bttv_apply_geo(btv, &set->bottom->geo,1);
bttv_apply_geo(btv, &set->bottom->geo,0); bttv_apply_geo(btv, &set->bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
@ -637,58 +661,54 @@ bttv_buffer_activate_video(struct bttv *btv,
int int
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
{ {
int r = 0;
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm; const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
struct scatterlist *list = sgt->sgl;
dprintk("%d: buffer field: %s format: 0x%08x size: %dx%d\n", unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;
btv->c.nr, v4l2_field_names[buf->vb.field],
btv->fmt->fourcc, buf->vb.width, buf->vb.height);
/* packed pixel modes */ /* packed pixel modes */
if (btv->fmt->flags & FORMAT_FLAGS_PACKED) { if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {
int bpl = (btv->fmt->depth >> 3) * buf->vb.width; int bpl = (btv->fmt->depth >> 3) * btv->width;
int bpf = bpl * (buf->vb.height >> 1); int bpf = bpl * (btv->height >> 1);
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
V4L2_FIELD_HAS_BOTH(buf->vb.field), V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,
tvnorm, &btv->crop[!!btv->do_crop].rect); &btv->crop[!!btv->do_crop].rect);
switch (buf->vbuf.field) {
switch (buf->vb.field) {
case V4L2_FIELD_TOP: case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,dma->sglist, r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
/* offset */ 0,bpl, 0, btv->height);
/* padding */ 0,/* skip_lines */ 0,
buf->vb.height);
break; break;
case V4L2_FIELD_BOTTOM: case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,dma->sglist, r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,
0,bpl,0,0,buf->vb.height); 0, 0, btv->height);
break; break;
case V4L2_FIELD_INTERLACED: case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,dma->sglist, r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,
0,bpl,bpl,0,buf->vb.height >> 1); bpl, 0, btv->height >> 1);
bttv_risc_packed(btv,&buf->bottom,dma->sglist, r = bttv_risc_packed(btv, &buf->bottom, list, bpl,
bpl,bpl,bpl,0,buf->vb.height >> 1); bpl, bpl, 0, btv->height >> 1);
break; break;
case V4L2_FIELD_SEQ_TB: case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,dma->sglist, r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
0,bpl,0,0,buf->vb.height >> 1); 0, btv->height >> 1);
bttv_risc_packed(btv,&buf->bottom,dma->sglist, r = bttv_risc_packed(btv, &buf->bottom, list, bpf,
bpf,bpl,0,0,buf->vb.height >> 1); bpl, 0, 0, btv->height >> 1);
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
return -EINVAL;
} }
} }
/* planar modes */ /* planar modes */
if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) { if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {
int uoffset, voffset; int uoffset, voffset;
int ypadding, cpadding, lines; int ypadding, cpadding, lines;
/* calculate chroma offsets */ /* calculate chroma offsets */
uoffset = buf->vb.width * buf->vb.height; uoffset = btv->width * btv->height;
voffset = buf->vb.width * buf->vb.height; voffset = btv->width * btv->height;
if (btv->fmt->flags & FORMAT_FLAGS_CrCb) { if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {
/* Y-Cr-Cb plane order */ /* Y-Cr-Cb plane order */
uoffset >>= btv->fmt->hshift; uoffset >>= btv->fmt->hshift;
@ -700,93 +720,87 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
voffset >>= btv->fmt->vshift; voffset >>= btv->fmt->vshift;
voffset += uoffset; voffset += uoffset;
} }
switch (buf->vbuf.field) {
switch (buf->vb.field) {
case V4L2_FIELD_TOP: case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width, bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
buf->vb.height,/* both_fields */ 0, 0, tvnorm,
tvnorm, &btv->crop[!!btv->do_crop].rect); &btv->crop[!!btv->do_crop].rect);
bttv_risc_planar(btv, &buf->top, dma->sglist, r = bttv_risc_planar(btv, &buf->top, list, 0,
0,buf->vb.width,0,buf->vb.height, btv->width, 0, btv->height,
uoffset, voffset, btv->fmt->hshift, uoffset, voffset,
btv->fmt->vshift, 0); btv->fmt->hshift,
btv->fmt->vshift, 0);
break; break;
case V4L2_FIELD_BOTTOM: case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width, bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
buf->vb.height,0, 0, tvnorm,
tvnorm, &btv->crop[!!btv->do_crop].rect); &btv->crop[!!btv->do_crop].rect);
bttv_risc_planar(btv, &buf->bottom, dma->sglist, r = bttv_risc_planar(btv, &buf->bottom, list, 0,
0,buf->vb.width,0,buf->vb.height, btv->width, 0, btv->height,
uoffset, voffset, btv->fmt->hshift, uoffset, voffset,
btv->fmt->vshift, 0); btv->fmt->hshift,
btv->fmt->vshift, 0);
break; break;
case V4L2_FIELD_INTERLACED: case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width, bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
buf->vb.height,1, 1, tvnorm,
tvnorm, &btv->crop[!!btv->do_crop].rect); &btv->crop[!!btv->do_crop].rect);
lines = buf->vb.height >> 1; lines = btv->height >> 1;
ypadding = buf->vb.width; ypadding = btv->width;
cpadding = buf->vb.width >> btv->fmt->hshift; cpadding = btv->width >> btv->fmt->hshift;
bttv_risc_planar(btv,&buf->top, r = bttv_risc_planar(btv, &buf->top, list, 0,
dma->sglist, btv->width, ypadding, lines,
0,buf->vb.width,ypadding,lines, uoffset, voffset,
uoffset,voffset, btv->fmt->hshift,
btv->fmt->hshift, btv->fmt->vshift, cpadding);
btv->fmt->vshift,
cpadding); r = bttv_risc_planar(btv, &buf->bottom, list,
bttv_risc_planar(btv,&buf->bottom, ypadding, btv->width, ypadding,
dma->sglist, lines, uoffset + cpadding,
ypadding,buf->vb.width,ypadding,lines, voffset + cpadding,
uoffset+cpadding, btv->fmt->hshift,
voffset+cpadding, btv->fmt->vshift, cpadding);
btv->fmt->hshift,
btv->fmt->vshift,
cpadding);
break; break;
case V4L2_FIELD_SEQ_TB: case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width, bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
buf->vb.height,1, 1, tvnorm,
tvnorm, &btv->crop[!!btv->do_crop].rect); &btv->crop[!!btv->do_crop].rect);
lines = buf->vb.height >> 1; lines = btv->height >> 1;
ypadding = buf->vb.width; ypadding = btv->width;
cpadding = buf->vb.width >> btv->fmt->hshift; cpadding = btv->width >> btv->fmt->hshift;
bttv_risc_planar(btv,&buf->top, r = bttv_risc_planar(btv, &buf->top, list, 0,
dma->sglist, btv->width, 0, lines,
0,buf->vb.width,0,lines, uoffset >> 1, voffset >> 1,
uoffset >> 1, btv->fmt->hshift,
voffset >> 1, btv->fmt->vshift, 0);
btv->fmt->hshift, r = bttv_risc_planar(btv, &buf->bottom, list,
btv->fmt->vshift, lines * ypadding,
0); btv->width, 0, lines,
bttv_risc_planar(btv,&buf->bottom, lines * ypadding + (uoffset >> 1),
dma->sglist, lines * ypadding + (voffset >> 1),
lines * ypadding,buf->vb.width,0,lines, btv->fmt->hshift,
lines * ypadding + (uoffset >> 1), btv->fmt->vshift, 0);
lines * ypadding + (voffset >> 1),
btv->fmt->hshift,
btv->fmt->vshift,
0);
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
return -EINVAL;
} }
} }
/* raw data */ /* raw data */
if (btv->fmt->flags & FORMAT_FLAGS_RAW) { if (btv->fmt->flags & FORMAT_FLAGS_RAW) {
/* build risc code */ /* 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, bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,
1, tvnorm, &btv->crop[!!btv->do_crop].rect); 1, tvnorm, &btv->crop[!!btv->do_crop].rect);
bttv_risc_packed(btv, &buf->top, dma->sglist, r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,
/* offset */ 0, RAW_BPL, /* padding */ 0, RAW_LINES);
/* skip_lines */ 0, RAW_LINES); r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,
bttv_risc_packed(btv, &buf->bottom, dma->sglist, RAW_BPL, 0, 0, RAW_LINES);
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
} }
/* copy format info */ /* copy format info */
buf->btformat = btv->fmt->btformat; buf->btformat = btv->fmt->btformat;
buf->btswap = btv->fmt->btswap; buf->btswap = btv->fmt->btswap;
return 0;
return r;
} }

View File

@ -34,16 +34,6 @@
to be about 244. */ to be about 244. */
#define VBI_OFFSET 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 vbibufs = 4;
static unsigned int vbi_debug; static unsigned int vbi_debug;
@ -67,165 +57,123 @@ do { \
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* vbi risc code + mm */ /* vbi risc code + mm */
static int vbi_buffer_setup(struct videobuf_queue *q, static int queue_setup_vbi(struct vb2_queue *q, unsigned int *num_buffers,
unsigned int *count, unsigned int *size) unsigned int *num_planes, unsigned int sizes[],
struct device *alloc_devs[])
{ {
struct bttv_fh *fh = q->priv_data; struct bttv *btv = vb2_get_drv_priv(q);
struct bttv *btv = fh->btv; unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
if (0 == *count) if (*num_planes)
*count = vbibufs; return sizes[0] < size ? -EINVAL : 0;
*num_planes = 1;
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt); sizes[0] = size;
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]);
return 0; return 0;
} }
static int vbi_buffer_prepare(struct videobuf_queue *q, static void buf_queue_vbi(struct vb2_buffer *vb)
struct videobuf_buffer *vb,
enum v4l2_field field)
{ {
struct bttv_fh *fh = q->priv_data; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct bttv *btv = fh->btv; struct vb2_queue *vq = vb->vb2_queue;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv *btv = vb2_get_drv_priv(vq);
const struct bttv_tvnorm *tvnorm; struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
unsigned int skip_lines0, skip_lines1, min_vdelay; unsigned long flags;
int redo_dma_risc;
int rc;
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt); spin_lock_irqsave(&btv->s_lock, flags);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) 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; 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; return ret;
/* 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;
} }
static void static void buf_cleanup_vbi(struct vb2_buffer *vb)
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{ {
struct bttv_fh *fh = q->priv_data; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct bttv *btv = fh->btv; struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct vb2_queue *vq = vb->vb2_queue;
struct bttv *btv = vb2_get_drv_priv(vq);
dprintk("queue %p\n",vb); btcx_riscmem_free(btv->c.pci, &buf->top);
buf->vb.state = VIDEOBUF_QUEUED; btcx_riscmem_free(btv->c.pci, &buf->bottom);
list_add_tail(&buf->vb.queue,&btv->vcapture);
if (NULL == btv->cvbi) {
fh->btv->loop_irq |= 4;
bttv_set_dma(btv,0x0c);
}
} }
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; int ret;
struct bttv *btv = fh->btv; int seqnr = 0;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_buffer *buf;
struct bttv *btv = vb2_get_drv_priv(q);
dprintk("free %p\n",vb); btv->framedrop = 0;
bttv_dma_free(q,fh->btv,buf); 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 = { static void stop_streaming_vbi(struct vb2_queue *q)
.buf_setup = vbi_buffer_setup, {
.buf_prepare = vbi_buffer_prepare, struct bttv *btv = vb2_get_drv_priv(q);
.buf_queue = vbi_buffer_queue, unsigned long flags;
.buf_release = vbi_buffer_release,
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) 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); struct bttv *btv = video_drvdata(file);
const struct bttv_tvnorm *tvnorm; const struct bttv_tvnorm *tvnorm;
__s32 start1, end; __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); mutex_lock(&btv->lock);
rc = -EBUSY; rc = -EBUSY;
if (fh->resources & RESOURCE_VBI) if (btv->resources & RESOURCE_VBI)
goto fail; goto fail;
tvnorm = &bttv_tvnorms[btv->tvnorm]; 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. */ because vbi_fmt.end counts field lines times two. */
end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; 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.fmt = frt->fmt.vbi;
btv->vbi_fmt.tvnorm = tvnorm; btv->vbi_fmt.tvnorm = tvnorm;
btv->vbi_fmt.end = end; btv->vbi_fmt.end = end;
mutex_unlock(&fh->vbi.vb_lock);
rc = 0; rc = 0;
fail: fail:

View File

@ -26,7 +26,7 @@
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h> #include <media/v4l2-fh.h>
#include <media/videobuf-dma-sg.h> #include <media/videobuf2-dma-sg.h>
#include <media/tveeprom.h> #include <media/tveeprom.h>
#include <media/rc-core.h> #include <media/rc-core.h>
#include <media/i2c/ir-kbd-i2c.h> #include <media/i2c/ir-kbd-i2c.h>
@ -142,7 +142,8 @@ struct bttv_geometry {
struct bttv_buffer { struct bttv_buffer {
/* common v4l buffer stuff -- must be first */ /* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb; struct vb2_v4l2_buffer vbuf;
struct list_head list;
/* bttv specific */ /* bttv specific */
int btformat; int btformat;
@ -171,6 +172,8 @@ struct bttv_vbi_fmt {
}; };
/* bttv-vbi.c */ /* bttv-vbi.c */
extern const struct vb2_ops bttv_vbi_qops;
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
struct bttv_crop { struct bttv_crop {
@ -187,28 +190,6 @@ struct bttv_crop {
__s32 max_scaled_height; __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 */ /* 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_risc(struct bttv *btv, struct bttv_buffer *buf);
int bttv_buffer_activate_video(struct bttv *btv, int bttv_buffer_activate_video(struct bttv *btv,
struct bttv_buffer_set *set); 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, int bttv_buffer_activate_vbi(struct bttv *btv,
struct bttv_buffer *vbi); struct bttv_buffer *vbi);
void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
struct bttv_buffer *buf);
/* ---------------------------------------------------------- */ /* ---------------------------------------------------------- */
/* bttv-vbi.c */ /* 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 #define VBI_DEFLINES 16
int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); 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_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); 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 */ /* bttv-gpio.c */
@ -269,6 +255,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
extern unsigned int bttv_verbose; extern unsigned int bttv_verbose;
extern unsigned int bttv_debug; extern unsigned int bttv_debug;
extern unsigned int bttv_gpio; 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); extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
#define dprintk(fmt, ...) \ #define dprintk(fmt, ...) \
@ -390,7 +378,7 @@ struct bttv {
v4l2_std_id std; v4l2_std_id std;
int hue, contrast, bright, saturation; int hue, contrast, bright, saturation;
struct v4l2_framebuffer fbuf; struct v4l2_framebuffer fbuf;
unsigned int field_count; __u32 field_count;
/* various options */ /* various options */
int opt_combfilter; int opt_combfilter;
@ -441,12 +429,21 @@ struct bttv {
unsigned int irq_me; unsigned int irq_me;
unsigned int users; 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; const struct bttv_format *fmt;
int width; int width;
int height; int height;
/* vbi capture */
struct vb2_queue vbiq;
struct bttv_vbi_fmt vbi_fmt; struct bttv_vbi_fmt vbi_fmt;
unsigned int vbi_skip[2];
unsigned int vbi_count[2]; unsigned int vbi_count[2];
/* Application called VIDIOC_S_SELECTION. */ /* Application called VIDIOC_S_SELECTION. */
@ -489,6 +486,8 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
#endif #endif
void init_irqreg(struct bttv *btv);
#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr))
#define btread(adr) readl(btv->bt848_mmio+(adr)) #define btread(adr) readl(btv->bt848_mmio+(adr))