|
@@ -381,42 +381,6 @@ static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
-/* ----------------------------------------------------------------------- */
|
|
|
|
-/* resource management */
|
|
|
|
-
|
|
|
|
-static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit)
|
|
|
|
-{
|
|
|
|
- if (fh->resources & bit)
|
|
|
|
- /* have it already allocated */
|
|
|
|
- return 1;
|
|
|
|
-
|
|
|
|
- /* is it free? */
|
|
|
|
- mutex_lock(&dev->lock);
|
|
|
|
- if (dev->resources & bit) {
|
|
|
|
- /* no, someone else uses it */
|
|
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- /* it's free, grab it */
|
|
|
|
- fh->resources |= bit;
|
|
|
|
- dev->resources |= bit;
|
|
|
|
- dprintk("res: get %d\n",bit);
|
|
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
- return 1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static
|
|
|
|
-void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
|
|
|
|
-{
|
|
|
|
- BUG_ON((fh->resources & bits) != bits);
|
|
|
|
-
|
|
|
|
- mutex_lock(&dev->lock);
|
|
|
|
- fh->resources &= ~bits;
|
|
|
|
- dev->resources &= ~bits;
|
|
|
|
- dprintk("res: put %d\n",bits);
|
|
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
|
|
static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
|
|
static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
|
|
@@ -824,15 +788,15 @@ static int buffer_activate(struct saa7134_dev *dev,
|
|
struct saa7134_buf *buf,
|
|
struct saa7134_buf *buf,
|
|
struct saa7134_buf *next)
|
|
struct saa7134_buf *next)
|
|
{
|
|
{
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv;
|
|
unsigned long base,control,bpl;
|
|
unsigned long base,control,bpl;
|
|
unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
|
|
unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
|
|
|
|
|
|
dprintk("buffer_activate buf=%p\n",buf);
|
|
dprintk("buffer_activate buf=%p\n",buf);
|
|
- buf->vb.state = VIDEOBUF_ACTIVE;
|
|
|
|
buf->top_seen = 0;
|
|
buf->top_seen = 0;
|
|
|
|
|
|
- set_size(dev, TASK_A, buf->vb.width, buf->vb.height,
|
|
|
|
- V4L2_FIELD_HAS_BOTH(buf->vb.field));
|
|
|
|
|
|
+ set_size(dev, TASK_A, dev->width, dev->height,
|
|
|
|
+ V4L2_FIELD_HAS_BOTH(dev->field));
|
|
if (dev->fmt->yuv)
|
|
if (dev->fmt->yuv)
|
|
saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
|
|
saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
|
|
else
|
|
else
|
|
@@ -842,17 +806,17 @@ static int buffer_activate(struct saa7134_dev *dev,
|
|
/* DMA: setup channel 0 (= Video Task A0) */
|
|
/* DMA: setup channel 0 (= Video Task A0) */
|
|
base = saa7134_buffer_base(buf);
|
|
base = saa7134_buffer_base(buf);
|
|
if (dev->fmt->planar)
|
|
if (dev->fmt->planar)
|
|
- bpl = buf->vb.width;
|
|
|
|
|
|
+ bpl = dev->width;
|
|
else
|
|
else
|
|
- bpl = (buf->vb.width * dev->fmt->depth) / 8;
|
|
|
|
|
|
+ bpl = (dev->width * dev->fmt->depth) / 8;
|
|
control = SAA7134_RS_CONTROL_BURST_16 |
|
|
control = SAA7134_RS_CONTROL_BURST_16 |
|
|
SAA7134_RS_CONTROL_ME |
|
|
SAA7134_RS_CONTROL_ME |
|
|
- (dev->video_q.pt.dma >> 12);
|
|
|
|
|
|
+ (dmaq->pt.dma >> 12);
|
|
if (dev->fmt->bswap)
|
|
if (dev->fmt->bswap)
|
|
control |= SAA7134_RS_CONTROL_BSWAP;
|
|
control |= SAA7134_RS_CONTROL_BSWAP;
|
|
if (dev->fmt->wswap)
|
|
if (dev->fmt->wswap)
|
|
control |= SAA7134_RS_CONTROL_WSWAP;
|
|
control |= SAA7134_RS_CONTROL_WSWAP;
|
|
- if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
|
|
|
|
|
|
+ if (V4L2_FIELD_HAS_BOTH(dev->field)) {
|
|
/* interlaced */
|
|
/* interlaced */
|
|
saa_writel(SAA7134_RS_BA1(0),base);
|
|
saa_writel(SAA7134_RS_BA1(0),base);
|
|
saa_writel(SAA7134_RS_BA2(0),base+bpl);
|
|
saa_writel(SAA7134_RS_BA2(0),base+bpl);
|
|
@@ -868,14 +832,14 @@ static int buffer_activate(struct saa7134_dev *dev,
|
|
if (dev->fmt->planar) {
|
|
if (dev->fmt->planar) {
|
|
/* DMA: setup channel 4+5 (= planar task A) */
|
|
/* DMA: setup channel 4+5 (= planar task A) */
|
|
bpl_uv = bpl >> dev->fmt->hshift;
|
|
bpl_uv = bpl >> dev->fmt->hshift;
|
|
- lines_uv = buf->vb.height >> dev->fmt->vshift;
|
|
|
|
- base2 = base + bpl * buf->vb.height;
|
|
|
|
|
|
+ lines_uv = dev->height >> dev->fmt->vshift;
|
|
|
|
+ base2 = base + bpl * dev->height;
|
|
base3 = base2 + bpl_uv * lines_uv;
|
|
base3 = base2 + bpl_uv * lines_uv;
|
|
if (dev->fmt->uvswap)
|
|
if (dev->fmt->uvswap)
|
|
tmp = base2, base2 = base3, base3 = tmp;
|
|
tmp = base2, base2 = base3, base3 = tmp;
|
|
dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
|
|
dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
|
|
bpl_uv,lines_uv,base2,base3);
|
|
bpl_uv,lines_uv,base2,base3);
|
|
- if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
|
|
|
|
|
|
+ if (V4L2_FIELD_HAS_BOTH(dev->field)) {
|
|
/* interlaced */
|
|
/* interlaced */
|
|
saa_writel(SAA7134_RS_BA1(4),base2);
|
|
saa_writel(SAA7134_RS_BA1(4),base2);
|
|
saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
|
|
saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
|
|
@@ -898,23 +862,61 @@ static int buffer_activate(struct saa7134_dev *dev,
|
|
|
|
|
|
/* start DMA */
|
|
/* start DMA */
|
|
saa7134_set_dmabits(dev);
|
|
saa7134_set_dmabits(dev);
|
|
- mod_timer(&dev->video_q.timeout, jiffies + BUFFER_TIMEOUT);
|
|
|
|
|
|
+ mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int buffer_prepare(struct videobuf_queue *q,
|
|
|
|
- struct videobuf_buffer *vb,
|
|
|
|
- enum v4l2_field field)
|
|
|
|
|
|
+static int buffer_init(struct vb2_buffer *vb2)
|
|
{
|
|
{
|
|
- struct saa7134_dmaqueue *dmaq = q->priv_data;
|
|
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
|
|
|
|
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
|
|
|
|
+
|
|
|
|
+ dmaq->curr = NULL;
|
|
|
|
+ buf->activate = buffer_activate;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int buffer_prepare(struct vb2_buffer *vb2)
|
|
|
|
+{
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
|
|
struct saa7134_dev *dev = dmaq->dev;
|
|
struct saa7134_dev *dev = dmaq->dev;
|
|
- struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
|
|
|
|
|
|
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
|
|
|
|
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
|
|
unsigned int size;
|
|
unsigned int size;
|
|
- int err;
|
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
- /* sanity checks */
|
|
|
|
- if (NULL == dev->fmt)
|
|
|
|
|
|
+ size = (dev->width * dev->height * dev->fmt->depth) >> 3;
|
|
|
|
+ if (vb2_plane_size(vb2, 0) < size)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
+
|
|
|
|
+ vb2_set_plane_payload(vb2, 0, size);
|
|
|
|
+ vb2->v4l2_buf.field = dev->field;
|
|
|
|
+
|
|
|
|
+ ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
|
|
|
|
+ if (!ret)
|
|
|
|
+ return -EIO;
|
|
|
|
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
|
|
|
|
+ saa7134_buffer_startpage(buf));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void buffer_finish(struct vb2_buffer *vb2)
|
|
|
|
+{
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
|
|
|
|
+ struct saa7134_dev *dev = dmaq->dev;
|
|
|
|
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
|
|
|
|
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
|
|
|
|
+
|
|
|
|
+ dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
|
|
|
|
+ unsigned int *nbuffers, unsigned int *nplanes,
|
|
|
|
+ unsigned int sizes[], void *alloc_ctxs[])
|
|
|
|
+{
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
|
|
|
|
+ struct saa7134_dev *dev = dmaq->dev;
|
|
|
|
+ int size = dev->fmt->depth * dev->width * dev->height >> 3;
|
|
|
|
+
|
|
if (dev->width < 48 ||
|
|
if (dev->width < 48 ||
|
|
dev->height < 32 ||
|
|
dev->height < 32 ||
|
|
dev->width/4 > dev->crop_current.width ||
|
|
dev->width/4 > dev->crop_current.width ||
|
|
@@ -922,82 +924,88 @@ static int buffer_prepare(struct videobuf_queue *q,
|
|
dev->width > dev->crop_bounds.width ||
|
|
dev->width > dev->crop_bounds.width ||
|
|
dev->height > dev->crop_bounds.height)
|
|
dev->height > dev->crop_bounds.height)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- size = (dev->width * dev->height * dev->fmt->depth) >> 3;
|
|
|
|
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
|
|
- dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
|
|
|
|
- vb->i, dev->width, dev->height, size, v4l2_field_names[field],
|
|
|
|
- dev->fmt->name);
|
|
|
|
- if (buf->vb.width != dev->width ||
|
|
|
|
- buf->vb.height != dev->height ||
|
|
|
|
- buf->vb.size != size ||
|
|
|
|
- buf->vb.field != field) {
|
|
|
|
- saa7134_dma_free(q,buf);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
|
|
|
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
|
|
|
-
|
|
|
|
- buf->vb.width = dev->width;
|
|
|
|
- buf->vb.height = dev->height;
|
|
|
|
- buf->vb.size = size;
|
|
|
|
- buf->vb.field = field;
|
|
|
|
- dev->video_q.curr = NULL;
|
|
|
|
-
|
|
|
|
- err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
|
|
|
|
- if (err)
|
|
|
|
- goto oops;
|
|
|
|
- err = saa7134_pgtable_build(dev->pci, &dmaq->pt,
|
|
|
|
- dma->sglist,
|
|
|
|
- dma->sglen,
|
|
|
|
- saa7134_buffer_startpage(buf));
|
|
|
|
- if (err)
|
|
|
|
- goto oops;
|
|
|
|
- }
|
|
|
|
- buf->vb.state = VIDEOBUF_PREPARED;
|
|
|
|
- buf->activate = buffer_activate;
|
|
|
|
|
|
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
|
|
|
|
+ *nplanes = 1;
|
|
|
|
+ sizes[0] = size;
|
|
return 0;
|
|
return 0;
|
|
-
|
|
|
|
- oops:
|
|
|
|
- saa7134_dma_free(q,buf);
|
|
|
|
- return err;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
|
|
|
|
|
|
+/*
|
|
|
|
+ * move buffer to hardware queue
|
|
|
|
+ */
|
|
|
|
+void saa7134_vb2_buffer_queue(struct vb2_buffer *vb)
|
|
{
|
|
{
|
|
- struct saa7134_dmaqueue *dmaq = q->priv_data;
|
|
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = vb->vb2_queue->drv_priv;
|
|
struct saa7134_dev *dev = dmaq->dev;
|
|
struct saa7134_dev *dev = dmaq->dev;
|
|
|
|
+ struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb2);
|
|
|
|
|
|
- *size = dev->fmt->depth * dev->width * dev->height >> 3;
|
|
|
|
- if (0 == *count)
|
|
|
|
- *count = gbuffers;
|
|
|
|
- *count = saa7134_buffer_count(*size,*count);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ saa7134_buffer_queue(dev, dmaq, buf);
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(saa7134_vb2_buffer_queue);
|
|
|
|
|
|
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
|
|
|
|
|
+int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
|
|
{
|
|
{
|
|
- struct saa7134_dmaqueue *dmaq = q->priv_data;
|
|
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
|
|
struct saa7134_dev *dev = dmaq->dev;
|
|
struct saa7134_dev *dev = dmaq->dev;
|
|
- struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
|
|
|
|
|
|
|
|
- saa7134_buffer_queue(dev, &dev->video_q, buf);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Planar video capture and TS share the same DMA channel,
|
|
|
|
+ * so only one can be active at a time.
|
|
|
|
+ */
|
|
|
|
+ if (card_is_empress(dev) && vb2_is_busy(&dev->empress_vbq) &&
|
|
|
|
+ dmaq == &dev->video_q && dev->fmt->planar) {
|
|
|
|
+ struct saa7134_buf *buf, *tmp;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
|
|
|
|
+ list_del(&buf->entry);
|
|
|
|
+ vb2_buffer_done(&buf->vb2, VB2_BUF_STATE_QUEUED);
|
|
|
|
+ }
|
|
|
|
+ if (dmaq->curr) {
|
|
|
|
+ vb2_buffer_done(&dmaq->curr->vb2, VB2_BUF_STATE_QUEUED);
|
|
|
|
+ dmaq->curr = NULL;
|
|
|
|
+ }
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
|
|
|
|
+ * configured conservatively, there's 22 usec of buffering for video.
|
|
|
|
+ * We therefore request a DMA latency of 20 usec, giving us 2 usec of
|
|
|
|
+ * margin in case the FIFO is configured differently to the datasheet.
|
|
|
|
+ * Unfortunately, I lack register-level documentation to check the
|
|
|
|
+ * Linux FIFO setup and confirm the perfect value.
|
|
|
|
+ */
|
|
|
|
+ if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
|
|
|
|
+ (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
|
|
|
|
+ pm_qos_add_request(&dev->qos_request,
|
|
|
|
+ PM_QOS_CPU_DMA_LATENCY, 20);
|
|
|
|
+ dmaq->seq_nr = 0;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
|
|
|
|
|
+void saa7134_vb2_stop_streaming(struct vb2_queue *vq)
|
|
{
|
|
{
|
|
- struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
|
|
|
|
|
|
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
|
|
|
|
+ struct saa7134_dev *dev = dmaq->dev;
|
|
|
|
+
|
|
|
|
+ saa7134_stop_streaming(dev, dmaq);
|
|
|
|
|
|
- saa7134_dma_free(q,buf);
|
|
|
|
|
|
+ if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
|
|
|
|
+ (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
|
|
|
|
+ pm_qos_remove_request(&dev->qos_request);
|
|
}
|
|
}
|
|
|
|
|
|
-static struct videobuf_queue_ops video_qops = {
|
|
|
|
- .buf_setup = buffer_setup,
|
|
|
|
- .buf_prepare = buffer_prepare,
|
|
|
|
- .buf_queue = buffer_queue,
|
|
|
|
- .buf_release = buffer_release,
|
|
|
|
|
|
+static struct vb2_ops vb2_qops = {
|
|
|
|
+ .queue_setup = queue_setup,
|
|
|
|
+ .buf_init = buffer_init,
|
|
|
|
+ .buf_prepare = buffer_prepare,
|
|
|
|
+ .buf_finish = buffer_finish,
|
|
|
|
+ .buf_queue = saa7134_vb2_buffer_queue,
|
|
|
|
+ .wait_prepare = vb2_ops_wait_prepare,
|
|
|
|
+ .wait_finish = vb2_ops_wait_finish,
|
|
|
|
+ .start_streaming = saa7134_vb2_start_streaming,
|
|
|
|
+ .stop_streaming = saa7134_vb2_stop_streaming,
|
|
};
|
|
};
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------ */
|
|
@@ -1075,7 +1083,7 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
default:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
- if (restart_overlay && res_locked(dev, RESOURCE_OVERLAY)) {
|
|
|
|
|
|
+ if (restart_overlay && dev->overlay_owner) {
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
stop_preview(dev);
|
|
stop_preview(dev);
|
|
start_preview(dev);
|
|
start_preview(dev);
|
|
@@ -1086,55 +1094,21 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
|
|
-static struct videobuf_queue *saa7134_queue(struct file *file)
|
|
|
|
-{
|
|
|
|
- struct video_device *vdev = video_devdata(file);
|
|
|
|
- struct saa7134_dev *dev = video_drvdata(file);
|
|
|
|
- struct saa7134_fh *fh = file->private_data;
|
|
|
|
- struct videobuf_queue *q = NULL;
|
|
|
|
-
|
|
|
|
- switch (vdev->vfl_type) {
|
|
|
|
- case VFL_TYPE_GRABBER:
|
|
|
|
- q = fh->is_empress ? &dev->empress_vbq : &dev->video_vbq;
|
|
|
|
- break;
|
|
|
|
- case VFL_TYPE_VBI:
|
|
|
|
- q = &dev->vbi_vbq;
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- BUG();
|
|
|
|
- }
|
|
|
|
- return q;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int saa7134_resource(struct file *file)
|
|
|
|
|
|
+static inline struct vb2_queue *saa7134_queue(struct file *file)
|
|
{
|
|
{
|
|
- struct video_device *vdev = video_devdata(file);
|
|
|
|
- struct saa7134_fh *fh = file->private_data;
|
|
|
|
-
|
|
|
|
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
|
|
|
|
- return fh->is_empress ? RESOURCE_EMPRESS : RESOURCE_VIDEO;
|
|
|
|
-
|
|
|
|
- if (vdev->vfl_type == VFL_TYPE_VBI)
|
|
|
|
- return RESOURCE_VBI;
|
|
|
|
-
|
|
|
|
- BUG();
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return video_devdata(file)->queue;
|
|
}
|
|
}
|
|
|
|
|
|
static int video_open(struct file *file)
|
|
static int video_open(struct file *file)
|
|
{
|
|
{
|
|
struct video_device *vdev = video_devdata(file);
|
|
struct video_device *vdev = video_devdata(file);
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
- struct saa7134_fh *fh;
|
|
|
|
|
|
+ int ret = v4l2_fh_open(file);
|
|
|
|
|
|
- /* allocate + initialize per filehandle data */
|
|
|
|
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
|
|
|
|
- if (NULL == fh)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
- v4l2_fh_init(&fh->fh, vdev);
|
|
|
|
- file->private_data = fh;
|
|
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
+ mutex_lock(&dev->lock);
|
|
if (vdev->vfl_type == VFL_TYPE_RADIO) {
|
|
if (vdev->vfl_type == VFL_TYPE_RADIO) {
|
|
/* switch to radio mode */
|
|
/* switch to radio mode */
|
|
saa7134_tvaudio_setinput(dev, &card(dev).radio);
|
|
saa7134_tvaudio_setinput(dev, &card(dev).radio);
|
|
@@ -1143,127 +1117,34 @@ static int video_open(struct file *file)
|
|
/* switch to video/vbi mode */
|
|
/* switch to video/vbi mode */
|
|
video_mux(dev, dev->ctl_input);
|
|
video_mux(dev, dev->ctl_input);
|
|
}
|
|
}
|
|
- v4l2_fh_add(&fh->fh);
|
|
|
|
|
|
+ mutex_unlock(&dev->lock);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static ssize_t
|
|
|
|
-video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
|
|
|
|
-{
|
|
|
|
- struct video_device *vdev = video_devdata(file);
|
|
|
|
- struct saa7134_dev *dev = video_drvdata(file);
|
|
|
|
- struct saa7134_fh *fh = file->private_data;
|
|
|
|
-
|
|
|
|
- switch (vdev->vfl_type) {
|
|
|
|
- case VFL_TYPE_GRABBER:
|
|
|
|
- if (res_locked(dev, RESOURCE_VIDEO))
|
|
|
|
- return -EBUSY;
|
|
|
|
- return videobuf_read_one(saa7134_queue(file),
|
|
|
|
- data, count, ppos,
|
|
|
|
- file->f_flags & O_NONBLOCK);
|
|
|
|
- case VFL_TYPE_VBI:
|
|
|
|
- if (!res_get(dev, fh, RESOURCE_VBI))
|
|
|
|
- return -EBUSY;
|
|
|
|
- return videobuf_read_stream(saa7134_queue(file),
|
|
|
|
- data, count, ppos, 1,
|
|
|
|
- file->f_flags & O_NONBLOCK);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- BUG();
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static unsigned int
|
|
|
|
-video_poll(struct file *file, struct poll_table_struct *wait)
|
|
|
|
-{
|
|
|
|
- unsigned long req_events = poll_requested_events(wait);
|
|
|
|
- struct video_device *vdev = video_devdata(file);
|
|
|
|
- struct saa7134_dev *dev = video_drvdata(file);
|
|
|
|
- struct saa7134_fh *fh = file->private_data;
|
|
|
|
- struct videobuf_buffer *buf = NULL;
|
|
|
|
- struct videobuf_queue *q = &dev->video_vbq;
|
|
|
|
- unsigned int rc = 0;
|
|
|
|
-
|
|
|
|
- if (v4l2_event_pending(&fh->fh))
|
|
|
|
- rc = POLLPRI;
|
|
|
|
- else if (req_events & POLLPRI)
|
|
|
|
- poll_wait(file, &fh->fh.wait, wait);
|
|
|
|
-
|
|
|
|
- if (vdev->vfl_type == VFL_TYPE_VBI)
|
|
|
|
- return rc | videobuf_poll_stream(file, &dev->vbi_vbq, wait);
|
|
|
|
-
|
|
|
|
- if (res_check(fh, RESOURCE_VIDEO)) {
|
|
|
|
- mutex_lock(&q->vb_lock);
|
|
|
|
- if (!list_empty(&q->stream))
|
|
|
|
- buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
|
|
|
|
- } else {
|
|
|
|
- mutex_lock(&q->vb_lock);
|
|
|
|
- if (UNSET == q->read_off) {
|
|
|
|
- /* need to capture a new frame */
|
|
|
|
- if (res_locked(dev, RESOURCE_VIDEO))
|
|
|
|
- goto err;
|
|
|
|
- if (0 != q->ops->buf_prepare(q, q->read_buf, q->field))
|
|
|
|
- goto err;
|
|
|
|
- q->ops->buf_queue(q, q->read_buf);
|
|
|
|
- q->read_off = 0;
|
|
|
|
- }
|
|
|
|
- buf = q->read_buf;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!buf)
|
|
|
|
- goto err;
|
|
|
|
-
|
|
|
|
- poll_wait(file, &buf->done, wait);
|
|
|
|
- if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR)
|
|
|
|
- rc |= POLLIN | POLLRDNORM;
|
|
|
|
- mutex_unlock(&q->vb_lock);
|
|
|
|
- return rc;
|
|
|
|
-
|
|
|
|
-err:
|
|
|
|
- mutex_unlock(&q->vb_lock);
|
|
|
|
- return rc | POLLERR;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int video_release(struct file *file)
|
|
static int video_release(struct file *file)
|
|
{
|
|
{
|
|
struct video_device *vdev = video_devdata(file);
|
|
struct video_device *vdev = video_devdata(file);
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
- struct saa7134_fh *fh = file->private_data;
|
|
|
|
|
|
+ struct v4l2_fh *fh = file->private_data;
|
|
struct saa6588_command cmd;
|
|
struct saa6588_command cmd;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
+ mutex_lock(&dev->lock);
|
|
saa7134_tvaudio_close(dev);
|
|
saa7134_tvaudio_close(dev);
|
|
|
|
|
|
/* turn off overlay */
|
|
/* turn off overlay */
|
|
- if (res_check(fh, RESOURCE_OVERLAY)) {
|
|
|
|
|
|
+ if (fh == dev->overlay_owner) {
|
|
spin_lock_irqsave(&dev->slock,flags);
|
|
spin_lock_irqsave(&dev->slock,flags);
|
|
stop_preview(dev);
|
|
stop_preview(dev);
|
|
spin_unlock_irqrestore(&dev->slock,flags);
|
|
spin_unlock_irqrestore(&dev->slock,flags);
|
|
- res_free(dev, fh, RESOURCE_OVERLAY);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* stop video capture */
|
|
|
|
- if (res_check(fh, RESOURCE_VIDEO)) {
|
|
|
|
- pm_qos_remove_request(&dev->qos_request);
|
|
|
|
- videobuf_streamoff(&dev->video_vbq);
|
|
|
|
- res_free(dev, fh, RESOURCE_VIDEO);
|
|
|
|
- videobuf_mmap_free(&dev->video_vbq);
|
|
|
|
- INIT_LIST_HEAD(&dev->video_vbq.stream);
|
|
|
|
- }
|
|
|
|
- if (dev->video_vbq.read_buf) {
|
|
|
|
- buffer_release(&dev->video_vbq, dev->video_vbq.read_buf);
|
|
|
|
- kfree(dev->video_vbq.read_buf);
|
|
|
|
|
|
+ dev->overlay_owner = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- /* stop vbi capture */
|
|
|
|
- if (res_check(fh, RESOURCE_VBI)) {
|
|
|
|
- videobuf_stop(&dev->vbi_vbq);
|
|
|
|
- res_free(dev, fh, RESOURCE_VBI);
|
|
|
|
- videobuf_mmap_free(&dev->vbi_vbq);
|
|
|
|
- INIT_LIST_HEAD(&dev->vbi_vbq.stream);
|
|
|
|
- }
|
|
|
|
|
|
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
|
|
|
|
+ v4l2_fh_release(file);
|
|
|
|
+ else
|
|
|
|
+ _vb2_fop_release(file, NULL);
|
|
|
|
|
|
/* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
|
|
/* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
|
|
saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
|
|
saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
|
|
@@ -1274,19 +1155,11 @@ static int video_release(struct file *file)
|
|
saa_call_all(dev, core, s_power, 0);
|
|
saa_call_all(dev, core, s_power, 0);
|
|
if (vdev->vfl_type == VFL_TYPE_RADIO)
|
|
if (vdev->vfl_type == VFL_TYPE_RADIO)
|
|
saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
|
|
saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
|
|
|
|
+ mutex_unlock(&dev->lock);
|
|
|
|
|
|
- v4l2_fh_del(&fh->fh);
|
|
|
|
- v4l2_fh_exit(&fh->fh);
|
|
|
|
- file->private_data = NULL;
|
|
|
|
- kfree(fh);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int video_mmap(struct file *file, struct vm_area_struct * vma)
|
|
|
|
-{
|
|
|
|
- return videobuf_mmap_mapper(saa7134_queue(file), vma);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static ssize_t radio_read(struct file *file, char __user *data,
|
|
static ssize_t radio_read(struct file *file, char __user *data,
|
|
size_t count, loff_t *ppos)
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
{
|
|
@@ -1299,7 +1172,9 @@ static ssize_t radio_read(struct file *file, char __user *data,
|
|
cmd.instance = file;
|
|
cmd.instance = file;
|
|
cmd.result = -ENODEV;
|
|
cmd.result = -ENODEV;
|
|
|
|
|
|
|
|
+ mutex_lock(&dev->lock);
|
|
saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
|
|
saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
|
|
|
|
+ mutex_unlock(&dev->lock);
|
|
|
|
|
|
return cmd.result;
|
|
return cmd.result;
|
|
}
|
|
}
|
|
@@ -1313,7 +1188,9 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
|
|
cmd.instance = file;
|
|
cmd.instance = file;
|
|
cmd.event_list = wait;
|
|
cmd.event_list = wait;
|
|
cmd.result = 0;
|
|
cmd.result = 0;
|
|
|
|
+ mutex_lock(&dev->lock);
|
|
saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
|
|
saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
|
|
|
|
+ mutex_unlock(&dev->lock);
|
|
|
|
|
|
return rc | cmd.result;
|
|
return rc | cmd.result;
|
|
}
|
|
}
|
|
@@ -1347,7 +1224,7 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
|
|
|
|
|
|
f->fmt.pix.width = dev->width;
|
|
f->fmt.pix.width = dev->width;
|
|
f->fmt.pix.height = dev->height;
|
|
f->fmt.pix.height = dev->height;
|
|
- f->fmt.pix.field = dev->video_vbq.field;
|
|
|
|
|
|
+ f->fmt.pix.field = dev->field;
|
|
f->fmt.pix.pixelformat = dev->fmt->fourcc;
|
|
f->fmt.pix.pixelformat = dev->fmt->fourcc;
|
|
f->fmt.pix.bytesperline =
|
|
f->fmt.pix.bytesperline =
|
|
(f->fmt.pix.width * dev->fmt->depth) >> 3;
|
|
(f->fmt.pix.width * dev->fmt->depth) >> 3;
|
|
@@ -1371,7 +1248,6 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
|
|
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
|
|
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
- mutex_lock(&dev->lock);
|
|
|
|
f->fmt.win = dev->win;
|
|
f->fmt.win = dev->win;
|
|
f->fmt.win.clips = clips;
|
|
f->fmt.win.clips = clips;
|
|
if (clips == NULL)
|
|
if (clips == NULL)
|
|
@@ -1385,7 +1261,6 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
|
|
sizeof(struct v4l2_rect)))
|
|
sizeof(struct v4l2_rect)))
|
|
err = -EFAULT;
|
|
err = -EFAULT;
|
|
}
|
|
}
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
|
|
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
@@ -1469,7 +1344,7 @@ static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
|
|
dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
|
|
dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
|
|
dev->width = f->fmt.pix.width;
|
|
dev->width = f->fmt.pix.width;
|
|
dev->height = f->fmt.pix.height;
|
|
dev->height = f->fmt.pix.height;
|
|
- dev->video_vbq.field = f->fmt.pix.field;
|
|
|
|
|
|
+ dev->field = f->fmt.pix.field;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1490,25 +1365,20 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
|
|
if (0 != err)
|
|
if (0 != err)
|
|
return err;
|
|
return err;
|
|
|
|
|
|
- mutex_lock(&dev->lock);
|
|
|
|
-
|
|
|
|
dev->win = f->fmt.win;
|
|
dev->win = f->fmt.win;
|
|
dev->nclips = f->fmt.win.clipcount;
|
|
dev->nclips = f->fmt.win.clipcount;
|
|
|
|
|
|
if (copy_from_user(dev->clips, f->fmt.win.clips,
|
|
if (copy_from_user(dev->clips, f->fmt.win.clips,
|
|
- sizeof(struct v4l2_clip) * dev->nclips)) {
|
|
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
|
|
+ sizeof(struct v4l2_clip) * dev->nclips))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- }
|
|
|
|
|
|
|
|
- if (res_check(priv, RESOURCE_OVERLAY)) {
|
|
|
|
|
|
+ if (priv == dev->overlay_owner) {
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
stop_preview(dev);
|
|
stop_preview(dev);
|
|
start_preview(dev);
|
|
start_preview(dev);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1560,9 +1430,7 @@ int saa7134_s_input(struct file *file, void *priv, unsigned int i)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
if (NULL == card_in(dev, i).name)
|
|
if (NULL == card_in(dev, i).name)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- mutex_lock(&dev->lock);
|
|
|
|
video_mux(dev, i);
|
|
video_mux(dev, i);
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(saa7134_s_input);
|
|
EXPORT_SYMBOL_GPL(saa7134_s_input);
|
|
@@ -1572,7 +1440,6 @@ int saa7134_querycap(struct file *file, void *priv,
|
|
{
|
|
{
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
struct video_device *vdev = video_devdata(file);
|
|
struct video_device *vdev = video_devdata(file);
|
|
- struct saa7134_fh *fh = priv;
|
|
|
|
u32 radio_caps, video_caps, vbi_caps;
|
|
u32 radio_caps, video_caps, vbi_caps;
|
|
|
|
|
|
unsigned int tuner_type = dev->tuner_type;
|
|
unsigned int tuner_type = dev->tuner_type;
|
|
@@ -1591,7 +1458,7 @@ int saa7134_querycap(struct file *file, void *priv,
|
|
radio_caps |= V4L2_CAP_RDS_CAPTURE;
|
|
radio_caps |= V4L2_CAP_RDS_CAPTURE;
|
|
|
|
|
|
video_caps = V4L2_CAP_VIDEO_CAPTURE;
|
|
video_caps = V4L2_CAP_VIDEO_CAPTURE;
|
|
- if (saa7134_no_overlay <= 0 && !fh->is_empress)
|
|
|
|
|
|
+ if (saa7134_no_overlay <= 0 && !is_empress(file))
|
|
video_caps |= V4L2_CAP_VIDEO_OVERLAY;
|
|
video_caps |= V4L2_CAP_VIDEO_OVERLAY;
|
|
|
|
|
|
vbi_caps = V4L2_CAP_VBI_CAPTURE;
|
|
vbi_caps = V4L2_CAP_VBI_CAPTURE;
|
|
@@ -1622,12 +1489,12 @@ EXPORT_SYMBOL_GPL(saa7134_querycap);
|
|
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
{
|
|
{
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
struct saa7134_dev *dev = video_drvdata(file);
|
|
- struct saa7134_fh *fh = priv;
|
|
|
|
|
|
+ struct v4l2_fh *fh = priv;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
unsigned int i;
|
|
unsigned int i;
|
|
v4l2_std_id fixup;
|
|
v4l2_std_id fixup;
|
|
|
|
|
|
- if (fh->is_empress && res_locked(dev, RESOURCE_OVERLAY)) {
|
|
|
|
|
|
+ if (is_empress(file) && dev->overlay_owner) {
|
|
/* Don't change the std from the mpeg device
|
|
/* Don't change the std from the mpeg device
|
|
if overlay is active. */
|
|
if overlay is active. */
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
@@ -1666,8 +1533,7 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
|
|
|
|
id = tvnorms[i].id;
|
|
id = tvnorms[i].id;
|
|
|
|
|
|
- mutex_lock(&dev->lock);
|
|
|
|
- if (!fh->is_empress && res_check(fh, RESOURCE_OVERLAY)) {
|
|
|
|
|
|
+ if (!is_empress(file) && fh == dev->overlay_owner) {
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
stop_preview(dev);
|
|
stop_preview(dev);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
@@ -1681,7 +1547,6 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
set_tvnorm(dev, &tvnorms[i]);
|
|
set_tvnorm(dev, &tvnorms[i]);
|
|
|
|
|
|
saa7134_tvaudio_do_scan(dev);
|
|
saa7134_tvaudio_do_scan(dev);
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(saa7134_s_std);
|
|
EXPORT_SYMBOL_GPL(saa7134_s_std);
|
|
@@ -1768,9 +1633,9 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr
|
|
crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
|
|
crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if (res_locked(dev, RESOURCE_OVERLAY))
|
|
|
|
|
|
+ if (dev->overlay_owner)
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
- if (res_locked(dev, RESOURCE_VIDEO))
|
|
|
|
|
|
+ if (vb2_is_streaming(&dev->video_vbq))
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
|
|
*c = crop->c;
|
|
*c = crop->c;
|
|
@@ -1864,12 +1729,10 @@ int saa7134_s_frequency(struct file *file, void *priv,
|
|
|
|
|
|
if (0 != f->tuner)
|
|
if (0 != f->tuner)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- mutex_lock(&dev->lock);
|
|
|
|
|
|
|
|
saa_call_all(dev, tuner, s_frequency, f);
|
|
saa_call_all(dev, tuner, s_frequency, f);
|
|
|
|
|
|
saa7134_tvaudio_do_scan(dev);
|
|
saa7134_tvaudio_do_scan(dev);
|
|
- mutex_unlock(&dev->lock);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(saa7134_s_frequency);
|
|
EXPORT_SYMBOL_GPL(saa7134_s_frequency);
|
|
@@ -1953,87 +1816,24 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!res_get(dev, priv, RESOURCE_OVERLAY))
|
|
|
|
|
|
+ if (dev->overlay_owner && priv != dev->overlay_owner)
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
+ dev->overlay_owner = priv;
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
start_preview(dev);
|
|
start_preview(dev);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
}
|
|
}
|
|
if (!on) {
|
|
if (!on) {
|
|
- if (!res_check(priv, RESOURCE_OVERLAY))
|
|
|
|
|
|
+ if (priv != dev->overlay_owner)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
stop_preview(dev);
|
|
stop_preview(dev);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
- res_free(dev, priv, RESOURCE_OVERLAY);
|
|
|
|
|
|
+ dev->overlay_owner = NULL;
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-int saa7134_reqbufs(struct file *file, void *priv,
|
|
|
|
- struct v4l2_requestbuffers *p)
|
|
|
|
-{
|
|
|
|
- return videobuf_reqbufs(saa7134_queue(file), p);
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(saa7134_reqbufs);
|
|
|
|
-
|
|
|
|
-int saa7134_querybuf(struct file *file, void *priv,
|
|
|
|
- struct v4l2_buffer *b)
|
|
|
|
-{
|
|
|
|
- return videobuf_querybuf(saa7134_queue(file), b);
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(saa7134_querybuf);
|
|
|
|
-
|
|
|
|
-int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
|
|
|
-{
|
|
|
|
- return videobuf_qbuf(saa7134_queue(file), b);
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(saa7134_qbuf);
|
|
|
|
-
|
|
|
|
-int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
|
|
|
-{
|
|
|
|
- return videobuf_dqbuf(saa7134_queue(file), b,
|
|
|
|
- file->f_flags & O_NONBLOCK);
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(saa7134_dqbuf);
|
|
|
|
-
|
|
|
|
-int saa7134_streamon(struct file *file, void *priv,
|
|
|
|
- enum v4l2_buf_type type)
|
|
|
|
-{
|
|
|
|
- struct saa7134_dev *dev = video_drvdata(file);
|
|
|
|
- int res = saa7134_resource(file);
|
|
|
|
-
|
|
|
|
- if (!res_get(dev, priv, res))
|
|
|
|
- return -EBUSY;
|
|
|
|
-
|
|
|
|
- /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
|
|
|
|
- * configured conservatively, there's 22 usec of buffering for video.
|
|
|
|
- * We therefore request a DMA latency of 20 usec, giving us 2 usec of
|
|
|
|
- * margin in case the FIFO is configured differently to the datasheet.
|
|
|
|
- * Unfortunately, I lack register-level documentation to check the
|
|
|
|
- * Linux FIFO setup and confirm the perfect value.
|
|
|
|
- */
|
|
|
|
- if (res != RESOURCE_EMPRESS)
|
|
|
|
- pm_qos_add_request(&dev->qos_request,
|
|
|
|
- PM_QOS_CPU_DMA_LATENCY, 20);
|
|
|
|
-
|
|
|
|
- return videobuf_streamon(saa7134_queue(file));
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(saa7134_streamon);
|
|
|
|
-
|
|
|
|
-int saa7134_streamoff(struct file *file, void *priv,
|
|
|
|
- enum v4l2_buf_type type)
|
|
|
|
-{
|
|
|
|
- struct saa7134_dev *dev = video_drvdata(file);
|
|
|
|
- int res = saa7134_resource(file);
|
|
|
|
-
|
|
|
|
- if (res != RESOURCE_EMPRESS)
|
|
|
|
- pm_qos_remove_request(&dev->qos_request);
|
|
|
|
-
|
|
|
|
- return videobuf_streamoff(saa7134_queue(file));
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(saa7134_streamoff);
|
|
|
|
-
|
|
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
static int vidioc_g_register (struct file *file, void *priv,
|
|
static int vidioc_g_register (struct file *file, void *priv,
|
|
struct v4l2_dbg_register *reg)
|
|
struct v4l2_dbg_register *reg)
|
|
@@ -2091,10 +1891,10 @@ static const struct v4l2_file_operations video_fops =
|
|
.owner = THIS_MODULE,
|
|
.owner = THIS_MODULE,
|
|
.open = video_open,
|
|
.open = video_open,
|
|
.release = video_release,
|
|
.release = video_release,
|
|
- .read = video_read,
|
|
|
|
- .poll = video_poll,
|
|
|
|
- .mmap = video_mmap,
|
|
|
|
- .ioctl = video_ioctl2,
|
|
|
|
|
|
+ .read = vb2_fop_read,
|
|
|
|
+ .poll = vb2_fop_poll,
|
|
|
|
+ .mmap = vb2_fop_mmap,
|
|
|
|
+ .unlocked_ioctl = video_ioctl2,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
@@ -2111,18 +1911,18 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
|
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
|
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
|
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
|
.vidioc_cropcap = saa7134_cropcap,
|
|
.vidioc_cropcap = saa7134_cropcap,
|
|
- .vidioc_reqbufs = saa7134_reqbufs,
|
|
|
|
- .vidioc_querybuf = saa7134_querybuf,
|
|
|
|
- .vidioc_qbuf = saa7134_qbuf,
|
|
|
|
- .vidioc_dqbuf = saa7134_dqbuf,
|
|
|
|
|
|
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
|
|
|
|
+ .vidioc_querybuf = vb2_ioctl_querybuf,
|
|
|
|
+ .vidioc_qbuf = vb2_ioctl_qbuf,
|
|
|
|
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
|
|
.vidioc_s_std = saa7134_s_std,
|
|
.vidioc_s_std = saa7134_s_std,
|
|
.vidioc_g_std = saa7134_g_std,
|
|
.vidioc_g_std = saa7134_g_std,
|
|
.vidioc_querystd = saa7134_querystd,
|
|
.vidioc_querystd = saa7134_querystd,
|
|
.vidioc_enum_input = saa7134_enum_input,
|
|
.vidioc_enum_input = saa7134_enum_input,
|
|
.vidioc_g_input = saa7134_g_input,
|
|
.vidioc_g_input = saa7134_g_input,
|
|
.vidioc_s_input = saa7134_s_input,
|
|
.vidioc_s_input = saa7134_s_input,
|
|
- .vidioc_streamon = saa7134_streamon,
|
|
|
|
- .vidioc_streamoff = saa7134_streamoff,
|
|
|
|
|
|
+ .vidioc_streamon = vb2_ioctl_streamon,
|
|
|
|
+ .vidioc_streamoff = vb2_ioctl_streamoff,
|
|
.vidioc_g_tuner = saa7134_g_tuner,
|
|
.vidioc_g_tuner = saa7134_g_tuner,
|
|
.vidioc_s_tuner = saa7134_s_tuner,
|
|
.vidioc_s_tuner = saa7134_s_tuner,
|
|
.vidioc_g_crop = saa7134_g_crop,
|
|
.vidioc_g_crop = saa7134_g_crop,
|
|
@@ -2146,7 +1946,7 @@ static const struct v4l2_file_operations radio_fops = {
|
|
.open = video_open,
|
|
.open = video_open,
|
|
.read = radio_read,
|
|
.read = radio_read,
|
|
.release = video_release,
|
|
.release = video_release,
|
|
- .ioctl = video_ioctl2,
|
|
|
|
|
|
+ .unlocked_ioctl = video_ioctl2,
|
|
.poll = radio_poll,
|
|
.poll = radio_poll,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -2224,6 +2024,8 @@ static const struct v4l2_ctrl_config saa7134_ctrl_automute = {
|
|
int saa7134_video_init1(struct saa7134_dev *dev)
|
|
int saa7134_video_init1(struct saa7134_dev *dev)
|
|
{
|
|
{
|
|
struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
|
|
struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
|
|
|
|
+ struct vb2_queue *q;
|
|
|
|
+ int ret;
|
|
|
|
|
|
/* sanitycheck insmod options */
|
|
/* sanitycheck insmod options */
|
|
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
|
|
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
|
|
@@ -2275,6 +2077,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
|
|
dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
|
|
dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
|
|
dev->width = 720;
|
|
dev->width = 720;
|
|
dev->height = 576;
|
|
dev->height = 576;
|
|
|
|
+ dev->field = V4L2_FIELD_INTERLACED;
|
|
dev->win.w.width = dev->width;
|
|
dev->win.w.width = dev->width;
|
|
dev->win.w.height = dev->height;
|
|
dev->win.w.height = dev->height;
|
|
dev->win.field = V4L2_FIELD_INTERLACED;
|
|
dev->win.field = V4L2_FIELD_INTERLACED;
|
|
@@ -2286,19 +2089,40 @@ int saa7134_video_init1(struct saa7134_dev *dev)
|
|
if (saa7134_boards[dev->board].video_out)
|
|
if (saa7134_boards[dev->board].video_out)
|
|
saa7134_videoport_init(dev);
|
|
saa7134_videoport_init(dev);
|
|
|
|
|
|
- videobuf_queue_sg_init(&dev->video_vbq, &video_qops,
|
|
|
|
- &dev->pci->dev, &dev->slock,
|
|
|
|
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
|
|
|
- V4L2_FIELD_INTERLACED,
|
|
|
|
- sizeof(struct saa7134_buf),
|
|
|
|
- &dev->video_q, NULL);
|
|
|
|
- videobuf_queue_sg_init(&dev->vbi_vbq, &saa7134_vbi_qops,
|
|
|
|
- &dev->pci->dev, &dev->slock,
|
|
|
|
- V4L2_BUF_TYPE_VBI_CAPTURE,
|
|
|
|
- V4L2_FIELD_SEQ_TB,
|
|
|
|
- sizeof(struct saa7134_buf),
|
|
|
|
- &dev->vbi_q, NULL);
|
|
|
|
|
|
+ q = &dev->video_vbq;
|
|
|
|
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
+ /*
|
|
|
|
+ * Do not add VB2_USERPTR: the saa7134 DMA engine cannot handle
|
|
|
|
+ * transfers that do not start at the beginning of a page. A USERPTR
|
|
|
|
+ * can start anywhere in a page, so USERPTR support is a no-go.
|
|
|
|
+ */
|
|
|
|
+ q->io_modes = VB2_MMAP | VB2_READ;
|
|
|
|
+ q->drv_priv = &dev->video_q;
|
|
|
|
+ q->ops = &vb2_qops;
|
|
|
|
+ q->gfp_flags = GFP_DMA32;
|
|
|
|
+ q->mem_ops = &vb2_dma_sg_memops;
|
|
|
|
+ q->buf_struct_size = sizeof(struct saa7134_buf);
|
|
|
|
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
|
|
|
+ q->lock = &dev->lock;
|
|
|
|
+ ret = vb2_queue_init(q);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
|
|
saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
|
|
|
|
+
|
|
|
|
+ q = &dev->vbi_vbq;
|
|
|
|
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
|
|
|
+ /* Don't add VB2_USERPTR, see comment above */
|
|
|
|
+ q->io_modes = VB2_MMAP | VB2_READ;
|
|
|
|
+ q->drv_priv = &dev->vbi_q;
|
|
|
|
+ q->ops = &saa7134_vbi_qops;
|
|
|
|
+ q->gfp_flags = GFP_DMA32;
|
|
|
|
+ q->mem_ops = &vb2_dma_sg_memops;
|
|
|
|
+ q->buf_struct_size = sizeof(struct saa7134_buf);
|
|
|
|
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
|
|
|
+ q->lock = &dev->lock;
|
|
|
|
+ ret = vb2_queue_init(q);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
|
|
saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -2307,7 +2131,9 @@ int saa7134_video_init1(struct saa7134_dev *dev)
|
|
void saa7134_video_fini(struct saa7134_dev *dev)
|
|
void saa7134_video_fini(struct saa7134_dev *dev)
|
|
{
|
|
{
|
|
/* free stuff */
|
|
/* free stuff */
|
|
|
|
+ vb2_queue_release(&dev->video_vbq);
|
|
saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
|
|
saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
|
|
|
|
+ vb2_queue_release(&dev->vbi_vbq);
|
|
saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
|
|
saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
|
|
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
|
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
|
if (card_has_radio(dev))
|
|
if (card_has_radio(dev))
|
|
@@ -2401,8 +2227,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
|
|
|
|
|
|
spin_lock(&dev->slock);
|
|
spin_lock(&dev->slock);
|
|
if (dev->video_q.curr) {
|
|
if (dev->video_q.curr) {
|
|
- dev->video_fieldcount++;
|
|
|
|
- field = dev->video_q.curr->vb.field;
|
|
|
|
|
|
+ field = dev->field;
|
|
if (V4L2_FIELD_HAS_BOTH(field)) {
|
|
if (V4L2_FIELD_HAS_BOTH(field)) {
|
|
/* make sure we have seen both fields */
|
|
/* make sure we have seen both fields */
|
|
if ((status & 0x10) == 0x00) {
|
|
if ((status & 0x10) == 0x00) {
|
|
@@ -2418,8 +2243,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
|
|
if ((status & 0x10) != 0x00)
|
|
if ((status & 0x10) != 0x00)
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
- dev->video_q.curr->vb.field_count = dev->video_fieldcount;
|
|
|
|
- saa7134_buffer_finish(dev, &dev->video_q, VIDEOBUF_DONE);
|
|
|
|
|
|
+ saa7134_buffer_finish(dev, &dev->video_q, VB2_BUF_STATE_DONE);
|
|
}
|
|
}
|
|
saa7134_buffer_next(dev, &dev->video_q);
|
|
saa7134_buffer_next(dev, &dev->video_q);
|
|
|
|
|