c1686f55cd68f6581961909f58a1a0a2b6fc8a21
[oweals/openwrt.git] /
1 From 7c876909bc0a6d23124689d5fca89657a4fcb5a5 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Tue, 5 Mar 2019 15:43:27 +0000
4 Subject: [PATCH] media: bcm2835-unicam: Add support for enum
5  framesizes and frameintervals
6
7 vidioc_enum_framesizes and vidioc_enum_frameintervals weren't implemented,
8 therefore clients couldn't enumerate the supported resolutions.
9
10 Implement them by forwarding on to the sensor driver.
11
12 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
13 ---
14  .../media/platform/bcm2835/bcm2835-unicam.c   | 94 +++++++++++++++++++
15  1 file changed, 94 insertions(+)
16
17 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
18 +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
19 @@ -1406,6 +1406,84 @@ static int unicam_g_edid(struct file *fi
20         return v4l2_subdev_call(dev->sensor, pad, get_edid, edid);
21  }
22  
23 +static int unicam_enum_framesizes(struct file *file, void *priv,
24 +                                 struct v4l2_frmsizeenum *fsize)
25 +{
26 +       struct unicam_device *dev = video_drvdata(file);
27 +       const struct unicam_fmt *fmt;
28 +       struct v4l2_subdev_frame_size_enum fse;
29 +       int ret;
30 +
31 +       /* check for valid format */
32 +       fmt = find_format_by_pix(dev, fsize->pixel_format);
33 +       if (!fmt) {
34 +               unicam_dbg(3, dev, "Invalid pixel code: %x\n",
35 +                          fsize->pixel_format);
36 +               return -EINVAL;
37 +       }
38 +
39 +       fse.index = fsize->index;
40 +       fse.pad = 0;
41 +       fse.code = fmt->code;
42 +
43 +       ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse);
44 +       if (ret)
45 +               return ret;
46 +
47 +       unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
48 +                  __func__, fse.index, fse.code, fse.min_width, fse.max_width,
49 +                  fse.min_height, fse.max_height);
50 +
51 +       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
52 +       fsize->discrete.width = fse.max_width;
53 +       fsize->discrete.height = fse.max_height;
54 +
55 +       return 0;
56 +}
57 +
58 +static int unicam_enum_frameintervals(struct file *file, void *priv,
59 +                                     struct v4l2_frmivalenum *fival)
60 +{
61 +       struct unicam_device *dev = video_drvdata(file);
62 +       const struct unicam_fmt *fmt;
63 +       struct v4l2_subdev_frame_interval_enum fie = {
64 +               .index = fival->index,
65 +               .width = fival->width,
66 +               .height = fival->height,
67 +               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
68 +       };
69 +       int ret;
70 +
71 +       fmt = find_format_by_pix(dev, fival->pixel_format);
72 +       if (!fmt)
73 +               return -EINVAL;
74 +
75 +       fie.code = fmt->code;
76 +       ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval,
77 +                              NULL, &fie);
78 +       if (ret)
79 +               return ret;
80 +
81 +       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
82 +       fival->discrete = fie.interval;
83 +
84 +       return 0;
85 +}
86 +
87 +static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
88 +{
89 +       struct unicam_device *dev = video_drvdata(file);
90 +
91 +       return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a);
92 +}
93 +
94 +static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
95 +{
96 +       struct unicam_device *dev = video_drvdata(file);
97 +
98 +       return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a);
99 +}
100 +
101  static int unicam_g_dv_timings(struct file *file, void *priv,
102                                struct v4l2_dv_timings *timings)
103  {
104 @@ -1613,6 +1691,12 @@ static const struct v4l2_ioctl_ops unica
105         .vidioc_g_edid                  = unicam_g_edid,
106         .vidioc_s_edid                  = unicam_s_edid,
107  
108 +       .vidioc_enum_framesizes         = unicam_enum_framesizes,
109 +       .vidioc_enum_frameintervals     = unicam_enum_frameintervals,
110 +
111 +       .vidioc_g_parm                  = unicam_g_parm,
112 +       .vidioc_s_parm                  = unicam_s_parm,
113 +
114         .vidioc_s_dv_timings            = unicam_s_dv_timings,
115         .vidioc_g_dv_timings            = unicam_g_dv_timings,
116         .vidioc_query_dv_timings        = unicam_query_dv_timings,
117 @@ -1850,6 +1934,16 @@ static int unicam_probe_complete(struct
118                 v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_DV_TIMINGS);
119                 v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERY_DV_TIMINGS);
120         }
121 +       if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
122 +               v4l2_disable_ioctl(&unicam->video_dev,
123 +                                  VIDIOC_ENUM_FRAMEINTERVALS);
124 +       if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
125 +               v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_PARM);
126 +       if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
127 +               v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_PARM);
128 +
129 +       if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
130 +               v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_FRAMESIZES);
131  
132         ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev);
133         if (ret) {