summaryrefslogtreecommitdiff
path: root/drivers/media/usb/cx231xx/cx231xx-video.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/cx231xx/cx231xx-video.c')
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c1280
1 files changed, 506 insertions, 774 deletions
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 990626101718..2cd4e333bc4b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
cx231xx-video.c - driver for Conexant Cx23100/101/102
USB video capture devices
@@ -7,27 +8,14 @@
Based on cx23885 driver
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>
@@ -36,15 +24,14 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/tuner.h>
-#include "dvb_frontend.h"
+#include <media/dvb_frontend.h>
-#include "cx231xx.h"
#include "cx231xx-vbi.h"
-#define CX231XX_VERSION "0.0.2"
+#define CX231XX_VERSION "0.0.3"
#define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
#define DRIVER_DESC "Conexant cx231xx based USB video device driver"
@@ -71,10 +58,10 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(CX231XX_VERSION);
-static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
+static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
+static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
+static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U };
module_param_array(card, int, NULL, 0444);
module_param_array(video_nr, int, NULL, 0444);
@@ -93,7 +80,6 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
/* supported video standards */
static struct cx231xx_fmt format[] = {
{
- .name = "16bpp YUY2, 4:2:2, packed",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.reg = 0,
@@ -101,6 +87,73 @@ static struct cx231xx_fmt format[] = {
};
+static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *entity, *decoder = NULL, *source;
+ struct media_link *link, *found_link = NULL;
+ int ret, active_links = 0;
+
+ if (!mdev)
+ return 0;
+
+ /*
+ * This will find the tuner that is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be
+ * using an analog input instead of the tuner. However, as we can't
+ * do DVB streaming while the DMA engine is being used for V4L2,
+ * this should be enough for the actual needs.
+ */
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
+ decoder = entity;
+ break;
+ }
+ }
+ if (!decoder)
+ return 0;
+
+ list_for_each_entry(link, &decoder->links, list) {
+ if (link->sink->entity == decoder) {
+ found_link = link;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ break;
+ }
+ }
+
+ if (active_links == 1 || !found_link)
+ return 0;
+
+ source = found_link->source->entity;
+ list_for_each_entry(link, &source->links, list) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ sink = link->sink->entity;
+
+ if (sink == entity)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ dev_err(dev->dev,
+ "Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ } else
+ dev_dbg(dev->dev,
+ "link %s->%s was %s\n",
+ source->name, sink->name,
+ flags ? "ENABLED" : "disabled");
+ }
+#endif
+ return 0;
+}
+
/* ------------------------------------------------------------------
Video buffer and parser functions
------------------------------------------------------------------*/
@@ -113,18 +166,19 @@ static inline void buffer_filled(struct cx231xx *dev,
struct cx231xx_buffer *buf)
{
/* Advice that buffer was filled */
- cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- v4l2_get_timestamp(&buf->vb.ts);
+ cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.vb2_buf.index);
+ buf->vb.sequence = dma_q->sequence++;
+ buf->vb.field = V4L2_FIELD_INTERLACED;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, dev->size);
if (dev->USE_ISO)
dev->video_mode.isoc_ctl.buf = NULL;
else
dev->video_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);
}
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
@@ -133,10 +187,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)";
@@ -166,7 +220,7 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
}
/*
- * video-buf generic routine to get the next available buffer
+ * generic routine to get the next available buffer
*/
static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
struct cx231xx_buffer **buf)
@@ -188,11 +242,11 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
}
/* 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, dev->size);
if (dev->USE_ISO)
dev->video_mode.isoc_ctl.buf = *buf;
@@ -208,7 +262,7 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
- int i, rc = 1;
+ int i;
unsigned char *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
u8 sav_eav = 0;
@@ -299,13 +353,12 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
bytes_parsed = 0;
}
- return rc;
+ return 1;
}
static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
- int rc = 1;
unsigned char *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
u8 sav_eav = 0;
@@ -379,7 +432,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
bytes_parsed = 0;
}
- return rc;
+ return 1;
}
@@ -601,7 +654,7 @@ int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
if (buf == NULL)
return -1;
- p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+ p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
@@ -620,7 +673,7 @@ int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
bytes_to_copy : dma_q->bytes_left_in_line;
- if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size))
+ if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + dev->size))
return 0;
/* The below copies the UYVY data straight into video buffer */
@@ -656,145 +709,97 @@ u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
Videobuf operations
------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static int 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);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
- *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
- if (0 == *count)
- *count = CX231XX_DEF_BUF;
+ dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
- if (*count < CX231XX_MIN_BUF)
- *count = CX231XX_MIN_BUF;
+ if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF)
+ *nbuffers = CX231XX_MIN_BUF - q_num_bufs;
+
+ if (*nplanes)
+ return sizes[0] < dev->size ? -EINVAL : 0;
+ *nplanes = 1;
+ sizes[0] = dev->size;
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)
+static void buffer_queue(struct vb2_buffer *vb)
{
- 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.)
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb.vb2_buf);
+ struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+ unsigned long flags;
- 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->video_mode.slock, flags);
- if (dev->USE_ISO) {
- if (dev->video_mode.isoc_ctl.buf == buf)
- dev->video_mode.isoc_ctl.buf = NULL;
- } else {
- if (dev->video_mode.bulk_ctl.buf == buf)
- dev->video_mode.bulk_ctl.buf = NULL;
- }
+ list_add_tail(&buf->list, &vidq->active);
spin_unlock_irqrestore(&dev->video_mode.slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static void return_all_buffers(struct cx231xx *dev,
+ enum vb2_buffer_state state)
{
- 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;
-
- /* The only currently supported format is 16 bits/pixel */
- buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
- + 7) >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
+ struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+ struct cx231xx_buffer *buf, *node;
+ unsigned long flags;
- if (dev->USE_ISO) {
- if (!dev->video_mode.isoc_ctl.num_bufs)
- urb_init = 1;
- } else {
- if (!dev->video_mode.bulk_ctl.num_bufs)
- urb_init = 1;
- }
- /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
- urb_init, dev->video_mode.max_pkt_size);*/
- if (urb_init) {
- dev->mode_tv = 0;
- if (dev->USE_ISO)
- rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_isoc_copy);
- else
- rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_bulk_copy);
- if (rc < 0)
- goto fail;
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ else
+ dev->video_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);
}
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);
}
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = vb2_get_drv_priv(vq);
struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+ int ret = 0;
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
+ vidq->sequence = 0;
+ dev->mode_tv = 0;
+ cx231xx_enable_analog_tuner(dev);
+ if (dev->USE_ISO)
+ ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ else
+ ret = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ if (ret)
+ return_all_buffers(dev, VB2_BUF_STATE_QUEUED);
+ call_all(dev, video, s_stream, 1);
+ return ret;
}
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static void stop_streaming(struct vb2_queue *vq)
{
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = (struct cx231xx *)fh->dev;
-
- cx231xx_isocdbg("cx231xx: called buffer_release\n");
+ struct cx231xx *dev = vb2_get_drv_priv(vq);
- free_buffer(vq, buf);
+ call_all(dev, video, s_stream, 0);
+ return_all_buffers(dev, VB2_BUF_STATE_ERROR);
}
-static struct videobuf_queue_ops cx231xx_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
+static const struct vb2_ops cx231xx_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
};
/********************* v4l2 interface **************************************/
@@ -810,64 +815,12 @@ void video_mux(struct cx231xx *dev, int index)
cx231xx_set_audio_input(dev, dev->ctl_ainput);
- cx231xx_info("video_mux : %d\n", index);
+ dev_dbg(dev->dev, "video_mux : %d\n", index);
/* do mode control overrides if required */
cx231xx_do_mode_ctrl_overrides(dev);
}
-/* Usage lock check functions */
-static int res_get(struct cx231xx_fh *fh)
-{
- struct cx231xx *dev = fh->dev;
- int rc = 0;
-
- /* This instance already has stream_on */
- if (fh->stream_on)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (dev->stream_on)
- return -EBUSY;
- dev->stream_on = 1;
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (dev->vbi_stream_on)
- return -EBUSY;
- dev->vbi_stream_on = 1;
- } else
- return -EINVAL;
-
- fh->stream_on = 1;
-
- return rc;
-}
-
-static int res_check(struct cx231xx_fh *fh)
-{
- return fh->stream_on;
-}
-
-static void res_free(struct cx231xx_fh *fh)
-{
- struct cx231xx *dev = fh->dev;
-
- fh->stream_on = 0;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- dev->stream_on = 0;
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- dev->vbi_stream_on = 0;
-}
-
-static int check_dev(struct cx231xx *dev)
-{
- if (dev->state & DEV_DISCONNECTED) {
- cx231xx_errdev("v4l2 ioctl: device not present\n");
- return -ENODEV;
- }
- return 0;
-}
-
/* ------------------------------------------------------------------
IOCTL vidioc handling
------------------------------------------------------------------*/
@@ -875,8 +828,7 @@ static int check_dev(struct cx231xx *dev)
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
@@ -886,7 +838,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -905,8 +856,7 @@ static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
unsigned int width = f->fmt.pix.width;
unsigned int height = f->fmt.pix.height;
unsigned int maxw = norm_maxw(dev);
@@ -931,7 +881,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -939,48 +888,36 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int rc;
- struct cx231xx_fmt *fmt;
- struct v4l2_mbus_framefmt mbus_fmt;
- rc = check_dev(dev);
- if (rc < 0)
+ rc = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (rc)
return rc;
- vidioc_try_fmt_vid_cap(file, priv, f);
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt)
- return -EINVAL;
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- cx231xx_errdev("%s queue busy\n", __func__);
- return -EBUSY;
- }
-
- if (dev->stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
+ if (vb2_is_busy(&dev->vidq)) {
+ dev_err(dev->dev, "%s: queue busy\n", __func__);
return -EBUSY;
}
/* set new image size */
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
- dev->format = fmt;
+ dev->format = format_by_fourcc(f->fmt.pix.pixelformat);
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
- call_all(dev, video, s_mbus_fmt, &mbus_fmt);
- v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+ v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
+ call_all(dev, pad, set_fmt, NULL, &format);
+ v4l2_fill_pix_format(&f->fmt.pix, &format.format);
return rc;
}
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
*id = dev->norm;
return 0;
@@ -988,19 +925,15 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct v4l2_mbus_framefmt mbus_fmt;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ struct cx231xx *dev = video_drvdata(file);
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
if (dev->norm == norm)
return 0;
- if (videobuf_queue_is_busy(&fh->vb_vidq))
+ if (vb2_is_busy(&dev->vidq))
return -EBUSY;
dev->norm = norm;
@@ -1009,16 +942,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
dev->width = 720;
dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
/* We need to reset basic properties in the decoder related to
resolution (since a standard change effects things like the number
of lines in VACT, etc) */
- memset(&mbus_fmt, 0, sizeof(mbus_fmt));
- mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
- mbus_fmt.width = dev->width;
- mbus_fmt.height = dev->height;
- call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ format.format.code = MEDIA_BUS_FMT_FIXED;
+ format.format.width = dev->width;
+ format.format.height = dev->height;
+ call_all(dev, pad, set_fmt, NULL, &format);
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
@@ -1032,16 +964,61 @@ static const char *iname[] = {
[CX231XX_VMUX_TELEVISION] = "Television",
[CX231XX_VMUX_CABLE] = "Cable TV",
[CX231XX_VMUX_DVB] = "DVB",
- [CX231XX_VMUX_DEBUG] = "for debug only",
};
+void cx231xx_v4l2_create_entities(struct cx231xx *dev)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ int ret, i;
+
+ /* Create entities for each input connector */
+ for (i = 0; i < MAX_CX231XX_INPUT; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+
+ if (!INPUT(i)->type)
+ break;
+
+ ent->name = iname[INPUT(i)->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ switch (INPUT(i)->type) {
+ case CX231XX_VMUX_COMPOSITE1:
+ ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case CX231XX_VMUX_SVIDEO:
+ ent->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ case CX231XX_VMUX_TELEVISION:
+ case CX231XX_VMUX_CABLE:
+ case CX231XX_VMUX_DVB:
+ /* The DVB core will handle it */
+ if (dev->tuner_type == TUNER_ABSENT)
+ continue;
+ fallthrough;
+ default: /* just to shut up a gcc warning */
+ ent->function = MEDIA_ENT_F_CONN_RF;
+ break;
+ }
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+#endif
+}
+
int cx231xx_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
u32 gen_stat;
- unsigned int ret, n;
+ unsigned int n;
+ int ret;
n = i->index;
if (n >= MAX_CX231XX_INPUT)
@@ -1052,13 +1029,13 @@ int cx231xx_enum_input(struct file *file, void *priv,
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n)->type]);
+ strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
(CX231XX_VMUX_CABLE == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
- i->std = dev->vdev->tvnorms;
+ i->std = dev->vdev.tvnorms;
/* If they are asking about the active input, read signal status */
if (n == dev->video_input) {
@@ -1077,8 +1054,7 @@ int cx231xx_enum_input(struct file *file, void *priv,
int cx231xx_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
*i = dev->video_input;
@@ -1087,14 +1063,9 @@ int cx231xx_g_input(struct file *file, void *priv, unsigned int *i)
int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
+ struct cx231xx *dev = video_drvdata(file);
dev->mode_tv = 0;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (i >= MAX_CX231XX_INPUT)
return -EINVAL;
@@ -1108,7 +1079,7 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
/* There's a tuner, so reset the standard and put it on the
last known frequency (since it was probably powered down
until now */
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
}
return 0;
@@ -1116,18 +1087,12 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ struct cx231xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Tuner");
+ strscpy(t->name, "Tuner", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM;
@@ -1140,27 +1105,15 @@ int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
if (0 != t->index)
return -EINVAL;
-#if 0
- call_all(dev, tuner, s_tuner, t);
-#endif
return 0;
}
int cx231xx_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
if (f->tuner)
return -EINVAL;
@@ -1173,19 +1126,14 @@ int cx231xx_g_frequency(struct file *file, void *priv,
int cx231xx_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
struct v4l2_frequency new_freq = *f;
- int rc;
+ int rc, need_if_freq = 0;
u32 if_frequency = 5400000;
- cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
- f->frequency, f->type);
- /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ dev_dbg(dev->dev,
+ "Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
+ f->frequency, f->type);
if (0 != f->tuner)
return -EINVAL;
@@ -1193,14 +1141,30 @@ int cx231xx_s_frequency(struct file *file, void *priv,
/* set pre channel change settings in DIF first */
rc = cx231xx_tuner_pre_channel_change(dev);
- call_all(dev, tuner, s_frequency, f);
- call_all(dev, tuner, g_frequency, &new_freq);
- dev->ctl_freq = new_freq.frequency;
+ switch (dev->model) { /* i2c device tuners */
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
+ case CX231XX_BOARD_HAUPPAUGE_975:
+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
+ if (dev->cx231xx_set_analog_freq)
+ dev->cx231xx_set_analog_freq(dev, f->frequency);
+ dev->ctl_freq = f->frequency;
+ need_if_freq = 1;
+ break;
+ default:
+ call_all(dev, tuner, s_frequency, f);
+ call_all(dev, tuner, g_frequency, &new_freq);
+ dev->ctl_freq = new_freq.frequency;
+ break;
+ }
+
+ pr_debug("%s() %u : %u\n", __func__, f->frequency, dev->ctl_freq);
/* set post channel change settings in DIF first */
rc = cx231xx_tuner_post_channel_change(dev);
- if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ if (need_if_freq || dev->tuner_type == TUNER_NXP_TDA18271) {
if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
if_frequency = 5400000; /*5.4MHz */
else if (dev->norm & V4L2_STD_B)
@@ -1216,13 +1180,14 @@ int cx231xx_s_frequency(struct file *file, void *priv,
else if (dev->norm & V4L2_STD_SECAM_LC)
if_frequency = 1250000; /*1.25MHz */
- cx231xx_info("if_frequency is set to %d\n", if_frequency);
+ dev_dbg(dev->dev,
+ "if_frequency is set to %d\n", if_frequency);
cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
update_HH_register_after_set_DIF(dev);
}
- cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
+ dev_dbg(dev->dev, "Set New FREQUENCY to %d\n", f->frequency);
return rc;
}
@@ -1236,22 +1201,22 @@ int cx231xx_g_chip_info(struct file *file, void *fh,
case 0: /* Cx231xx - internal registers */
return 0;
case 1: /* AFE - read byte */
- strlcpy(chip->name, "AFE (byte)", sizeof(chip->name));
+ strscpy(chip->name, "AFE (byte)", sizeof(chip->name));
return 0;
case 2: /* Video Block - read byte */
- strlcpy(chip->name, "Video (byte)", sizeof(chip->name));
+ strscpy(chip->name, "Video (byte)", sizeof(chip->name));
return 0;
case 3: /* I2S block - read byte */
- strlcpy(chip->name, "I2S (byte)", sizeof(chip->name));
+ strscpy(chip->name, "I2S (byte)", sizeof(chip->name));
return 0;
case 4: /* AFE - read dword */
- strlcpy(chip->name, "AFE (dword)", sizeof(chip->name));
+ strscpy(chip->name, "AFE (dword)", sizeof(chip->name));
return 0;
case 5: /* Video Block - read dword */
- strlcpy(chip->name, "Video (dword)", sizeof(chip->name));
+ strscpy(chip->name, "Video (dword)", sizeof(chip->name));
return 0;
case 6: /* I2S Block - read dword */
- strlcpy(chip->name, "I2S (dword)", sizeof(chip->name));
+ strscpy(chip->name, "I2S (dword)", sizeof(chip->name));
return 0;
}
return -EINVAL;
@@ -1260,8 +1225,7 @@ int cx231xx_g_chip_info(struct file *file, void *fh,
int cx231xx_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
int ret;
u8 value[4] = { 0, 0, 0, 0 };
u32 data = 0;
@@ -1271,7 +1235,7 @@ int cx231xx_g_register(struct file *file, void *priv,
ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
(u16)reg->reg, value, 4);
reg->val = value[0] | value[1] << 8 |
- value[2] << 16 | value[3] << 24;
+ value[2] << 16 | (u32)value[3] << 24;
reg->size = 4;
break;
case 1: /* AFE - read byte */
@@ -1319,8 +1283,7 @@ int cx231xx_g_register(struct file *file, void *priv,
int cx231xx_s_register(struct file *file, void *priv,
const struct v4l2_dbg_register *reg)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
int ret;
u8 data[4] = { 0, 0, 0, 0 };
@@ -1364,97 +1327,70 @@ int cx231xx_s_register(struct file *file, void *priv,
}
#endif
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cc)
+static int vidioc_g_pixelaspect(struct file *file, void *priv,
+ int type, struct v4l2_fract *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
+ bool is_50hz = dev->norm & V4L2_STD_625_50;
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
- cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
+ f->numerator = is_50hz ? 54 : 11;
+ f->denominator = is_50hz ? 59 : 10;
return 0;
}
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
+static int vidioc_g_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- rc = res_get(fh);
+ struct cx231xx *dev = video_drvdata(file);
- if (likely(rc >= 0))
- rc = videobuf_streamon(&fh->vb_vidq);
-
- call_all(dev, video, s_stream, 1);
-
- return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (type != fh->type)
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- cx25840_call(dev, video, s_stream, 0);
-
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
-
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = dev->width;
+ s->r.height = dev->height;
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
int cx231xx_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
- strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
- strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+ strscpy(cap->driver, "cx231xx", sizeof(cap->driver));
+ strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- if (vdev->vfl_type == VFL_TYPE_RADIO)
- cap->device_caps = V4L2_CAP_RADIO;
- else {
- cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- if (vdev->vfl_type == VFL_TYPE_VBI)
- cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
- else
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- }
- if (dev->tuner_type != TUNER_ABSENT)
- cap->device_caps |= V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE |
+ cap->capabilities = V4L2_CAP_READWRITE |
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- if (dev->radio_dev)
+ if (video_is_registered(&dev->radio_dev))
cap->capabilities |= V4L2_CAP_RADIO;
+ switch (dev->model) {
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
+ case CX231XX_BOARD_HAUPPAUGE_975:
+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
+ cap->capabilities |= V4L2_CAP_TUNER;
+ break;
+ default:
+ if (dev->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ break;
+ }
return 0;
}
@@ -1464,7 +1400,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
f->pixelformat = format[f->index].fourcc;
return 0;
@@ -1475,8 +1410,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
@@ -1498,8 +1432,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(file);
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
@@ -1522,81 +1455,21 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- if (dev->vbi_stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
- return -EBUSY;
- }
return vidioc_try_fmt_vbi_cap(file, priv, f);
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_reqbufs(&fh->vb_vidq, rb);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_querybuf(&fh->vb_vidq, b);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_qbuf(&fh->vb_vidq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
-}
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+ struct cx231xx *dev = video_drvdata(file);
if (t->index)
return -EINVAL;
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
call_all(dev, tuner, g_tuner, t);
@@ -1604,7 +1477,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
}
static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+ struct cx231xx *dev = video_drvdata(file);
if (t->index)
return -EINVAL;
@@ -1620,52 +1493,20 @@ static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner
*/
static int cx231xx_v4l2_open(struct file *filp)
{
- int errCode = 0, radio = 0;
struct video_device *vdev = video_devdata(filp);
struct cx231xx *dev = video_drvdata(filp);
- struct cx231xx_fh *fh;
- enum v4l2_buf_type fh_type = 0;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- cx231xx_videodbg("open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[fh_type],
- dev->users);
-
-#if 0
- errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
- if (errCode < 0) {
- cx231xx_errdev
- ("Device locked on digital mode. Can't open analog\n");
- return -EBUSY;
- }
-#endif
+ int ret;
- fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
- if (!fh) {
- cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
- return -ENOMEM;
- }
- if (mutex_lock_interruptible(&dev->lock)) {
- kfree(fh);
+ if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
+
+ ret = v4l2_fh_open(filp);
+ if (ret) {
+ mutex_unlock(&dev->lock);
+ return ret;
}
- fh->dev = dev;
- fh->type = fh_type;
- filp->private_data = fh;
- v4l2_fh_init(&fh->fh, vdev);
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (dev->users++ == 0) {
/* Power up in Analog TV mode */
if (dev->board.external_av)
cx231xx_set_power_mode(dev,
@@ -1673,10 +1514,6 @@ static int cx231xx_v4l2_open(struct file *filp)
else
cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
-#if 0
- cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
-#endif
-
/* set video alternate setting */
cx231xx_set_video_alternate(dev);
@@ -1686,79 +1523,49 @@ static int cx231xx_v4l2_open(struct file *filp)
/* device needs to be initialized before isoc transfer */
dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
-
}
- if (radio) {
+
+ if (vdev->vfl_type == VFL_TYPE_RADIO) {
cx231xx_videodbg("video_open: setting radio device\n");
/* cx231xx_start_radio(dev); */
call_all(dev, tuner, s_radio);
}
-
- dev->users++;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
- NULL, &dev->video_mode.slock,
- fh->type, V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer),
- fh, &dev->lock);
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
/* Set the required alternate setting VBI interface works in
Bulk mode only */
cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
-
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
- NULL, &dev->vbi_mode.slock,
- fh->type, V4L2_FIELD_SEQ_TB,
- sizeof(struct cx231xx_buffer),
- fh, &dev->lock);
}
mutex_unlock(&dev->lock);
- v4l2_fh_add(&fh->fh);
-
- return errCode;
+ return 0;
}
/*
* cx231xx_realease_resources()
* unregisters the v4l2,i2c and usb devices
- * called when the device gets disconected or at module unload
+ * called when the device gets disconnected or at module unload
*/
void cx231xx_release_analog_resources(struct cx231xx *dev)
{
/*FIXME: I2C IR should be disconnected */
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
- if (dev->vbi_dev) {
- cx231xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
+ if (video_is_registered(&dev->radio_dev))
+ video_unregister_device(&dev->radio_dev);
+ if (video_is_registered(&dev->vbi_dev)) {
+ dev_info(dev->dev, "V4L2 device %s deregistered\n",
+ video_device_node_name(&dev->vbi_dev));
+ video_unregister_device(&dev->vbi_dev);
}
- if (dev->vdev) {
- cx231xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
+ if (video_is_registered(&dev->vdev)) {
+ dev_info(dev->dev, "V4L2 device %s deregistered\n",
+ video_device_node_name(&dev->vdev));
if (dev->board.has_417)
cx231xx_417_unregister(dev);
- if (video_is_registered(dev->vdev))
- video_unregister_device(dev->vdev);
- else
- video_device_release(dev->vdev);
- dev->vdev = NULL;
+ video_unregister_device(&dev->vdev);
}
v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
@@ -1771,14 +1578,22 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
*/
static int cx231xx_close(struct file *filp)
{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(filp);
+ struct video_device *vdev = video_devdata(filp);
- cx231xx_videodbg("users=%d\n", dev->users);
+ _vb2_fop_release(filp, NULL);
- cx231xx_videodbg("users=%d\n", dev->users);
- if (res_check(fh))
- res_free(fh);
+ if (--dev->users == 0) {
+ /* Save some power by putting tuner to sleep */
+ call_all(dev, tuner, standby);
+
+ /* do this before setting alternate! */
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ }
/*
* To workaround error number=-71 on EP0 for VideoGrabber,
@@ -1786,76 +1601,32 @@ static int cx231xx_close(struct file *filp)
* FIXME: It is probably safe to remove most of these, as we're
* now avoiding the alternate setting for INDEX_VANC
*/
- if (!dev->board.no_alt_vanc)
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
- if (atomic_read(&dev->devlist_count) > 0) {
- cx231xx_release_resources(dev);
- fh->dev = NULL;
- return 0;
- }
- return 0;
- }
-
- /* do this before setting alternate! */
- cx231xx_uninit_vbi_isoc(dev);
-
- /* set alternate 0 */
- if (!dev->vbi_or_sliced_cc_mode)
- cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
- else
- cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
-
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- kfree(fh);
- dev->users--;
- wake_up_interruptible_nr(&dev->open, 1);
- return 0;
- }
-
- v4l2_fh_del(&fh->fh);
- dev->users--;
- if (!dev->users) {
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
- cx231xx_release_resources(dev);
- fh->dev = NULL;
- return 0;
- }
-
- /* Save some power by putting tuner to sleep */
- call_all(dev, core, s_power, 0);
-
+ if (!dev->board.no_alt_vanc && vdev->vfl_type == VFL_TYPE_VBI) {
/* do this before setting alternate! */
- if (dev->USE_ISO)
- cx231xx_uninit_isoc(dev);
+ cx231xx_uninit_vbi_isoc(dev);
+
+ /* set alternate 0 */
+ if (!dev->vbi_or_sliced_cc_mode)
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
else
- cx231xx_uninit_bulk(dev);
- cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+ wake_up_interruptible_nr(&dev->open, 1);
+ return 0;
+ }
+
+ if (dev->users == 0) {
/* set alternate 0 */
cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
}
- v4l2_fh_exit(&fh->fh);
- kfree(fh);
- wake_up_interruptible_nr(&dev->open, 1);
+
+ wake_up_interruptible(&dev->open);
return 0;
}
static int cx231xx_v4l2_close(struct file *filp)
{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
+ struct cx231xx *dev = video_drvdata(filp);
int rc;
mutex_lock(&dev->lock);
@@ -1864,116 +1635,13 @@ static int cx231xx_v4l2_close(struct file *filp)
return rc;
}
-/*
- * cx231xx_v4l2_read()
- * will allocate buffers when called for the first time
- */
-static ssize_t
-cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
- loff_t *pos)
-{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
- rc = res_get(fh);
-
- if (unlikely(rc < 0))
- return rc;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- mutex_unlock(&dev->lock);
- return rc;
- }
- return 0;
-}
-
-/*
- * cx231xx_v4l2_poll()
- * will allocate buffers when called for the first time
- */
-static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
-{
- unsigned long req_events = poll_requested_events(wait);
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
- unsigned res = 0;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return POLLERR;
-
- rc = res_get(fh);
-
- if (unlikely(rc < 0))
- return POLLERR;
-
- if (v4l2_event_pending(&fh->fh))
- res |= POLLPRI;
- else
- poll_wait(filp, &fh->fh.wait, wait);
-
- if (!(req_events & (POLLIN | POLLRDNORM)))
- return res;
-
- if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
- (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) {
- mutex_lock(&dev->lock);
- res |= videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- mutex_unlock(&dev->lock);
- return res;
- }
- return res | POLLERR;
-}
-
-/*
- * cx231xx_v4l2_mmap()
- */
-static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- rc = res_get(fh);
-
- if (unlikely(rc < 0))
- return rc;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- mutex_unlock(&dev->lock);
-
- cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end -
- (unsigned long)vma->vm_start, rc);
-
- return rc;
-}
-
static const struct v4l2_file_operations cx231xx_v4l_fops = {
.owner = THIS_MODULE,
.open = cx231xx_v4l2_open,
.release = cx231xx_v4l2_close,
- .read = cx231xx_v4l2_read,
- .poll = cx231xx_v4l2_poll,
- .mmap = cx231xx_v4l2_mmap,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
@@ -1986,18 +1654,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
- .vidioc_cropcap = vidioc_cropcap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_pixelaspect = vidioc_g_pixelaspect,
+ .vidioc_g_selection = vidioc_g_selection,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = cx231xx_enum_input,
.vidioc_g_input = cx231xx_g_input,
.vidioc_s_input = cx231xx_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = cx231xx_g_tuner,
.vidioc_s_tuner = cx231xx_s_tuner,
.vidioc_g_frequency = cx231xx_g_frequency,
@@ -2015,7 +1684,7 @@ static struct video_device cx231xx_vbi_template;
static const struct video_device cx231xx_video_template = {
.fops = &cx231xx_v4l_fops,
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
};
@@ -2051,41 +1720,43 @@ static struct video_device cx231xx_radio_template = {
/******************************** usb interface ******************************/
-static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
- const struct video_device
- *template, const char *type_name)
+static void cx231xx_vdev_init(struct cx231xx *dev,
+ struct video_device *vfd,
+ const struct video_device *template,
+ const char *type_name)
{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
- vfd->debug = video_debug;
+ vfd->release = video_device_release_empty;
vfd->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
video_set_drvdata(vfd, dev);
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
- v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ switch (dev->model) {
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
+ case CX231XX_BOARD_HAUPPAUGE_975:
+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
+ break;
+ default:
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ break;
+ }
}
- return vfd;
}
int cx231xx_register_analog_devices(struct cx231xx *dev)
{
+ struct vb2_queue *q;
int ret;
- cx231xx_info("%s: v4l2 driver version %s\n",
- dev->name, CX231XX_VERSION);
+ dev_info(dev->dev, "v4l2 driver version %s\n", CX231XX_VERSION);
/* set default norm */
dev->norm = V4L2_STD_PAL;
@@ -2099,17 +1770,17 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Set the initial input */
video_mux(dev, dev->video_input);
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
if (dev->sd_cx25840) {
v4l2_ctrl_add_handler(&dev->ctrl_handler,
- dev->sd_cx25840->ctrl_handler, NULL);
+ dev->sd_cx25840->ctrl_handler, NULL, true);
v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
dev->sd_cx25840->ctrl_handler,
- v4l2_ctrl_radio_filter);
+ v4l2_ctrl_radio_filter, true);
}
if (dev->ctrl_handler.error)
@@ -2121,69 +1792,130 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* write code here... */
/* allocate and fill video video_device struct */
- dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
- if (!dev->vdev) {
- cx231xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
+ cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video");
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ dev->video_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
+ if (ret < 0)
+ dev_err(dev->dev, "failed to initialize video media entity!\n");
+#endif
+ dev->vdev.ctrl_handler = &dev->ctrl_handler;
+
+ q = &dev->vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx231xx_buffer);
+ q->ops = &cx231xx_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_queued_buffers = 1;
+ q->lock = &dev->lock;
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+ dev->vdev.queue = q;
+ dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+
+ switch (dev->model) { /* i2c device tuners */
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
+ case CX231XX_BOARD_HAUPPAUGE_975:
+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
+ dev->vdev.device_caps |= V4L2_CAP_TUNER;
+ break;
+ default:
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->vdev.device_caps |= V4L2_CAP_TUNER;
+ break;
}
- dev->vdev->ctrl_handler = &dev->ctrl_handler;
/* register v4l2 video video_device */
- ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO,
video_nr[dev->devno]);
if (ret) {
- cx231xx_errdev("unable to register video device (error=%i).\n",
- ret);
+ dev_err(dev->dev,
+ "unable to register video device (error=%i).\n",
+ ret);
return ret;
}
- cx231xx_info("%s/0: registered device %s [v4l2]\n",
- dev->name, video_device_node_name(dev->vdev));
+ dev_info(dev->dev, "Registered video device %s [v4l2]\n",
+ video_device_node_name(&dev->vdev));
/* Initialize VBI template */
cx231xx_vbi_template = cx231xx_video_template;
- strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
+ strscpy(cx231xx_vbi_template.name, "cx231xx-vbi",
+ sizeof(cx231xx_vbi_template.name));
/* Allocate and fill vbi video_device struct */
- dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+ cx231xx_vdev_init(dev, &dev->vbi_dev, &cx231xx_vbi_template, "vbi");
- if (!dev->vbi_dev) {
- cx231xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
+ if (ret < 0)
+ dev_err(dev->dev, "failed to initialize vbi media entity!\n");
+#endif
+ dev->vbi_dev.ctrl_handler = &dev->ctrl_handler;
+
+ q = &dev->vbiq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx231xx_buffer);
+ q->ops = &cx231xx_vbi_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_queued_buffers = 1;
+ q->lock = &dev->lock;
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+ dev->vbi_dev.queue = q;
+ dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ switch (dev->model) { /* i2c device tuners */
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
+ case CX231XX_BOARD_HAUPPAUGE_975:
+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
+ dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
+ break;
+ default:
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
}
- dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
+
/* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
- cx231xx_errdev("unable to register vbi device\n");
+ dev_err(dev->dev, "unable to register vbi device\n");
return ret;
}
- cx231xx_info("%s/0: registered device %s\n",
- dev->name, video_device_node_name(dev->vbi_dev));
+ dev_info(dev->dev, "Registered VBI device %s\n",
+ video_device_node_name(&dev->vbi_dev));
if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
- dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
- "radio");
- if (!dev->radio_dev) {
- cx231xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
- }
- dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ cx231xx_vdev_init(dev, &dev->radio_dev,
+ &cx231xx_radio_template, "radio");
+ dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
+ dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
- cx231xx_errdev("can't register radio device\n");
+ dev_err(dev->dev,
+ "can't register radio device\n");
return ret;
}
- cx231xx_info("Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
+ dev_info(dev->dev, "Registered radio device as %s\n",
+ video_device_node_name(&dev->radio_dev));
}
- cx231xx_info("V4L2 device registered as %s and %s\n",
- video_device_node_name(dev->vdev),
- video_device_node_name(dev->vbi_dev));
-
return 0;
}