summaryrefslogtreecommitdiff
path: root/drivers/media/usb/cx231xx/cx231xx-vbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/cx231xx/cx231xx-vbi.c')
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c245
1 files changed, 99 insertions, 146 deletions
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index c02794274f51..338e10148465 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -1,30 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
cx231xx_vbi.c - driver for Conexant Cx23100/101/102 USB video capture devices
Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
Based on cx88 driver
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bitmap.h>
-#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/mm.h>
#include <linux/mutex.h>
@@ -32,10 +20,9 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/tuner.h>
-#include "cx231xx.h"
#include "cx231xx-vbi.h"
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
@@ -44,10 +31,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
switch (status) {
case -ENOENT:
- errmsg = "unlinked synchronuously";
+ errmsg = "unlinked synchronously";
break;
case -ECONNRESET:
- errmsg = "unlinked asynchronuously";
+ errmsg = "unlinked asynchronously";
break;
case -ENOSR:
errmsg = "Buffer error (overrun)";
@@ -69,11 +56,12 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
break;
}
if (packet < 0) {
- cx231xx_err("URB status %d [%s].\n", status,
- errmsg);
+ dev_err(dev->dev,
+ "URB status %d [%s].\n", status, errmsg);
} else {
- cx231xx_err("URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
+ dev_err(dev->dev,
+ "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
}
}
@@ -165,132 +153,96 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
Vbi buf operations
------------------------------------------------------------------*/
-static int
-vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+static int vbi_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = vb2_get_drv_priv(vq);
u32 height = 0;
height = ((dev->norm & V4L2_STD_625_50) ?
PAL_VBI_LINES : NTSC_VBI_LINES);
- *size = (dev->width * height * 2 * 2);
- if (0 == *count)
- *count = CX231XX_DEF_VBI_BUF;
-
- if (*count < CX231XX_MIN_BUF)
- *count = CX231XX_MIN_BUF;
-
+ *nplanes = 1;
+ sizes[0] = (dev->width * height * 2 * 2);
return 0;
}
/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
-{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->vbi_mode.slock, flags);
- if (dev->vbi_mode.bulk_ctl.buf == buf)
- dev->vbi_mode.bulk_ctl.buf = NULL;
- spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int vbi_buf_prepare(struct vb2_buffer *vb)
{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx *dev = fh->dev;
- int rc = 0, urb_init = 0;
+ struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
u32 height = 0;
+ u32 size;
height = ((dev->norm & V4L2_STD_625_50) ?
PAL_VBI_LINES : NTSC_VBI_LINES);
- buf->vb.size = ((dev->width << 1) * height * 2);
+ size = ((dev->width << 1) * height * 2);
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ if (vb2_plane_size(vb, 0) < size)
return -EINVAL;
-
- buf->vb.width = dev->width;
- buf->vb.height = height;
- buf->vb.field = field;
- buf->vb.field = V4L2_FIELD_SEQ_TB;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- if (!dev->vbi_mode.bulk_ctl.num_bufs)
- urb_init = 1;
-
- if (urb_init) {
- rc = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS,
- CX231XX_NUM_VBI_BUFS,
- dev->vbi_mode.alt_max_pkt_size[0],
- cx231xx_isoc_vbi_copy);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
+ vb2_set_plane_payload(vb, 0, size);
return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
}
-static void
-vbi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void vbi_buf_queue(struct vb2_buffer *vb)
{
+ struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
+ container_of(vb, struct cx231xx_buffer, vb.vb2_buf);
struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->vbi_mode.slock, flags);
+ list_add_tail(&buf->list, &vidq->active);
+ spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
+}
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
+static void return_all_buffers(struct cx231xx *dev,
+ enum vb2_buffer_state state)
+{
+ struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq;
+ struct cx231xx_buffer *buf, *node;
+ unsigned long flags;
+ spin_lock_irqsave(&dev->vbi_mode.slock, flags);
+ dev->vbi_mode.bulk_ctl.buf = NULL;
+ list_for_each_entry_safe(buf, node, &vidq->active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+ spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
}
-static void vbi_buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static int vbi_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = vb2_get_drv_priv(vq);
+ struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq;
+ int ret;
+
+ vidq->sequence = 0;
+ ret = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS,
+ CX231XX_NUM_VBI_BUFS,
+ dev->vbi_mode.alt_max_pkt_size[0],
+ cx231xx_isoc_vbi_copy);
+ if (ret)
+ return_all_buffers(dev, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
+static void vbi_stop_streaming(struct vb2_queue *vq)
+{
+ struct cx231xx *dev = vb2_get_drv_priv(vq);
- free_buffer(vq, buf);
+ return_all_buffers(dev, VB2_BUF_STATE_ERROR);
}
-struct videobuf_queue_ops cx231xx_vbi_qops = {
- .buf_setup = vbi_buffer_setup,
- .buf_prepare = vbi_buffer_prepare,
- .buf_queue = vbi_buffer_queue,
- .buf_release = vbi_buffer_release,
+struct vb2_ops cx231xx_vbi_qops = {
+ .queue_setup = vbi_queue_setup,
+ .buf_prepare = vbi_buf_prepare,
+ .buf_queue = vbi_buf_queue,
+ .start_streaming = vbi_start_streaming,
+ .stop_streaming = vbi_stop_streaming,
};
/* ------------------------------------------------------------------
@@ -306,6 +258,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
+ unsigned long flags;
switch (urb->status) {
case 0: /* success */
@@ -316,23 +269,23 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- cx231xx_err("urb completition error %d.\n",
- urb->status);
+ dev_err(dev->dev,
+ "urb completion error %d.\n", urb->status);
break;
}
/* Copy data from URB */
- spin_lock(&dev->vbi_mode.slock);
+ spin_lock_irqsave(&dev->vbi_mode.slock, flags);
dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
- spin_unlock(&dev->vbi_mode.slock);
+ spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
/* Reset status */
urb->status = 0;
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
if (urb->status) {
- cx231xx_err("urb resubmit failed (error=%i)\n",
- urb->status);
+ dev_err(dev->dev, "urb resubmit failed (error=%i)\n",
+ urb->status);
}
}
@@ -344,7 +297,7 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
struct urb *urb;
int i;
- cx231xx_info("called cx231xx_uninit_vbi_isoc\n");
+ dev_dbg(dev->dev, "called cx231xx_uninit_vbi_isoc\n");
dev->vbi_mode.bulk_ctl.nfields = -1;
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
@@ -393,7 +346,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
struct urb *urb;
int rc;
- cx231xx_info("called cx231xx_vbi_isoc\n");
+ dev_dbg(dev->dev, "called cx231xx_vbi_isoc\n");
/* De-allocates all pending stuff */
cx231xx_uninit_vbi_isoc(dev);
@@ -416,17 +369,19 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < 8; i++)
dma_q->partial_buf[i] = 0;
- dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
+ dev->vbi_mode.bulk_ctl.urb = kcalloc(num_bufs, sizeof(void *),
GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.urb) {
- cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ dev_err(dev->dev,
+ "cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
dev->vbi_mode.bulk_ctl.transfer_buffer =
- kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+ kcalloc(num_bufs, sizeof(void *), GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.transfer_buffer) {
- cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ dev_err(dev->dev,
+ "cannot allocate memory for usbtransfer\n");
kfree(dev->vbi_mode.bulk_ctl.urb);
return -ENOMEM;
}
@@ -441,7 +396,6 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
@@ -451,9 +405,9 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
- cx231xx_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n", sb_size, i,
- in_interrupt() ? " while in int" : "");
+ dev_err(dev->dev,
+ "unable to allocate %i bytes for transfer buffer %i\n",
+ sb_size, i);
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
@@ -470,8 +424,8 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
if (rc) {
- cx231xx_err("submit of urb %i failed (error=%i)\n", i,
- rc);
+ dev_err(dev->dev,
+ "submit of urb %i failed (error=%i)\n", i, rc);
cx231xx_uninit_vbi_isoc(dev);
return rc;
}
@@ -522,16 +476,15 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
struct cx231xx_buffer *buf)
{
/* Advice that buffer was filled */
- /* cx231xx_info("[%p/%d] wakeup\n", buf, buf->vb.i); */
+ /* dev_dbg(dev->dev, "[%p/%d] wakeup\n", buf, buf->vb.index); */
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- v4l2_get_timestamp(&buf->vb.ts);
+ buf->vb.sequence = dma_q->sequence++;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
dev->vbi_mode.bulk_ctl.buf = NULL;
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
@@ -603,7 +556,7 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
}
/*
- * video-buf generic routine to get the next available buffer
+ * generic routine to get the next available buffer
*/
static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
struct cx231xx_buffer **buf)
@@ -614,18 +567,18 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
char *outp;
if (list_empty(&dma_q->active)) {
- cx231xx_err("No active queue to serve\n");
+ dev_err(dev->dev, "No active queue to serve\n");
dev->vbi_mode.bulk_ctl.buf = NULL;
*buf = NULL;
return;
}
/* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
+ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list);
/* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0, (*buf)->vb.size);
+ outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
+ memset(outp, 0, vb2_plane_size(&(*buf)->vb.vb2_buf, 0));
dev->vbi_mode.bulk_ctl.buf = *buf;
@@ -666,7 +619,7 @@ int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
if (buf == NULL)
return -EINVAL;
- p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+ p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
if (dma_q->bytes_left_in_line != _line_size) {
current_line_bytes_copied =