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

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
...@@ -3,7 +3,7 @@ config VIDEO_BT848 ...@@ -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
......
...@@ -231,7 +231,15 @@ ...@@ -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)
......
...@@ -641,15 +641,10 @@ static const unsigned int FORMATS = ARRAY_SIZE(formats); ...@@ -641,15 +641,10 @@ static const unsigned int FORMATS = ARRAY_SIZE(formats);
#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \ #define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
RESOURCE_VIDEO_STREAM) RESOURCE_VIDEO_STREAM)
static int check_alloc_btres_lock(struct bttv *btv, int bit)
int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
{ {
int xbits; /* mutual exclusive resources */ int xbits; /* mutual exclusive resources */
if (fh->resources & bit)
/* have it already allocated */
return 1;
xbits = bit; xbits = bit;
if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM)) if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
...@@ -682,7 +677,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) ...@@ -682,7 +677,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
} }
/* it's free, grab it */ /* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit; btv->resources |= bit;
return 1; return 1;
...@@ -691,9 +685,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) ...@@ -691,9 +685,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
} }
static static
int check_btres(struct bttv_fh *fh, int bit) int check_btres(struct bttv *btv, int bit)
{ {
return (fh->resources & bit); return (btv->resources & bit);
} }
static static
...@@ -731,14 +725,12 @@ disclaim_video_lines(struct bttv *btv) ...@@ -731,14 +725,12 @@ disclaim_video_lines(struct bttv *btv)
btwrite(0xfe, BT848_O_VDELAY_LO); btwrite(0xfe, BT848_O_VDELAY_LO);
} }
static void free_btres_lock(struct bttv *btv, int bits)
void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
{ {
if ((fh->resources & bits) != bits) { if ((btv->resources & bits) != bits) {
/* trying to free resources not allocated by us ... */ /* trying to free resources not allocated by us ... */
pr_err("BUG! (btres)\n"); pr_err("BUG! (btres)\n");
} }
fh->resources &= ~bits;
btv->resources &= ~bits; btv->resources &= ~bits;
bits = btv->resources; bits = btv->resources;
...@@ -1174,7 +1166,7 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) ...@@ -1174,7 +1166,7 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
set_tvnorm(btv, norm); set_tvnorm(btv, norm);
} }
static void init_irqreg(struct bttv *btv) void init_irqreg(struct bttv *btv)
{ {
/* clear status */ /* clear status */
btwrite(0xfffffUL, BT848_INT_STAT); btwrite(0xfffffUL, BT848_INT_STAT);
...@@ -1453,23 +1445,6 @@ void bttv_gpio_tracking(struct bttv *btv, char *comment) ...@@ -1453,23 +1445,6 @@ void bttv_gpio_tracking(struct bttv *btv, char *comment)
btv->c.nr, outbits, data & outbits, data & ~outbits, comment); btv->c.nr, outbits, data & outbits, data & ~outbits, comment);
} }
static void bttv_field_count(struct bttv *btv)
{
int need_count = 0;
if (btv->users)
need_count++;
if (need_count) {
/* start field counter */
btor(BT848_INT_VSYNC,BT848_INT_MASK);
} else {
/* stop field counter */
btand(~BT848_INT_VSYNC,BT848_INT_MASK);
btv->field_count = 0;
}
}
static const struct bttv_format* static const struct bttv_format*
format_by_fourcc(int fourcc) format_by_fourcc(int fourcc)
{ {
...@@ -1487,156 +1462,132 @@ format_by_fourcc(int fourcc) ...@@ -1487,156 +1462,132 @@ format_by_fourcc(int fourcc)
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* video4linux (1) interface */ /* video4linux (1) interface */
static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
struct bttv_buffer *buf, unsigned int *num_planes, unsigned int sizes[],
const struct bttv_format *fmt, struct device *alloc_devs[])
unsigned int width, unsigned int height,
enum v4l2_field field)
{ {
int redo_dma_risc = 0; struct bttv *btv = vb2_get_drv_priv(q);
struct bttv_crop c; unsigned int size = btv->fmt->depth * btv->width * btv->height >> 3;
int norm;
int rc;
/* check settings */ if (*num_planes)
if (NULL == fmt) return sizes[0] < size ? -EINVAL : 0;
return -EINVAL; *num_planes = 1;
if (fmt->btformat == BT848_COLOR_FMT_RAW) { sizes[0] = size;
width = RAW_BPL;
height = RAW_LINES*2;
if (width*height > buf->vb.bsize)
return -EINVAL;
buf->vb.size = buf->vb.bsize;
/* Make sure tvnorm and vbi_end remain consistent
until we're done. */
norm = btv->tvnorm;
/* In this mode capturing always starts at defrect.top
(default VDELAY), ignoring cropping parameters. */
if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
return -EINVAL;
}
c.rect = bttv_tvnorms[norm].cropcap.defrect; return 0;
} else { }
norm = btv->tvnorm;
c = btv->crop[!!btv->do_crop];
if (width < c.min_scaled_width ||
width > c.max_scaled_width ||
height < c.min_scaled_height)
return -EINVAL;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
/* btv->crop counts frame lines. Max. scale
factor is 16:1 for frames, 8:1 for fields. */
if (height * 2 > c.max_scaled_height)
return -EINVAL;
break;
default: static void buf_queue(struct vb2_buffer *vb)
if (height > c.max_scaled_height) {
return -EINVAL; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
break; 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 = (width * height * fmt->depth) >> 3; spin_lock_irqsave(&btv->s_lock, flags);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) if (list_empty(&btv->capture)) {
return -EINVAL; btv->loop_irq = BT848_RISC_VIDEO;
} if (vb2_is_streaming(&btv->vbiq))
btv->loop_irq |= BT848_RISC_VBI;
/* alloc + fill struct bttv_buffer (if changed) */ bttv_set_dma(btv, BT848_CAP_CTL_CAPTURE_ODD |
if (buf->vb.width != width || buf->vb.height != height || BT848_CAP_CTL_CAPTURE_EVEN);
buf->vb.field != field ||
btv->tvnorm != norm || btv->fmt != fmt ||
btv->crop[!!btv->do_crop].rect.top != c.rect.top ||
btv->crop[!!btv->do_crop].rect.left != c.rect.left ||
btv->crop[!!btv->do_crop].rect.width != c.rect.width ||
btv->crop[!!btv->do_crop].rect.height != c.rect.height) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
btv->tvnorm = norm;
btv->crop[!!btv->do_crop].rect = c.rect;
redo_dma_risc = 1;
}
/* alloc risc memory */
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
redo_dma_risc = 1;
if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
goto fail;
} }
list_add_tail(&buf->list, &btv->capture);
if (redo_dma_risc) spin_unlock_irqrestore(&btv->s_lock, flags);
if (0 != (rc = bttv_buffer_risc(btv,buf)))
goto fail;
buf->vb.state = VIDEOBUF_PREPARED;
return 0;
fail:
bttv_dma_free(q,btv,buf);
return rc;
} }
static int static int buf_prepare(struct vb2_buffer *vb)
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{ {
struct bttv_fh *fh = q->priv_data; 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 = (btv->fmt->depth * btv->width * btv->height) >> 3;
*size = fh->fmt->depth*fh->width*fh->height >> 3; if (vb2_plane_size(vb, 0) < size)
if (0 == *count) return -EINVAL;
*count = gbuffers; vb2_set_plane_payload(vb, 0, size);
if (*size * *count > gbuffers * gbufsize)
*count = (gbuffers * gbufsize) / *size; if (btv->field != V4L2_FIELD_ALTERNATE) {
return 0; buf->vbuf.field = btv->field;
} else if (btv->field_last == V4L2_FIELD_TOP) {
buf->vbuf.field = V4L2_FIELD_BOTTOM;
btv->field_last = V4L2_FIELD_BOTTOM;
} else {
buf->vbuf.field = V4L2_FIELD_TOP;
btv->field_last = V4L2_FIELD_TOP;
}
/* Allocate memory for risc struct and create the risc program. */
return bttv_buffer_risc(btv, buf);
} }
static int static void buf_cleanup(struct vb2_buffer *vb)
buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{ {
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct vb2_queue *vq = vb->vb2_queue;
struct bttv_fh *fh = q->priv_data; 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);
return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt, btcx_riscmem_free(btv->c.pci, &buf->top);
fh->width, fh->height, field); btcx_riscmem_free(btv->c.pci, &buf->bottom);
} }
static void static int start_streaming(struct vb2_queue *q, unsigned int count)
buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{ {
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); int ret = 1;
struct bttv_fh *fh = q->priv_data; int seqnr = 0;
struct bttv *btv = fh->btv; struct bttv_buffer *buf;
struct bttv *btv = vb2_get_drv_priv(q);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue,&btv->capture); ret = check_alloc_btres_lock(btv, RESOURCE_VIDEO_STREAM);
if (!btv->curr.frame_irq) { if (ret == 0) {
btv->loop_irq |= 1; if (btv->field_count)
bttv_set_dma(btv, 0x03); seqnr++;
while (!list_empty(&btv->capture)) {
buf = list_entry(btv->capture.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->vbiq)) {
init_irqreg(btv);
btv->field_count = 0;
}
btv->framedrop = 0;
return 0;
} }
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) static void stop_streaming(struct vb2_queue *q)
{ {
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); unsigned long flags;
struct bttv_fh *fh = q->priv_data; struct bttv *btv = vb2_get_drv_priv(q);
bttv_dma_free(q,fh->btv,buf); vb2_wait_for_all_buffers(q);
spin_lock_irqsave(&btv->s_lock, flags);
free_btres_lock(btv, RESOURCE_VIDEO_STREAM);
if (!vb2_is_streaming(&btv->vbiq)) {
/* stop field counter */
btand(~BT848_INT_VSYNC, BT848_INT_MASK);
}
spin_unlock_irqrestore(&btv->s_lock, flags);
} }
static const struct videobuf_queue_ops bttv_video_qops = { static const struct vb2_ops bttv_video_qops = {
.buf_setup = buffer_setup, .queue_setup = queue_setup,
.buf_prepare = buffer_prepare, .buf_queue = buf_queue,
.buf_queue = buffer_queue, .buf_prepare = buf_prepare,
.buf_release = buffer_release, .buf_cleanup = buf_cleanup,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
}; };
static void radio_enable(struct bttv *btv) static void radio_enable(struct bttv *btv)
...@@ -1890,16 +1841,11 @@ bttv_crop_adjust (struct bttv_crop * c, ...@@ -1890,16 +1841,11 @@ bttv_crop_adjust (struct bttv_crop * c,
also adjust the current cropping parameters to get closer to the also adjust the current cropping parameters to get closer to the
desired image size. */ desired image size. */
static int static int
limit_scaled_size_lock (struct bttv_fh * fh, limit_scaled_size_lock(struct bttv *btv, __s32 *width, __s32 *height,
__s32 * width, enum v4l2_field field, unsigned int width_mask,
__s32 * height, unsigned int width_bias, int adjust_size,
enum v4l2_field field, int adjust_crop)
unsigned int width_mask, {
unsigned int width_bias,
int adjust_size,
int adjust_crop)
{
struct bttv *btv = fh->btv;
const struct v4l2_rect *b; const struct v4l2_rect *b;
struct bttv_crop *c; struct bttv_crop *c;
__s32 min_width; __s32 min_width;
...@@ -1993,52 +1939,31 @@ limit_scaled_size_lock (struct bttv_fh * fh, ...@@ -1993,52 +1939,31 @@ limit_scaled_size_lock (struct bttv_fh * fh,
return rc; return rc;
} }
/* ----------------------------------------------------------------------- */ static int bttv_switch_type(struct bttv *btv, enum v4l2_buf_type type)
static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
{ {
struct videobuf_queue* q = NULL; int res;
struct vb2_queue *q;
switch (fh->type) { switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
q = &fh->cap;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
q = &fh->vbi;
break;
default:
BUG();
}
return q;
}
static int bttv_resource(struct bttv_fh *fh)
{
int res = 0;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE:
q = &btv->capq;
res = RESOURCE_VIDEO_STREAM; res = RESOURCE_VIDEO_STREAM;
break; break;
case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_CAPTURE:
q = &btv->vbiq;
res = RESOURCE_VBI; res = RESOURCE_VBI;
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
return -EINVAL;
} }
return res;
}
static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) if (check_btres(btv, res))
{
struct videobuf_queue *q = bttv_queue(fh);
int res = bttv_resource(fh);
if (check_btres(fh,res))
return -EBUSY; return -EBUSY;
if (videobuf_queue_is_busy(q)) if (vb2_is_busy(q))
return -EBUSY; return -EBUSY;
fh->type = type; btv->type = type;
return 0; return 0;
} }
...@@ -2063,11 +1988,10 @@ pix_format_set_size (struct v4l2_pix_format * f, ...@@ -2063,11 +1988,10 @@ pix_format_set_size (struct v4l2_pix_format * f,
static int bttv_g_fmt_vid_cap(struct file *file, void *priv, static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct bttv_fh *fh = priv;
struct bttv *btv = video_drvdata(file); struct bttv *btv = video_drvdata(file);
pix_format_set_size(&f->fmt.pix, btv->fmt, btv->width, btv->height); pix_format_set_size(&f->fmt.pix, btv->fmt, btv->width, btv->height);
f->fmt.pix.field = fh->cap.field; f->fmt.pix.field = btv->field;
f->fmt.pix.pixelformat = btv->fmt->fourcc; f->fmt.pix.pixelformat = btv->fmt->fourcc;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
...@@ -2091,7 +2015,6 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, ...@@ -2091,7 +2015,6 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
const struct bttv_format *fmt; const struct bttv_format *fmt;
struct bttv_fh *fh = priv;
struct bttv *btv = video_drvdata(file); struct bttv *btv = video_drvdata(file);
enum v4l2_field field; enum v4l2_field field;
__s32 width, height; __s32 width, height;
...@@ -2130,10 +2053,8 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, ...@@ -2130,10 +2053,8 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
height = f->fmt.pix.height; height = f->fmt.pix.height;
bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias); bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
rc = limit_scaled_size_lock(fh, &width, &height, field, rc = limit_scaled_size_lock(btv, &width, &height, field, width_mask,
width_mask, width_bias, width_bias, 1, 0);
/* adjust_size */ 1,
/* adjust_crop */ 0);
if (0 != rc) if (0 != rc)
return rc; return rc;
...@@ -2146,17 +2067,16 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, ...@@ -2146,17 +2067,16 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
} }
static int bttv_s_fmt_vid_cap(struct file *file, void *priv, static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
int retval; int retval;
const struct bttv_format *fmt; const struct bttv_format *fmt;
struct bttv_fh *fh = priv;
struct bttv *btv = video_drvdata(file); struct bttv *btv = video_drvdata(file);
__s32 width, height; __s32 width, height;
unsigned int width_mask, width_bias; unsigned int width_mask, width_bias;
enum v4l2_field field; enum v4l2_field field;
retval = bttv_switch_type(fh, f->type); retval = bttv_switch_type(btv, f->type);
if (0 != retval) if (0 != retval)
return retval; return retval;
...@@ -2170,27 +2090,25 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, ...@@ -2170,27 +2090,25 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat); fmt = format_by_fourcc(f->fmt.pix.pixelformat);
bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias); bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field, retval = limit_scaled_size_lock(btv, &width, &height, f->fmt.pix.field,
width_mask, width_bias, width_mask, width_bias, 1, 1);
/* adjust_size */ 1,
/* adjust_crop */ 1);
if (0 != retval) if (0 != retval)
return retval; return retval;
f->fmt.pix.field = field; f->fmt.pix.field = field;
/* update our state information */ /* update our state information */
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
btv->fmt = fmt; btv->fmt = fmt;
btv->width = f->fmt.pix.width; btv->width = f->fmt.pix.width;
btv->height = f->fmt.pix.height; btv->height = f->fmt.pix.height;
btv->field = f->fmt.pix.field;
/*
* When field is V4L2_FIELD_ALTERNATE, buffers will be either
* V4L2_FIELD_TOP or V4L2_FIELD_BOTTOM depending on the value of
* field_last. Initialize field_last to V4L2_FIELD_BOTTOM so that
* streaming starts with a V4L2_FIELD_TOP buffer.
*/
btv->field_last = V4L2_FIELD_BOTTOM;
return 0; return 0;
} }
...@@ -2245,68 +2163,6 @@ static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, ...@@ -2245,68 +2163,6 @@ static int bttv_enum_fmt_vid_cap(struct file *file, void *priv,
return 0; return 0;
} }
static int bttv_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct bttv_fh *fh = priv;
return videobuf_reqbufs(bttv_queue(fh), p);
}
static int bttv_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
struct bttv_fh *fh = priv;
return videobuf_querybuf(bttv_queue(fh), b);
}
static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct bttv_fh *fh = priv;
struct bttv *btv = video_drvdata(file);
int res = bttv_resource(fh);
if (!check_alloc_btres_lock(btv, fh, res))
return -EBUSY;
return videobuf_qbuf(bttv_queue(fh), b);
}
static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct bttv_fh *fh = priv;
return videobuf_dqbuf(bttv_queue(fh), b,
file->f_flags & O_NONBLOCK);
}
static int bttv_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
int res = bttv_resource(fh);
if (!check_alloc_btres_lock(btv, fh, res))
return -EBUSY;
return videobuf_streamon(bttv_queue(fh));
}
static int bttv_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
int retval;
int res = bttv_resource(fh);
retval = videobuf_streamoff(bttv_queue(fh));
if (retval < 0)
return retval;
free_btres_lock(btv, fh, res);
return 0;
}
static int bttv_g_parm(struct file *file, void *f, static int bttv_g_parm(struct file *file, void *f,
struct v4l2_streamparm *parm) struct v4l2_streamparm *parm)
{ {
...@@ -2382,7 +2238,6 @@ static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *s ...@@ -2382,7 +2238,6 @@ static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *s
static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *sel) static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *sel)
{ {
struct bttv_fh *fh = f;
struct bttv *btv = video_drvdata(file); struct bttv *btv = video_drvdata(file);
const struct v4l2_rect *b; const struct v4l2_rect *b;
int retval; int retval;
...@@ -2403,9 +2258,8 @@ static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *s ...@@ -2403,9 +2258,8 @@ static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *s
read() may change vbi_end in check_alloc_btres_lock(). */ read() may change vbi_end in check_alloc_btres_lock(). */
retval = -EBUSY; retval = -EBUSY;
if (locked_btres(fh->btv, VIDEO_RESOURCES)) { if (locked_btres(btv, VIDEO_RESOURCES))
return retval; return retval;
}
b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
...@@ -2454,228 +2308,15 @@ static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *s ...@@ -2454,228 +2308,15 @@ static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *s
return 0; return 0;
} }
static ssize_t bttv_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
struct bttv_fh *fh = file->private_data;
int retval = 0;
if (fh->btv->errors)
bttv_reinit_bt848(fh->btv);
dprintk("%d: read count=%d type=%s\n",
fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]);
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {
/* VIDEO_READ in use by another fh,
or VIDEO_STREAM by any fh. */
return -EBUSY;
}
retval = videobuf_read_one(&fh->cap, data, count, ppos,
file->f_flags & O_NONBLOCK);
free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
return -EBUSY;
retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
file->f_flags & O_NONBLOCK);
break;
default:
BUG();
}
return retval;
}
static __poll_t bttv_poll(struct file *file, poll_table *wait)
{
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
enum v4l2_field field;
__poll_t rc = 0;
__poll_t req_events = poll_requested_events(wait);
if (v4l2_event_pending(&fh->fh))
rc = EPOLLPRI;
else if (req_events & EPOLLPRI)
poll_wait(file, &fh->fh.wait, wait);
if (!(req_events & (EPOLLIN | EPOLLRDNORM)))
return rc;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
return rc | EPOLLERR;
return rc | videobuf_poll_stream(file, &fh->vbi, wait);
}
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
return rc | EPOLLERR;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
return rc | EPOLLERR;
fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf)
return rc | EPOLLERR;
fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
field = videobuf_next_field(&fh->cap);
if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
kfree (fh->cap.read_buf);
fh->cap.read_buf = NULL;
return rc | EPOLLERR;
}
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
rc = rc | EPOLLIN|EPOLLRDNORM;
return rc;
}
static int bttv_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct bttv *btv = video_drvdata(file);
struct bttv_fh *fh;
enum v4l2_buf_type type = 0;
dprintk("open dev=%s\n", video_device_node_name(vdev));
if (vdev->vfl_type == VFL_TYPE_VIDEO) {
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
} else if (vdev->vfl_type == VFL_TYPE_VBI) {
type = V4L2_BUF_TYPE_VBI_CAPTURE;
} else {
WARN_ON(1);
return -ENODEV;
}
dprintk("%d: open called (type=%s)\n",
btv->c.nr, v4l2_type_names[type]);
/* allocate per filehandle data */
fh = kmalloc(sizeof(*fh), GFP_KERNEL);
if (unlikely(!fh))
return -ENOMEM;
btv->users++;
file->private_data = fh;
*fh = btv->init;
v4l2_fh_init(&fh->fh, vdev);
fh->type = type;
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
fh, &btv->lock);
videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct bttv_buffer),
fh, &btv->lock);
set_tvnorm(btv,btv->tvnorm);
set_input(btv, btv->input, btv->tvnorm);
audio_mute(btv, btv->mute);
/* The V4L2 spec requires one global set of cropping parameters
which only change on request. These are stored in btv->crop[1].
However for compatibility with V4L apps and cropping unaware
V4L2 apps we now reset the cropping parameters as seen through
this fh, which is to say VIDIOC_G_SELECTION and scaling limit checks
will use btv->crop[0], the default cropping parameters for the
current video standard, and VIDIOC_S_FMT will not implicitly
change the cropping parameters until VIDIOC_S_SELECTION has been
called. */
btv->do_crop = !reset_crop; /* module parameter */
/* Likewise there should be one global set of VBI capture
parameters, but for compatibility with V4L apps and earlier
driver versions each fh has its own parameters. */
bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
bttv_field_count(btv);
v4l2_fh_add(&fh->fh);
return 0;
}
static int bttv_release(struct file *file)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
/* stop video capture */
if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);
}
if (fh->cap.read_buf) {
buffer_release(&fh->cap,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
if (check_btres(fh, RESOURCE_VIDEO_READ)) {
free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);
}
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
videobuf_stop(&fh->vbi);
free_btres_lock(btv,fh,RESOURCE_VBI);
}
/* free stuff */
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
file->private_data = NULL;
btv->users--;
bttv_field_count(btv);
if (!btv->users)
audio_mute(btv, btv->mute);
v4l2_fh_del(&fh->fh);
v4l2_fh_exit(&fh->fh);
kfree(fh);
return 0;
}
static int
bttv_mmap(struct file *file, struct vm_area_struct *vma)
{
struct bttv_fh *fh = file->private_data;
dprintk("%d: mmap type=%s 0x%lx+%ld\n",
fh->btv->c.nr, v4l2_type_names[fh->type],
vma->vm_start, vma->vm_end - vma->vm_start);
return videobuf_mmap_mapper(bttv_queue(fh),vma);
}
static const struct v4l2_file_operations bttv_fops = static const struct v4l2_file_operations bttv_fops =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = bttv_open, .open = v4l2_fh_open,
.release = bttv_release, .release = vb2_fop_release,
.unlocked_ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.read = bttv_read, .read = vb2_fop_read,
.mmap = bttv_mmap, .mmap = vb2_fop_mmap,
.poll = bttv_poll, .poll = vb2_fop_poll,
}; };
static const struct v4l2_ioctl_ops bttv_ioctl_ops = { static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
...@@ -2688,17 +2329,18 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { ...@@ -2688,17 +2329,18 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,
.vidioc_g_pixelaspect = bttv_g_pixelaspect, .vidioc_g_pixelaspect = bttv_g_pixelaspect,
.vidioc_reqbufs = bttv_reqbufs, .vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = bttv_querybuf, .vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_qbuf = bttv_qbuf, .vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_dqbuf = bttv_dqbuf, .vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_s_std = bttv_s_std, .vidioc_s_std = bttv_s_std,
.vidioc_g_std = bttv_g_std, .vidioc_g_std = bttv_g_std,
.vidioc_enum_input = bttv_enum_input, .vidioc_enum_input = bttv_enum_input,
.vidioc_g_input = bttv_g_input, .vidioc_g_input = bttv_g_input,
.vidioc_s_input = bttv_s_input, .vidioc_s_input = bttv_s_input,
.vidioc_streamon = bttv_streamon,
.vidioc_streamoff = bttv_streamoff,
.vidioc_g_tuner = bttv_g_tuner, .vidioc_g_tuner = bttv_g_tuner,
.vidioc_s_tuner = bttv_s_tuner, .vidioc_s_tuner = bttv_s_tuner,
.vidioc_g_selection = bttv_g_selection, .vidioc_g_selection = bttv_g_selection,
...@@ -3021,17 +2663,19 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) ...@@ -3021,17 +2663,19 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
/* capture request ? */ /* capture request ? */
if (!list_empty(&btv->capture)) { if (!list_empty(&btv->capture)) {
set->frame_irq = 1; set->frame_irq = BT848_RISC_VIDEO;
item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); item = list_entry(btv->capture.next, struct bttv_buffer, list);
if (V4L2_FIELD_HAS_TOP(item->vb.field))
if (V4L2_FIELD_HAS_TOP(item->vbuf.field))
set->top = item; set->top = item;
if (V4L2_FIELD_HAS_BOTTOM(item->vb.field)) if (V4L2_FIELD_HAS_BOTTOM(item->vbuf.field))
set->bottom = item; set->bottom = item;
/* capture request for other field ? */ /* capture request for other field ? */
if (!V4L2_FIELD_HAS_BOTH(item->vb.field) && if (!V4L2_FIELD_HAS_BOTH(item->vbuf.field) &&
(item->vb.queue.next != &btv->capture)) { item->list.next != &btv->capture) {
item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue); item = list_entry(item->list.next,
struct bttv_buffer, list);
/* Mike Isely <isely@pobox.com> - Only check /* Mike Isely <isely@pobox.com> - Only check
* and set up the bottom field in the logic * and set up the bottom field in the logic
* below. Don't ever do the top field. This * below. Don't ever do the top field. This
...@@ -3059,13 +2703,18 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) ...@@ -3059,13 +2703,18 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
* sync within a single frame time. (Out of * sync within a single frame time. (Out of
* order fields can screw up deinterlacing * order fields can screw up deinterlacing
* algorithms.) */ * algorithms.) */
if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) { if (!V4L2_FIELD_HAS_BOTH(item->vbuf.field)) {
if (NULL == set->bottom && if (!set->bottom &&
V4L2_FIELD_BOTTOM == item->vb.field) { item->vbuf.field == V4L2_FIELD_BOTTOM)
set->bottom = item; set->bottom = item;
if (set->top && set->bottom) {
/*
* The buffer set has a top buffer and
* a bottom buffer and they are not
* copies of each other.
*/
set->top_irq = BT848_RISC_TOP;
} }
if (NULL != set->top && NULL != set->bottom)
set->top_irq = 2;
} }
} }
} }
...@@ -3087,44 +2736,47 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, ...@@ -3087,44 +2736,47 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
if (irq_debug > 1) if (irq_debug > 1)
pr_debug("%d: wakeup: both=%p\n", pr_debug("%d: wakeup: both=%p\n",
btv->c.nr, wakeup->top); btv->c.nr, wakeup->top);
wakeup->top->vb.ts = ts; wakeup->top->vbuf.vb2_buf.timestamp = ts;
wakeup->top->vb.field_count = btv->field_count; wakeup->top->vbuf.sequence = btv->field_count >> 1;
wakeup->top->vb.state = state; vb2_buffer_done(&wakeup->top->vbuf.vb2_buf, state);
wake_up(&wakeup->top->vb.done); if (btv->field_count == 0)
btor(BT848_INT_VSYNC, BT848_INT_MASK);
} }
} else { } else {
if (NULL != wakeup->top && curr->top != wakeup->top) { if (NULL != wakeup->top && curr->top != wakeup->top) {
if (irq_debug > 1) if (irq_debug > 1)
pr_debug("%d: wakeup: top=%p\n", pr_debug("%d: wakeup: top=%p\n",
btv->c.nr, wakeup->top); btv->c.nr, wakeup->top);
wakeup->top->vb.ts = ts; wakeup->top->vbuf.vb2_buf.timestamp = ts;
wakeup->top->vb.field_count = btv->field_count; wakeup->top->vbuf.sequence = btv->field_count >> 1;
wakeup->top->vb.state = state; vb2_buffer_done(&wakeup->top->vbuf.vb2_buf, state);
wake_up(&wakeup->top->vb.done); if (btv->field_count == 0)
btor(BT848_INT_VSYNC, BT848_INT_MASK);
} }
if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
if (irq_debug > 1) if (irq_debug > 1)
pr_debug("%d: wakeup: bottom=%p\n", pr_debug("%d: wakeup: bottom=%p\n",
btv->c.nr, wakeup->bottom); btv->c.nr, wakeup->bottom);
wakeup->bottom->vb.ts = ts; wakeup->bottom->vbuf.vb2_buf.timestamp = ts;
wakeup->bottom->vb.field_count = btv->field_count; wakeup->bottom->vbuf.sequence = btv->field_count >> 1;
wakeup->bottom->vb.state = state; vb2_buffer_done(&wakeup->bottom->vbuf.vb2_buf, state);
wake_up(&wakeup->bottom->vb.done); if (btv->field_count == 0)
btor(BT848_INT_VSYNC, BT848_INT_MASK);
} }
} }
} }
static void static void
bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
unsigned int state) unsigned int state)
{ {
if (NULL == wakeup) if (NULL == wakeup)
return; return;
wakeup->vbuf.vb2_buf.timestamp = ktime_get_ns();
wakeup->vb.ts = ktime_get_ns(); wakeup->vbuf.sequence = btv->field_count >> 1;
wakeup->vb.field_count = btv->field_count; vb2_buffer_done(&wakeup->vbuf.vb2_buf, state);
wakeup->vb.state = state; if (btv->field_count == 0)
wake_up(&wakeup->vb.done); btor(BT848_INT_VSYNC, BT848_INT_MASK);
} }
static void bttv_irq_timeout(struct timer_list *t) static void bttv_irq_timeout(struct timer_list *t)
...@@ -3134,6 +2786,7 @@ static void bttv_irq_timeout(struct timer_list *t) ...@@ -3134,6 +2786,7 @@ static void bttv_irq_timeout(struct timer_list *t)
struct bttv_buffer *ovbi; struct bttv_buffer *ovbi;
struct bttv_buffer *item; struct bttv_buffer *item;
unsigned long flags; unsigned long flags;
int seqnr = 0;
if (bttv_verbose) { if (bttv_verbose) {
pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
...@@ -3157,21 +2810,25 @@ static void bttv_irq_timeout(struct timer_list *t) ...@@ -3157,21 +2810,25 @@ static void bttv_irq_timeout(struct timer_list *t)
bttv_set_dma(btv, 0); bttv_set_dma(btv, 0);
/* wake up */ /* wake up */
bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); bttv_irq_wakeup_video(btv, &old, &new, VB2_BUF_STATE_DONE);
bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); bttv_irq_wakeup_vbi(btv, ovbi, VB2_BUF_STATE_DONE);
/* cancel all outstanding capture / vbi requests */ /* cancel all outstanding capture / vbi requests */
if (btv->field_count)
seqnr++;
while (!list_empty(&btv->capture)) { while (!list_empty(&btv->capture)) {
item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); item = list_entry(btv->capture.next, struct bttv_buffer, list);
list_del(&item->vb.queue); list_del(&item->list);
item->vb.state = VIDEOBUF_ERROR; item->vbuf.vb2_buf.timestamp = ktime_get_ns();
wake_up(&item->vb.done); item->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
vb2_buffer_done(&item->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
} }
while (!list_empty(&btv->vcapture)) { while (!list_empty(&btv->vcapture)) {
item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); item = list_entry(btv->vcapture.next, struct bttv_buffer, list);
list_del(&item->vb.queue); list_del(&item->list);
item->vb.state = VIDEOBUF_ERROR; item->vbuf.vb2_buf.timestamp = ktime_get_ns();
wake_up(&item->vb.done); item->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
vb2_buffer_done(&item->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
} }
btv->errors++; btv->errors++;
...@@ -3190,11 +2847,11 @@ bttv_irq_wakeup_top(struct bttv *btv) ...@@ -3190,11 +2847,11 @@ bttv_irq_wakeup_top(struct bttv *btv)
btv->curr.top_irq = 0; btv->curr.top_irq = 0;
btv->curr.top = NULL; btv->curr.top = NULL;
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
wakeup->vbuf.vb2_buf.timestamp = ktime_get_ns();
wakeup->vb.ts = ktime_get_ns(); wakeup->vbuf.sequence = btv->field_count >> 1;
wakeup->vb.field_count = btv->field_count; vb2_buffer_done(&wakeup->vbuf.vb2_buf, VB2_BUF_STATE_DONE);
wakeup->vb.state = VIDEOBUF_DONE; if (btv->field_count == 0)
wake_up(&wakeup->vb.done); btor(BT848_INT_VSYNC, BT848_INT_MASK);
spin_unlock(&btv->s_lock); spin_unlock(&btv->s_lock);
} }
...@@ -3231,7 +2888,7 @@ bttv_irq_switch_video(struct bttv *btv) ...@@ -3231,7 +2888,7 @@ bttv_irq_switch_video(struct bttv *btv)
/* switch over */ /* switch over */
old = btv->curr; old = btv->curr;
btv->curr = new; btv->curr = new;
btv->loop_irq &= ~1; btv->loop_irq &= ~BT848_RISC_VIDEO;
bttv_buffer_activate_video(btv, &new); bttv_buffer_activate_video(btv, &new);
bttv_set_dma(btv, 0); bttv_set_dma(btv, 0);
...@@ -3242,7 +2899,7 @@ bttv_irq_switch_video(struct bttv *btv) ...@@ -3242,7 +2899,7 @@ bttv_irq_switch_video(struct bttv *btv)
} }
/* wake up finished buffers */ /* wake up finished buffers */
bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); bttv_irq_wakeup_video(btv, &old, &new, VB2_BUF_STATE_DONE);
spin_unlock(&btv->s_lock); spin_unlock(&btv->s_lock);
} }
...@@ -3256,7 +2913,7 @@ bttv_irq_switch_vbi(struct bttv *btv) ...@@ -3256,7 +2913,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
spin_lock(&btv->s_lock); spin_lock(&btv->s_lock);
if (!list_empty(&btv->vcapture)) if (!list_empty(&btv->vcapture))
new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); new = list_entry(btv->vcapture.next, struct bttv_buffer, list);
old = btv->cvbi; old = btv->cvbi;
rc = btread(BT848_RISC_COUNT); rc = btread(BT848_RISC_COUNT);
...@@ -3271,11 +2928,11 @@ bttv_irq_switch_vbi(struct bttv *btv) ...@@ -3271,11 +2928,11 @@ bttv_irq_switch_vbi(struct bttv *btv)
/* switch */ /* switch */
btv->cvbi = new; btv->cvbi = new;
btv->loop_irq &= ~4; btv->loop_irq &= ~BT848_RISC_VBI;
bttv_buffer_activate_vbi(btv, new); bttv_buffer_activate_vbi(btv, new);
bttv_set_dma(btv, 0); bttv_set_dma(btv, 0);
bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); bttv_irq_wakeup_vbi(btv, old, VB2_BUF_STATE_DONE);
spin_unlock(&btv->s_lock); spin_unlock(&btv->s_lock);
} }
...@@ -3334,13 +2991,13 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) ...@@ -3334,13 +2991,13 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
wake_up(&btv->i2c_queue); wake_up(&btv->i2c_queue);
} }
if ((astat & BT848_INT_RISCI) && (stat & (4<<28))) if ((astat & BT848_INT_RISCI) && (stat & BT848_INT_RISCS_VBI))
bttv_irq_switch_vbi(btv); bttv_irq_switch_vbi(btv);
if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) if ((astat & BT848_INT_RISCI) && (stat & BT848_INT_RISCS_TOP))
bttv_irq_wakeup_top(btv); bttv_irq_wakeup_top(btv);
if ((astat & BT848_INT_RISCI) && (stat & (1<<28))) if ((astat & BT848_INT_RISCI) && (stat & BT848_INT_RISCS_VIDEO))
bttv_irq_switch_video(btv); bttv_irq_switch_video(btv);
if ((astat & BT848_INT_HLOCK) && btv->opt_automute) if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
...@@ -3396,11 +3053,12 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) ...@@ -3396,11 +3053,12 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* initialization */ /* initialization */
static void vdev_init(struct bttv *btv, static int vdev_init(struct bttv *btv, struct video_device *vfd,
struct video_device *vfd, const struct video_device *template,
const struct video_device *template, const char *type_name)
const char *type_name)
{ {
int err;
struct vb2_queue *q;
*vfd = *template; *vfd = *template;
vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release_empty; vfd->release = video_device_release_empty;
...@@ -3414,6 +3072,36 @@ static void vdev_init(struct bttv *btv, ...@@ -3414,6 +3072,36 @@ static void vdev_init(struct bttv *btv,
v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
} }
if (strcmp(type_name, "radio") == 0)
return 0;
if (strcmp(type_name, "video") == 0) {
q = &btv->capq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->ops = &bttv_video_qops;
} else if (strcmp(type_name, "vbi") == 0) {
q = &btv->vbiq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->ops = &bttv_vbi_qops;
} else {
return -EINVAL;
}
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
q->mem_ops = &vb2_dma_sg_memops;
q->drv_priv = btv;
q->gfp_flags = __GFP_DMA32;
q->buf_struct_size = sizeof(struct bttv_buffer);
q->lock = &btv->lock;
q->min_buffers_needed = 2;
q->dev = &btv->c.pci->dev;
err = vb2_queue_init(q);
if (err)
return err;
vfd->queue = q;
return 0;
} }
static void bttv_unregister_video(struct bttv *btv) static void bttv_unregister_video(struct bttv *btv)
...@@ -3621,13 +3309,10 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) ...@@ -3621,13 +3309,10 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
bttv_ctrl_coring.def = coring; bttv_ctrl_coring.def = coring;
/* fill struct bttv with some useful defaults */ /* fill struct bttv with some useful defaults */
btv->init.btv = btv;
btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
btv->init.width = 320;
btv->init.height = 240;
btv->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); btv->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
btv->width = 320; btv->width = 320;
btv->height = 240; btv->height = 240;
btv->field = V4L2_FIELD_INTERLACED;
btv->input = 0; btv->input = 0;
btv->tvnorm = 0; /* Index into bttv_tvnorms[] i.e. PAL. */ btv->tvnorm = 0; /* Index into bttv_tvnorms[] i.e. PAL. */
bttv_vbi_fmt_reset(&btv->vbi_fmt, btv->tvnorm); bttv_vbi_fmt_reset(&btv->vbi_fmt, btv->tvnorm);
...@@ -3708,7 +3393,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) ...@@ -3708,7 +3393,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
result = btv->radio_ctrl_handler.error; result = btv->radio_ctrl_handler.error;
goto fail2; goto fail2;
} }
set_input(btv, 0, btv->tvnorm); set_input(btv, btv->input, btv->tvnorm);
bttv_crop_reset(&btv->crop[0], btv->tvnorm); bttv_crop_reset(&btv->crop[0], btv->tvnorm);
btv->crop[1] = btv->crop[0]; /* current = default */ btv->crop[1] = btv->crop[0]; /* current = default */
disclaim_vbi_lines(btv); disclaim_vbi_lines(btv);
......
...@@ -67,8 +67,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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;
videobuf_waiton(q, &buf->vb, 0, 0); unsigned int bpl = 2044; /* max. vbipack */
videobuf_dma_unmap(q->dev, dma); unsigned int padding = VBI_BPL - bpl;
videobuf_dma_free(dma); unsigned int skip_lines0 = 0;
btcx_riscmem_free(btv->c.pci,&buf->bottom); unsigned int skip_lines1 = 0;
btcx_riscmem_free(btv->c.pci,&buf->top); unsigned int min_vdelay = MIN_VDELAY;
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 int
...@@ -539,8 +569,7 @@ bttv_buffer_activate_vbi(struct bttv *btv, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,
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: 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) ...@@ -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;
} }
...@@ -34,16 +34,6 @@ ...@@ -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 { \ ...@@ -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)
*count = vbibufs;
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
dprintk("setup: samples=%u start=%d,%d count=%u,%u\n", if (*num_planes)
fh->vbi_fmt.fmt.samples_per_line, return sizes[0] < size ? -EINVAL : 0;
fh->vbi_fmt.fmt.start[0], *num_planes = 1;
fh->vbi_fmt.fmt.start[1], sizes[0] = size;
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; spin_lock_irqsave(&btv->s_lock, flags);
if (list_empty(&btv->vcapture)) {
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt); btv->loop_irq = BT848_RISC_VBI;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) if (vb2_is_streaming(&btv->capq))
return -EINVAL; btv->loop_irq |= BT848_RISC_VIDEO;
bttv_set_dma(btv, BT848_CAP_CTL_CAPTURE_VBI_ODD |
tvnorm = fh->vbi_fmt.tvnorm; BT848_CAP_CTL_CAPTURE_VBI_EVEN);
/* 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;
} }
list_add_tail(&buf->list, &btv->vcapture);
spin_unlock_irqrestore(&btv->s_lock, flags);
}
if (redo_dma_risc) { static int buf_prepare_vbi(struct vb2_buffer *vb)
unsigned int bpl, padding, offset; {
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int ret = 0;
struct vb2_queue *vq = vb->vb2_queue;
bpl = 2044; /* max. vbipack */ struct bttv *btv = vb2_get_drv_priv(vq);
padding = VBI_BPL - bpl; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
if (fh->vbi_fmt.fmt.count[0] > 0) { unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
rc = bttv_risc_packed(btv, &buf->top,
dma->sglist, if (vb2_plane_size(vb, 0) < size)
/* offset */ 0, bpl, return -EINVAL;
padding, skip_lines0, vb2_set_plane_payload(vb, 0, size);
fh->vbi_fmt.fmt.count[0]); buf->vbuf.field = V4L2_FIELD_NONE;
if (0 != rc) ret = bttv_buffer_risc_vbi(btv, buf);
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, return ret;
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, static void buf_cleanup_vbi(struct vb2_buffer *vb)
no matter where the RISC program ends. VDELAY minimum is 2, {
bounds.top is the corresponding first field line number struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
times two. VDELAY counts half field lines. */ struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
min_vdelay = MIN_VDELAY; struct vb2_queue *vq = vb->vb2_queue;
if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top) struct bttv *btv = vb2_get_drv_priv(vq);
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: btcx_riscmem_free(btv->c.pci, &buf->top);
bttv_dma_free(q,btv,buf); btcx_riscmem_free(btv->c.pci, &buf->bottom);
return rc;
} }
static void static int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{ {
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("queue %p\n",vb);
buf->vb.state = VIDEOBUF_QUEUED; btv->framedrop = 0;
list_add_tail(&buf->vb.queue,&btv->vcapture); ret = check_alloc_btres_lock(btv, RESOURCE_VBI);
if (NULL == btv->cvbi) { if (ret == 0) {
fh->btv->loop_irq |= 4; if (btv->field_count)
bttv_set_dma(btv,0x0c); 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 = vb2_get_drv_priv(q);
struct bttv *btv = fh->btv; unsigned long flags;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
vb2_wait_for_all_buffers(q);
dprintk("free %p\n",vb); spin_lock_irqsave(&btv->s_lock, flags);
bttv_dma_free(q,fh->btv,buf); 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 = { const struct vb2_ops bttv_vbi_qops = {
.buf_setup = vbi_buffer_setup, .queue_setup = queue_setup_vbi,
.buf_prepare = vbi_buffer_prepare, .buf_queue = buf_queue_vbi,
.buf_queue = vbi_buffer_queue, .buf_prepare = buf_prepare_vbi,
.buf_release = vbi_buffer_release, .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) ...@@ -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) ...@@ -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) ...@@ -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:
......
...@@ -26,7 +26,7 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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); ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment