[media] cx23885: fix format/crop handling
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 30 Nov 2015 11:59:18 +0000 (09:59 -0200)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Fri, 18 Dec 2015 15:29:13 +0000 (13:29 -0200)
While testing the cx23885 driver with various TV standards I found
a number of bugs:

1) norm_maxw() returned 768 instead of 720 for PAL formats. This should
   always be 720, so drop this inline function and just always use 720.
2) cropcap() was missing, so the pixelaspect was never known and qv4l2 would
   scale the image incorrectly. Add cropcap support.
3) cx23885_set_tvnorm() should just return 0 if the same standard was
   set again. If another standard is set, then reset the width/height and
   call set_fmt for the subdevs.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885.h

index 63f302e063790ef1464154346875de0ea0f06690..ad4d7e683ba7717bdc5f9e798ae3b83d9cc408b1 100644 (file)
@@ -114,11 +114,19 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
 
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 {
+       struct v4l2_subdev_format format = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .format.code = MEDIA_BUS_FMT_FIXED,
+       };
+
        dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
                __func__,
                (unsigned int)norm,
                v4l2_norm_to_name(norm));
 
+       if (dev->tvnorm == norm)
+               return 0;
+
        if (dev->tvnorm != norm) {
                if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
                    vb2_is_busy(&dev->vb2_mpegq))
@@ -126,9 +134,17 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
        }
 
        dev->tvnorm = norm;
+       dev->width = 720;
+       dev->height = norm_maxh(norm);
+       dev->field = V4L2_FIELD_INTERLACED;
 
        call_all(dev, video, s_std, norm);
 
+       format.format.width = dev->width;
+       format.format.height = dev->height;
+       format.format.field = dev->field;
+       call_all(dev, pad, set_fmt, NULL, &format);
+
        return 0;
 }
 
@@ -545,7 +561,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
 
        field = f->fmt.pix.field;
-       maxw  = norm_maxw(dev->tvnorm);
+       maxw  = 720;
        maxh  = norm_maxh(dev->tvnorm);
 
        if (V4L2_FIELD_ANY == field) {
@@ -648,6 +664,26 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        return 0;
 }
 
+static int vidioc_cropcap(struct file *file, void *priv,
+                         struct v4l2_cropcap *cc)
+{
+       struct cx23885_dev *dev = video_drvdata(file);
+       bool is_50hz = dev->tvnorm & V4L2_STD_625_50;
+
+       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cc->bounds.left = 0;
+       cc->bounds.top = 0;
+       cc->bounds.width = 720;
+       cc->bounds.height = norm_maxh(dev->tvnorm);
+       cc->defrect = cc->bounds;
+       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+
+       return 0;
+}
+
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
        struct cx23885_dev *dev = video_drvdata(file);
@@ -1082,6 +1118,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
        .vidioc_streamon      = vb2_ioctl_streamon,
        .vidioc_streamoff     = vb2_ioctl_streamoff,
+       .vidioc_cropcap       = vidioc_cropcap,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_g_std         = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
index f9eb57b186fa3d907b5028f9b0b1f5d3b2636c39..9a8938b1085aa7e9a8f6fe847bb3c0d6a927c16b 100644 (file)
@@ -627,11 +627,6 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci,
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
 
-static inline unsigned int norm_maxw(v4l2_std_id norm)
-{
-       return (norm & V4L2_STD_525_60) ? 720 : 768;
-}
-
 static inline unsigned int norm_maxh(v4l2_std_id norm)
 {
        return (norm & V4L2_STD_525_60) ? 480 : 576;