Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * V4L2 sub-device
4 : : *
5 : : * Copyright (C) 2010 Nokia Corporation
6 : : *
7 : : * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
8 : : * Sakari Ailus <sakari.ailus@iki.fi>
9 : : */
10 : :
11 : : #include <linux/ioctl.h>
12 : : #include <linux/mm.h>
13 : : #include <linux/module.h>
14 : : #include <linux/slab.h>
15 : : #include <linux/types.h>
16 : : #include <linux/videodev2.h>
17 : : #include <linux/export.h>
18 : :
19 : : #include <media/v4l2-ctrls.h>
20 : : #include <media/v4l2-device.h>
21 : : #include <media/v4l2-ioctl.h>
22 : : #include <media/v4l2-fh.h>
23 : : #include <media/v4l2-event.h>
24 : :
25 : : static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
26 : : {
27 : : #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
28 [ # # ]: 0 : if (sd->entity.num_pads) {
29 : 0 : fh->pad = v4l2_subdev_alloc_pad_config(sd);
30 [ # # ]: 0 : if (fh->pad == NULL)
31 : : return -ENOMEM;
32 : : }
33 : : #endif
34 : : return 0;
35 : : }
36 : :
37 : : static void subdev_fh_free(struct v4l2_subdev_fh *fh)
38 : : {
39 : : #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
40 : 0 : v4l2_subdev_free_pad_config(fh->pad);
41 : 0 : fh->pad = NULL;
42 : : #endif
43 : : }
44 : :
45 : 0 : static int subdev_open(struct file *file)
46 : : {
47 : 0 : struct video_device *vdev = video_devdata(file);
48 : : struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
49 : : struct v4l2_subdev_fh *subdev_fh;
50 : : int ret;
51 : :
52 : 0 : subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
53 [ # # ]: 0 : if (subdev_fh == NULL)
54 : : return -ENOMEM;
55 : :
56 : : ret = subdev_fh_init(subdev_fh, sd);
57 [ # # ]: 0 : if (ret) {
58 : 0 : kfree(subdev_fh);
59 : 0 : return ret;
60 : : }
61 : :
62 : 0 : v4l2_fh_init(&subdev_fh->vfh, vdev);
63 : 0 : v4l2_fh_add(&subdev_fh->vfh);
64 : 0 : file->private_data = &subdev_fh->vfh;
65 : : #if defined(CONFIG_MEDIA_CONTROLLER)
66 [ # # # # ]: 0 : if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) {
67 : : struct module *owner;
68 : :
69 : 0 : owner = sd->entity.graph_obj.mdev->dev->driver->owner;
70 [ # # ]: 0 : if (!try_module_get(owner)) {
71 : : ret = -EBUSY;
72 : : goto err;
73 : : }
74 : 0 : subdev_fh->owner = owner;
75 : : }
76 : : #endif
77 : :
78 [ # # # # ]: 0 : if (sd->internal_ops && sd->internal_ops->open) {
79 : 0 : ret = sd->internal_ops->open(sd, subdev_fh);
80 [ # # ]: 0 : if (ret < 0)
81 : : goto err;
82 : : }
83 : :
84 : : return 0;
85 : :
86 : : err:
87 : 0 : module_put(subdev_fh->owner);
88 : 0 : v4l2_fh_del(&subdev_fh->vfh);
89 : 0 : v4l2_fh_exit(&subdev_fh->vfh);
90 : : subdev_fh_free(subdev_fh);
91 : 0 : kfree(subdev_fh);
92 : :
93 : 0 : return ret;
94 : : }
95 : :
96 : 0 : static int subdev_close(struct file *file)
97 : : {
98 : 0 : struct video_device *vdev = video_devdata(file);
99 : : struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
100 : 0 : struct v4l2_fh *vfh = file->private_data;
101 : : struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
102 : :
103 [ # # # # ]: 0 : if (sd->internal_ops && sd->internal_ops->close)
104 : 0 : sd->internal_ops->close(sd, subdev_fh);
105 : 0 : module_put(subdev_fh->owner);
106 : 0 : v4l2_fh_del(vfh);
107 : 0 : v4l2_fh_exit(vfh);
108 : : subdev_fh_free(subdev_fh);
109 : 0 : kfree(subdev_fh);
110 : 0 : file->private_data = NULL;
111 : :
112 : 0 : return 0;
113 : : }
114 : :
115 : : static inline int check_which(__u32 which)
116 : : {
117 [ # # # # : 0 : if (which != V4L2_SUBDEV_FORMAT_TRY &&
# # # # #
# ]
118 : : which != V4L2_SUBDEV_FORMAT_ACTIVE)
119 : : return -EINVAL;
120 : :
121 : : return 0;
122 : : }
123 : :
124 : : static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
125 : : {
126 : : #if defined(CONFIG_MEDIA_CONTROLLER)
127 [ # # # # : 0 : if (sd->entity.num_pads) {
# # # # #
# # # # #
# # # # #
# # # ]
128 [ # # # # : 0 : if (pad >= sd->entity.num_pads)
# # # # #
# # # # #
# # # # #
# # # ]
129 : : return -EINVAL;
130 : : return 0;
131 : : }
132 : : #endif
133 : : /* allow pad 0 on subdevices not registered as media entities */
134 [ # # # # : 0 : if (pad > 0)
# # # # #
# # # # #
# # # # #
# # # ]
135 : : return -EINVAL;
136 : : return 0;
137 : : }
138 : :
139 : : static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg)
140 : : {
141 [ # # # # : 0 : if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
# # # # #
# ]
142 : : return -EINVAL;
143 : :
144 : : return 0;
145 : : }
146 : :
147 : 0 : static inline int check_format(struct v4l2_subdev *sd,
148 : : struct v4l2_subdev_pad_config *cfg,
149 : : struct v4l2_subdev_format *format)
150 : : {
151 [ # # ]: 0 : if (!format)
152 : : return -EINVAL;
153 : :
154 [ # # # # ]: 0 : return check_which(format->which) ? : check_pad(sd, format->pad) ? :
155 : : check_cfg(format->which, cfg);
156 : : }
157 : :
158 : 0 : static int call_get_fmt(struct v4l2_subdev *sd,
159 : : struct v4l2_subdev_pad_config *cfg,
160 : : struct v4l2_subdev_format *format)
161 : : {
162 [ # # ]: 0 : return check_format(sd, cfg, format) ? :
163 : 0 : sd->ops->pad->get_fmt(sd, cfg, format);
164 : : }
165 : :
166 : 0 : static int call_set_fmt(struct v4l2_subdev *sd,
167 : : struct v4l2_subdev_pad_config *cfg,
168 : : struct v4l2_subdev_format *format)
169 : : {
170 [ # # ]: 0 : return check_format(sd, cfg, format) ? :
171 : 0 : sd->ops->pad->set_fmt(sd, cfg, format);
172 : : }
173 : :
174 : 0 : static int call_enum_mbus_code(struct v4l2_subdev *sd,
175 : : struct v4l2_subdev_pad_config *cfg,
176 : : struct v4l2_subdev_mbus_code_enum *code)
177 : : {
178 [ # # ]: 0 : if (!code)
179 : : return -EINVAL;
180 : :
181 [ # # # # ]: 0 : return check_which(code->which) ? : check_pad(sd, code->pad) ? :
182 [ # # ]: 0 : check_cfg(code->which, cfg) ? :
183 : 0 : sd->ops->pad->enum_mbus_code(sd, cfg, code);
184 : : }
185 : :
186 : 0 : static int call_enum_frame_size(struct v4l2_subdev *sd,
187 : : struct v4l2_subdev_pad_config *cfg,
188 : : struct v4l2_subdev_frame_size_enum *fse)
189 : : {
190 [ # # ]: 0 : if (!fse)
191 : : return -EINVAL;
192 : :
193 [ # # # # ]: 0 : return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
194 [ # # ]: 0 : check_cfg(fse->which, cfg) ? :
195 : 0 : sd->ops->pad->enum_frame_size(sd, cfg, fse);
196 : : }
197 : :
198 : : static inline int check_frame_interval(struct v4l2_subdev *sd,
199 : : struct v4l2_subdev_frame_interval *fi)
200 : : {
201 [ # # # # ]: 0 : if (!fi)
202 : : return -EINVAL;
203 : :
204 : 0 : return check_pad(sd, fi->pad);
205 : : }
206 : :
207 : 0 : static int call_g_frame_interval(struct v4l2_subdev *sd,
208 : : struct v4l2_subdev_frame_interval *fi)
209 : : {
210 [ # # ]: 0 : return check_frame_interval(sd, fi) ? :
211 : 0 : sd->ops->video->g_frame_interval(sd, fi);
212 : : }
213 : :
214 : 0 : static int call_s_frame_interval(struct v4l2_subdev *sd,
215 : : struct v4l2_subdev_frame_interval *fi)
216 : : {
217 [ # # ]: 0 : return check_frame_interval(sd, fi) ? :
218 : 0 : sd->ops->video->s_frame_interval(sd, fi);
219 : : }
220 : :
221 : 0 : static int call_enum_frame_interval(struct v4l2_subdev *sd,
222 : : struct v4l2_subdev_pad_config *cfg,
223 : : struct v4l2_subdev_frame_interval_enum *fie)
224 : : {
225 [ # # ]: 0 : if (!fie)
226 : : return -EINVAL;
227 : :
228 [ # # # # ]: 0 : return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
229 [ # # ]: 0 : check_cfg(fie->which, cfg) ? :
230 : 0 : sd->ops->pad->enum_frame_interval(sd, cfg, fie);
231 : : }
232 : :
233 : 0 : static inline int check_selection(struct v4l2_subdev *sd,
234 : : struct v4l2_subdev_pad_config *cfg,
235 : : struct v4l2_subdev_selection *sel)
236 : : {
237 [ # # ]: 0 : if (!sel)
238 : : return -EINVAL;
239 : :
240 [ # # # # ]: 0 : return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
241 : : check_cfg(sel->which, cfg);
242 : : }
243 : :
244 : 0 : static int call_get_selection(struct v4l2_subdev *sd,
245 : : struct v4l2_subdev_pad_config *cfg,
246 : : struct v4l2_subdev_selection *sel)
247 : : {
248 [ # # ]: 0 : return check_selection(sd, cfg, sel) ? :
249 : 0 : sd->ops->pad->get_selection(sd, cfg, sel);
250 : : }
251 : :
252 : 0 : static int call_set_selection(struct v4l2_subdev *sd,
253 : : struct v4l2_subdev_pad_config *cfg,
254 : : struct v4l2_subdev_selection *sel)
255 : : {
256 [ # # ]: 0 : return check_selection(sd, cfg, sel) ? :
257 : 0 : sd->ops->pad->set_selection(sd, cfg, sel);
258 : : }
259 : :
260 : : static inline int check_edid(struct v4l2_subdev *sd,
261 : : struct v4l2_subdev_edid *edid)
262 : : {
263 [ # # # # ]: 0 : if (!edid)
264 : : return -EINVAL;
265 : :
266 [ # # # # : 0 : if (edid->blocks && edid->edid == NULL)
# # # # ]
267 : : return -EINVAL;
268 : :
269 : 0 : return check_pad(sd, edid->pad);
270 : : }
271 : :
272 : 0 : static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
273 : : {
274 [ # # ]: 0 : return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid);
275 : : }
276 : :
277 : 0 : static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
278 : : {
279 [ # # ]: 0 : return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid);
280 : : }
281 : :
282 : 0 : static int call_dv_timings_cap(struct v4l2_subdev *sd,
283 : : struct v4l2_dv_timings_cap *cap)
284 : : {
285 [ # # ]: 0 : if (!cap)
286 : : return -EINVAL;
287 : :
288 [ # # ]: 0 : return check_pad(sd, cap->pad) ? :
289 : 0 : sd->ops->pad->dv_timings_cap(sd, cap);
290 : : }
291 : :
292 : 0 : static int call_enum_dv_timings(struct v4l2_subdev *sd,
293 : : struct v4l2_enum_dv_timings *dvt)
294 : : {
295 [ # # ]: 0 : if (!dvt)
296 : : return -EINVAL;
297 : :
298 [ # # ]: 0 : return check_pad(sd, dvt->pad) ? :
299 : 0 : sd->ops->pad->enum_dv_timings(sd, dvt);
300 : : }
301 : :
302 : : static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
303 : : .get_fmt = call_get_fmt,
304 : : .set_fmt = call_set_fmt,
305 : : .enum_mbus_code = call_enum_mbus_code,
306 : : .enum_frame_size = call_enum_frame_size,
307 : : .enum_frame_interval = call_enum_frame_interval,
308 : : .get_selection = call_get_selection,
309 : : .set_selection = call_set_selection,
310 : : .get_edid = call_get_edid,
311 : : .set_edid = call_set_edid,
312 : : .dv_timings_cap = call_dv_timings_cap,
313 : : .enum_dv_timings = call_enum_dv_timings,
314 : : };
315 : :
316 : : static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
317 : : .g_frame_interval = call_g_frame_interval,
318 : : .s_frame_interval = call_s_frame_interval,
319 : : };
320 : :
321 : : const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = {
322 : : .pad = &v4l2_subdev_call_pad_wrappers,
323 : : .video = &v4l2_subdev_call_video_wrappers,
324 : : };
325 : : EXPORT_SYMBOL(v4l2_subdev_call_wrappers);
326 : :
327 : 0 : static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
328 : : {
329 : 0 : struct video_device *vdev = video_devdata(file);
330 : : struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
331 : 0 : struct v4l2_fh *vfh = file->private_data;
332 : : #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
333 : : struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
334 : 0 : bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
335 : : int rval;
336 : : #endif
337 : :
338 [ # # # # : 0 : switch (cmd) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
339 : : case VIDIOC_QUERYCTRL:
340 : : /*
341 : : * TODO: this really should be folded into v4l2_queryctrl (this
342 : : * currently returns -EINVAL for NULL control handlers).
343 : : * However, v4l2_queryctrl() is still called directly by
344 : : * drivers as well and until that has been addressed I believe
345 : : * it is safer to do the check here. The same is true for the
346 : : * other control ioctls below.
347 : : */
348 [ # # ]: 0 : if (!vfh->ctrl_handler)
349 : : return -ENOTTY;
350 : 0 : return v4l2_queryctrl(vfh->ctrl_handler, arg);
351 : :
352 : : case VIDIOC_QUERY_EXT_CTRL:
353 [ # # ]: 0 : if (!vfh->ctrl_handler)
354 : : return -ENOTTY;
355 : 0 : return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg);
356 : :
357 : : case VIDIOC_QUERYMENU:
358 [ # # ]: 0 : if (!vfh->ctrl_handler)
359 : : return -ENOTTY;
360 : 0 : return v4l2_querymenu(vfh->ctrl_handler, arg);
361 : :
362 : : case VIDIOC_G_CTRL:
363 [ # # ]: 0 : if (!vfh->ctrl_handler)
364 : : return -ENOTTY;
365 : 0 : return v4l2_g_ctrl(vfh->ctrl_handler, arg);
366 : :
367 : : case VIDIOC_S_CTRL:
368 [ # # ]: 0 : if (!vfh->ctrl_handler)
369 : : return -ENOTTY;
370 : 0 : return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg);
371 : :
372 : : case VIDIOC_G_EXT_CTRLS:
373 [ # # ]: 0 : if (!vfh->ctrl_handler)
374 : : return -ENOTTY;
375 : 0 : return v4l2_g_ext_ctrls(vfh->ctrl_handler,
376 : 0 : vdev, sd->v4l2_dev->mdev, arg);
377 : :
378 : : case VIDIOC_S_EXT_CTRLS:
379 [ # # ]: 0 : if (!vfh->ctrl_handler)
380 : : return -ENOTTY;
381 : 0 : return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler,
382 : 0 : vdev, sd->v4l2_dev->mdev, arg);
383 : :
384 : : case VIDIOC_TRY_EXT_CTRLS:
385 [ # # ]: 0 : if (!vfh->ctrl_handler)
386 : : return -ENOTTY;
387 : 0 : return v4l2_try_ext_ctrls(vfh->ctrl_handler,
388 : 0 : vdev, sd->v4l2_dev->mdev, arg);
389 : :
390 : : case VIDIOC_DQEVENT:
391 [ # # ]: 0 : if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
392 : : return -ENOIOCTLCMD;
393 : :
394 : 0 : return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
395 : :
396 : : case VIDIOC_SUBSCRIBE_EVENT:
397 [ # # # # : 0 : return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
# # ]
398 : :
399 : : case VIDIOC_UNSUBSCRIBE_EVENT:
400 [ # # # # : 0 : return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
# # ]
401 : :
402 : : #ifdef CONFIG_VIDEO_ADV_DEBUG
403 : : case VIDIOC_DBG_G_REGISTER:
404 : : {
405 : : struct v4l2_dbg_register *p = arg;
406 : :
407 : : if (!capable(CAP_SYS_ADMIN))
408 : : return -EPERM;
409 : : return v4l2_subdev_call(sd, core, g_register, p);
410 : : }
411 : : case VIDIOC_DBG_S_REGISTER:
412 : : {
413 : : struct v4l2_dbg_register *p = arg;
414 : :
415 : : if (!capable(CAP_SYS_ADMIN))
416 : : return -EPERM;
417 : : return v4l2_subdev_call(sd, core, s_register, p);
418 : : }
419 : : case VIDIOC_DBG_G_CHIP_INFO:
420 : : {
421 : : struct v4l2_dbg_chip_info *p = arg;
422 : :
423 : : if (p->match.type != V4L2_CHIP_MATCH_SUBDEV || p->match.addr)
424 : : return -EINVAL;
425 : : if (sd->ops->core && sd->ops->core->s_register)
426 : : p->flags |= V4L2_CHIP_FL_WRITABLE;
427 : : if (sd->ops->core && sd->ops->core->g_register)
428 : : p->flags |= V4L2_CHIP_FL_READABLE;
429 : : strscpy(p->name, sd->name, sizeof(p->name));
430 : : return 0;
431 : : }
432 : : #endif
433 : :
434 : : case VIDIOC_LOG_STATUS: {
435 : : int ret;
436 : :
437 : 0 : pr_info("%s: ================= START STATUS =================\n",
438 : : sd->name);
439 [ # # # # : 0 : ret = v4l2_subdev_call(sd, core, log_status);
# # ]
440 : 0 : pr_info("%s: ================== END STATUS ==================\n",
441 : : sd->name);
442 : 0 : return ret;
443 : : }
444 : :
445 : : #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
446 : : case VIDIOC_SUBDEV_G_FMT: {
447 : : struct v4l2_subdev_format *format = arg;
448 : :
449 : 0 : memset(format->reserved, 0, sizeof(format->reserved));
450 : 0 : memset(format->format.reserved, 0, sizeof(format->format.reserved));
451 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
# # # # #
# ]
452 : : }
453 : :
454 : : case VIDIOC_SUBDEV_S_FMT: {
455 : : struct v4l2_subdev_format *format = arg;
456 : :
457 [ # # # # ]: 0 : if (format->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
458 : : return -EPERM;
459 : :
460 : 0 : memset(format->reserved, 0, sizeof(format->reserved));
461 : 0 : memset(format->format.reserved, 0, sizeof(format->format.reserved));
462 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
# # # # #
# ]
463 : : }
464 : :
465 : : case VIDIOC_SUBDEV_G_CROP: {
466 : : struct v4l2_subdev_crop *crop = arg;
467 : : struct v4l2_subdev_selection sel;
468 : :
469 : 0 : memset(crop->reserved, 0, sizeof(crop->reserved));
470 : 0 : memset(&sel, 0, sizeof(sel));
471 : 0 : sel.which = crop->which;
472 : 0 : sel.pad = crop->pad;
473 : : sel.target = V4L2_SEL_TGT_CROP;
474 : :
475 [ # # # # : 0 : rval = v4l2_subdev_call(
# # # # #
# ]
476 : : sd, pad, get_selection, subdev_fh->pad, &sel);
477 : :
478 : 0 : crop->rect = sel.r;
479 : :
480 : : return rval;
481 : : }
482 : :
483 : : case VIDIOC_SUBDEV_S_CROP: {
484 : : struct v4l2_subdev_crop *crop = arg;
485 : : struct v4l2_subdev_selection sel;
486 : :
487 [ # # # # ]: 0 : if (crop->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
488 : : return -EPERM;
489 : :
490 : 0 : memset(crop->reserved, 0, sizeof(crop->reserved));
491 : 0 : memset(&sel, 0, sizeof(sel));
492 : 0 : sel.which = crop->which;
493 : 0 : sel.pad = crop->pad;
494 : : sel.target = V4L2_SEL_TGT_CROP;
495 : 0 : sel.r = crop->rect;
496 : :
497 [ # # # # : 0 : rval = v4l2_subdev_call(
# # # # #
# ]
498 : : sd, pad, set_selection, subdev_fh->pad, &sel);
499 : :
500 : 0 : crop->rect = sel.r;
501 : :
502 : 0 : return rval;
503 : : }
504 : :
505 : : case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
506 : : struct v4l2_subdev_mbus_code_enum *code = arg;
507 : :
508 : 0 : memset(code->reserved, 0, sizeof(code->reserved));
509 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
# # # # #
# ]
510 : : code);
511 : : }
512 : :
513 : : case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
514 : : struct v4l2_subdev_frame_size_enum *fse = arg;
515 : :
516 : 0 : memset(fse->reserved, 0, sizeof(fse->reserved));
517 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
# # # # #
# ]
518 : : fse);
519 : : }
520 : :
521 : : case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
522 : : struct v4l2_subdev_frame_interval *fi = arg;
523 : :
524 : 0 : memset(fi->reserved, 0, sizeof(fi->reserved));
525 [ # # # # : 0 : return v4l2_subdev_call(sd, video, g_frame_interval, arg);
# # # # #
# ]
526 : : }
527 : :
528 : : case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
529 : : struct v4l2_subdev_frame_interval *fi = arg;
530 : :
531 [ # # ]: 0 : if (ro_subdev)
532 : : return -EPERM;
533 : :
534 : 0 : memset(fi->reserved, 0, sizeof(fi->reserved));
535 [ # # # # : 0 : return v4l2_subdev_call(sd, video, s_frame_interval, arg);
# # # # #
# ]
536 : : }
537 : :
538 : : case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
539 : : struct v4l2_subdev_frame_interval_enum *fie = arg;
540 : :
541 : 0 : memset(fie->reserved, 0, sizeof(fie->reserved));
542 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
# # # # #
# ]
543 : : fie);
544 : : }
545 : :
546 : : case VIDIOC_SUBDEV_G_SELECTION: {
547 : : struct v4l2_subdev_selection *sel = arg;
548 : :
549 : 0 : memset(sel->reserved, 0, sizeof(sel->reserved));
550 [ # # # # : 0 : return v4l2_subdev_call(
# # # # #
# ]
551 : : sd, pad, get_selection, subdev_fh->pad, sel);
552 : : }
553 : :
554 : : case VIDIOC_SUBDEV_S_SELECTION: {
555 : : struct v4l2_subdev_selection *sel = arg;
556 : :
557 [ # # # # ]: 0 : if (sel->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
558 : : return -EPERM;
559 : :
560 : 0 : memset(sel->reserved, 0, sizeof(sel->reserved));
561 [ # # # # : 0 : return v4l2_subdev_call(
# # # # #
# ]
562 : : sd, pad, set_selection, subdev_fh->pad, sel);
563 : : }
564 : :
565 : : case VIDIOC_G_EDID: {
566 : : struct v4l2_subdev_edid *edid = arg;
567 : :
568 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, get_edid, edid);
# # # # #
# ]
569 : : }
570 : :
571 : : case VIDIOC_S_EDID: {
572 : : struct v4l2_subdev_edid *edid = arg;
573 : :
574 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, set_edid, edid);
# # # # #
# ]
575 : : }
576 : :
577 : : case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {
578 : : struct v4l2_dv_timings_cap *cap = arg;
579 : :
580 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
# # # # #
# ]
581 : : }
582 : :
583 : : case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {
584 : : struct v4l2_enum_dv_timings *dvt = arg;
585 : :
586 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt);
# # # # #
# ]
587 : : }
588 : :
589 : : case VIDIOC_SUBDEV_QUERY_DV_TIMINGS:
590 [ # # # # : 0 : return v4l2_subdev_call(sd, video, query_dv_timings, arg);
# # ]
591 : :
592 : : case VIDIOC_SUBDEV_G_DV_TIMINGS:
593 [ # # # # : 0 : return v4l2_subdev_call(sd, video, g_dv_timings, arg);
# # ]
594 : :
595 : : case VIDIOC_SUBDEV_S_DV_TIMINGS:
596 [ # # ]: 0 : if (ro_subdev)
597 : : return -EPERM;
598 : :
599 [ # # # # : 0 : return v4l2_subdev_call(sd, video, s_dv_timings, arg);
# # ]
600 : :
601 : : case VIDIOC_SUBDEV_G_STD:
602 [ # # # # : 0 : return v4l2_subdev_call(sd, video, g_std, arg);
# # ]
603 : :
604 : : case VIDIOC_SUBDEV_S_STD: {
605 : : v4l2_std_id *std = arg;
606 : :
607 [ # # ]: 0 : if (ro_subdev)
608 : : return -EPERM;
609 : :
610 [ # # # # : 0 : return v4l2_subdev_call(sd, video, s_std, *std);
# # ]
611 : : }
612 : :
613 : : case VIDIOC_SUBDEV_ENUMSTD: {
614 : : struct v4l2_standard *p = arg;
615 : : v4l2_std_id id;
616 : :
617 [ # # # # : 0 : if (v4l2_subdev_call(sd, video, g_tvnorms, &id))
# # # # ]
618 : : return -EINVAL;
619 : :
620 : 0 : return v4l_video_std_enumstd(p, id);
621 : : }
622 : :
623 : : case VIDIOC_SUBDEV_QUERYSTD:
624 [ # # # # : 0 : return v4l2_subdev_call(sd, video, querystd, arg);
# # ]
625 : : #endif
626 : : default:
627 [ # # # # : 0 : return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
# # ]
628 : : }
629 : :
630 : : return 0;
631 : : }
632 : :
633 : 0 : static long subdev_do_ioctl_lock(struct file *file, unsigned int cmd, void *arg)
634 : : {
635 : 0 : struct video_device *vdev = video_devdata(file);
636 : 0 : struct mutex *lock = vdev->lock;
637 : : long ret = -ENODEV;
638 : :
639 [ # # # # ]: 0 : if (lock && mutex_lock_interruptible(lock))
640 : : return -ERESTARTSYS;
641 [ # # ]: 0 : if (video_is_registered(vdev))
642 : 0 : ret = subdev_do_ioctl(file, cmd, arg);
643 [ # # ]: 0 : if (lock)
644 : 0 : mutex_unlock(lock);
645 : 0 : return ret;
646 : : }
647 : :
648 : 0 : static long subdev_ioctl(struct file *file, unsigned int cmd,
649 : : unsigned long arg)
650 : : {
651 : 0 : return video_usercopy(file, cmd, arg, subdev_do_ioctl_lock);
652 : : }
653 : :
654 : : #ifdef CONFIG_COMPAT
655 : : static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
656 : : unsigned long arg)
657 : : {
658 : : struct video_device *vdev = video_devdata(file);
659 : : struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
660 : :
661 : : return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
662 : : }
663 : : #endif
664 : :
665 : 0 : static __poll_t subdev_poll(struct file *file, poll_table *wait)
666 : : {
667 : 0 : struct video_device *vdev = video_devdata(file);
668 : : struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
669 : 0 : struct v4l2_fh *fh = file->private_data;
670 : :
671 [ # # ]: 0 : if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
672 : : return EPOLLERR;
673 : :
674 : 0 : poll_wait(file, &fh->wait, wait);
675 : :
676 [ # # ]: 0 : if (v4l2_event_pending(fh))
677 : : return EPOLLPRI;
678 : :
679 : 0 : return 0;
680 : : }
681 : :
682 : : const struct v4l2_file_operations v4l2_subdev_fops = {
683 : : .owner = THIS_MODULE,
684 : : .open = subdev_open,
685 : : .unlocked_ioctl = subdev_ioctl,
686 : : #ifdef CONFIG_COMPAT
687 : : .compat_ioctl32 = subdev_compat_ioctl32,
688 : : #endif
689 : : .release = subdev_close,
690 : : .poll = subdev_poll,
691 : : };
692 : :
693 : : #ifdef CONFIG_MEDIA_CONTROLLER
694 : 0 : int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
695 : : struct media_link *link,
696 : : struct v4l2_subdev_format *source_fmt,
697 : : struct v4l2_subdev_format *sink_fmt)
698 : : {
699 : : /* The width, height and code must match. */
700 [ # # # # ]: 0 : if (source_fmt->format.width != sink_fmt->format.width
701 [ # # # # ]: 0 : || source_fmt->format.height != sink_fmt->format.height
702 [ # # # # ]: 0 : || source_fmt->format.code != sink_fmt->format.code)
703 : : return -EPIPE;
704 : :
705 : : /* The field order must match, or the sink field order must be NONE
706 : : * to support interlaced hardware connected to bridges that support
707 : : * progressive formats only.
708 : : */
709 [ # # # # : 0 : if (source_fmt->format.field != sink_fmt->format.field &&
# # # # ]
710 : : sink_fmt->format.field != V4L2_FIELD_NONE)
711 : : return -EPIPE;
712 : :
713 : 0 : return 0;
714 : : }
715 : : EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
716 : :
717 : : static int
718 : 0 : v4l2_subdev_link_validate_get_format(struct media_pad *pad,
719 : : struct v4l2_subdev_format *fmt)
720 : : {
721 [ # # ]: 0 : if (is_media_entity_v4l2_subdev(pad->entity)) {
722 : : struct v4l2_subdev *sd =
723 [ # # ]: 0 : media_entity_to_v4l2_subdev(pad->entity);
724 : :
725 : 0 : fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
726 : 0 : fmt->pad = pad->index;
727 [ # # # # : 0 : return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
# # # # #
# ]
728 : : }
729 : :
730 [ # # ]: 0 : WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
731 : : "Driver bug! Wrong media entity type 0x%08x, entity %s\n",
732 : : pad->entity->function, pad->entity->name);
733 : :
734 : : return -EINVAL;
735 : : }
736 : :
737 : 0 : int v4l2_subdev_link_validate(struct media_link *link)
738 : : {
739 : : struct v4l2_subdev *sink;
740 : : struct v4l2_subdev_format sink_fmt, source_fmt;
741 : : int rval;
742 : :
743 : 0 : rval = v4l2_subdev_link_validate_get_format(
744 : : link->source, &source_fmt);
745 [ # # ]: 0 : if (rval < 0)
746 : : return 0;
747 : :
748 : 0 : rval = v4l2_subdev_link_validate_get_format(
749 : : link->sink, &sink_fmt);
750 [ # # ]: 0 : if (rval < 0)
751 : : return 0;
752 : :
753 [ # # ]: 0 : sink = media_entity_to_v4l2_subdev(link->sink->entity);
754 : :
755 [ # # # # : 0 : rval = v4l2_subdev_call(sink, pad, link_validate, link,
# # ]
756 : : &source_fmt, &sink_fmt);
757 [ # # ]: 0 : if (rval != -ENOIOCTLCMD)
758 : : return rval;
759 : :
760 : 0 : return v4l2_subdev_link_validate_default(
761 : : sink, link, &source_fmt, &sink_fmt);
762 : : }
763 : : EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
764 : :
765 : : struct v4l2_subdev_pad_config *
766 : 0 : v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd)
767 : : {
768 : : struct v4l2_subdev_pad_config *cfg;
769 : : int ret;
770 : :
771 [ # # ]: 0 : if (!sd->entity.num_pads)
772 : : return NULL;
773 : :
774 : 0 : cfg = kvmalloc_array(sd->entity.num_pads, sizeof(*cfg),
775 : : GFP_KERNEL | __GFP_ZERO);
776 [ # # ]: 0 : if (!cfg)
777 : : return NULL;
778 : :
779 [ # # # # : 0 : ret = v4l2_subdev_call(sd, pad, init_cfg, cfg);
# # ]
780 [ # # ]: 0 : if (ret < 0 && ret != -ENOIOCTLCMD) {
781 : 0 : kvfree(cfg);
782 : 0 : return NULL;
783 : : }
784 : :
785 : : return cfg;
786 : : }
787 : : EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config);
788 : :
789 : 0 : void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg)
790 : : {
791 : 0 : kvfree(cfg);
792 : 0 : }
793 : : EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config);
794 : : #endif /* CONFIG_MEDIA_CONTROLLER */
795 : :
796 : 0 : void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
797 : : {
798 : 0 : INIT_LIST_HEAD(&sd->list);
799 [ # # ]: 0 : BUG_ON(!ops);
800 : 0 : sd->ops = ops;
801 : 0 : sd->v4l2_dev = NULL;
802 : 0 : sd->flags = 0;
803 : 0 : sd->name[0] = '\0';
804 : 0 : sd->grp_id = 0;
805 : 0 : sd->dev_priv = NULL;
806 : 0 : sd->host_priv = NULL;
807 : : #if defined(CONFIG_MEDIA_CONTROLLER)
808 : 0 : sd->entity.name = sd->name;
809 : 0 : sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
810 : 0 : sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
811 : : #endif
812 : 0 : }
813 : : EXPORT_SYMBOL(v4l2_subdev_init);
814 : :
815 : 0 : void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
816 : : const struct v4l2_event *ev)
817 : : {
818 : 0 : v4l2_event_queue(sd->devnode, ev);
819 : : v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev);
820 : 0 : }
821 : : EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event);
|