4 * Copyright (C) 2010 Nokia Corporation
6 * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7 * Sakari Ailus <sakari.ailus@iki.fi>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/ioctl.h>
24 #include <linux/slab.h>
25 #include <linux/types.h>
26 #include <linux/videodev2.h>
27 #include <linux/export.h>
29 #include <media/v4l2-ctrls.h>
30 #include <media/v4l2-device.h>
31 #include <media/v4l2-ioctl.h>
32 #include <media/v4l2-fh.h>
33 #include <media/v4l2-event.h>
35 static int subdev_fh_init(struct v4l2_subdev_fh
*fh
, struct v4l2_subdev
*sd
)
37 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
38 fh
->pad
= kzalloc(sizeof(*fh
->pad
) * sd
->entity
.num_pads
, GFP_KERNEL
);
45 static void subdev_fh_free(struct v4l2_subdev_fh
*fh
)
47 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
53 static int subdev_open(struct file
*file
)
55 struct video_device
*vdev
= video_devdata(file
);
56 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
57 struct v4l2_subdev_fh
*subdev_fh
;
58 #if defined(CONFIG_MEDIA_CONTROLLER)
59 struct media_entity
*entity
= NULL
;
63 subdev_fh
= kzalloc(sizeof(*subdev_fh
), GFP_KERNEL
);
64 if (subdev_fh
== NULL
)
67 ret
= subdev_fh_init(subdev_fh
, sd
);
73 v4l2_fh_init(&subdev_fh
->vfh
, vdev
);
74 v4l2_fh_add(&subdev_fh
->vfh
);
75 file
->private_data
= &subdev_fh
->vfh
;
76 #if defined(CONFIG_MEDIA_CONTROLLER)
77 if (sd
->v4l2_dev
->mdev
) {
78 entity
= media_entity_get(&sd
->entity
);
86 if (sd
->internal_ops
&& sd
->internal_ops
->open
) {
87 ret
= sd
->internal_ops
->open(sd
, subdev_fh
);
95 #if defined(CONFIG_MEDIA_CONTROLLER)
97 media_entity_put(entity
);
99 v4l2_fh_del(&subdev_fh
->vfh
);
100 v4l2_fh_exit(&subdev_fh
->vfh
);
101 subdev_fh_free(subdev_fh
);
107 static int subdev_close(struct file
*file
)
109 struct video_device
*vdev
= video_devdata(file
);
110 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
111 struct v4l2_fh
*vfh
= file
->private_data
;
112 struct v4l2_subdev_fh
*subdev_fh
= to_v4l2_subdev_fh(vfh
);
114 if (sd
->internal_ops
&& sd
->internal_ops
->close
)
115 sd
->internal_ops
->close(sd
, subdev_fh
);
116 #if defined(CONFIG_MEDIA_CONTROLLER)
117 if (sd
->v4l2_dev
->mdev
)
118 media_entity_put(&sd
->entity
);
122 subdev_fh_free(subdev_fh
);
124 file
->private_data
= NULL
;
129 static long subdev_do_ioctl(struct file
*file
, unsigned int cmd
, void *arg
)
131 struct video_device
*vdev
= video_devdata(file
);
132 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
133 struct v4l2_fh
*vfh
= file
->private_data
;
134 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
135 struct v4l2_subdev_fh
*subdev_fh
= to_v4l2_subdev_fh(vfh
);
139 case VIDIOC_QUERYCTRL
:
140 return v4l2_queryctrl(vfh
->ctrl_handler
, arg
);
142 case VIDIOC_QUERYMENU
:
143 return v4l2_querymenu(vfh
->ctrl_handler
, arg
);
146 return v4l2_g_ctrl(vfh
->ctrl_handler
, arg
);
149 return v4l2_s_ctrl(vfh
, vfh
->ctrl_handler
, arg
);
151 case VIDIOC_G_EXT_CTRLS
:
152 return v4l2_g_ext_ctrls(vfh
->ctrl_handler
, arg
);
154 case VIDIOC_S_EXT_CTRLS
:
155 return v4l2_s_ext_ctrls(vfh
, vfh
->ctrl_handler
, arg
);
157 case VIDIOC_TRY_EXT_CTRLS
:
158 return v4l2_try_ext_ctrls(vfh
->ctrl_handler
, arg
);
161 if (!(sd
->flags
& V4L2_SUBDEV_FL_HAS_EVENTS
))
164 return v4l2_event_dequeue(vfh
, arg
, file
->f_flags
& O_NONBLOCK
);
166 case VIDIOC_SUBSCRIBE_EVENT
:
167 return v4l2_subdev_call(sd
, core
, subscribe_event
, vfh
, arg
);
169 case VIDIOC_UNSUBSCRIBE_EVENT
:
170 return v4l2_subdev_call(sd
, core
, unsubscribe_event
, vfh
, arg
);
172 #ifdef CONFIG_VIDEO_ADV_DEBUG
173 case VIDIOC_DBG_G_REGISTER
:
175 struct v4l2_dbg_register
*p
= arg
;
177 if (!capable(CAP_SYS_ADMIN
))
179 return v4l2_subdev_call(sd
, core
, g_register
, p
);
181 case VIDIOC_DBG_S_REGISTER
:
183 struct v4l2_dbg_register
*p
= arg
;
185 if (!capable(CAP_SYS_ADMIN
))
187 return v4l2_subdev_call(sd
, core
, s_register
, p
);
191 case VIDIOC_LOG_STATUS
: {
194 pr_info("%s: ================= START STATUS =================\n",
196 ret
= v4l2_subdev_call(sd
, core
, log_status
);
197 pr_info("%s: ================== END STATUS ==================\n",
202 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
203 case VIDIOC_SUBDEV_G_FMT
: {
204 struct v4l2_subdev_format
*format
= arg
;
206 if (format
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
207 format
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
210 if (format
->pad
>= sd
->entity
.num_pads
)
213 return v4l2_subdev_call(sd
, pad
, get_fmt
, subdev_fh
, format
);
216 case VIDIOC_SUBDEV_S_FMT
: {
217 struct v4l2_subdev_format
*format
= arg
;
219 if (format
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
220 format
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
223 if (format
->pad
>= sd
->entity
.num_pads
)
226 return v4l2_subdev_call(sd
, pad
, set_fmt
, subdev_fh
, format
);
229 case VIDIOC_SUBDEV_G_CROP
: {
230 struct v4l2_subdev_crop
*crop
= arg
;
231 struct v4l2_subdev_selection sel
;
234 if (crop
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
235 crop
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
238 if (crop
->pad
>= sd
->entity
.num_pads
)
241 rval
= v4l2_subdev_call(sd
, pad
, get_crop
, subdev_fh
, crop
);
242 if (rval
!= -ENOIOCTLCMD
)
245 memset(&sel
, 0, sizeof(sel
));
246 sel
.which
= crop
->which
;
248 sel
.target
= V4L2_SEL_TGT_CROP
;
250 rval
= v4l2_subdev_call(
251 sd
, pad
, get_selection
, subdev_fh
, &sel
);
258 case VIDIOC_SUBDEV_S_CROP
: {
259 struct v4l2_subdev_crop
*crop
= arg
;
260 struct v4l2_subdev_selection sel
;
263 if (crop
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
264 crop
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
267 if (crop
->pad
>= sd
->entity
.num_pads
)
270 rval
= v4l2_subdev_call(sd
, pad
, set_crop
, subdev_fh
, crop
);
271 if (rval
!= -ENOIOCTLCMD
)
274 memset(&sel
, 0, sizeof(sel
));
275 sel
.which
= crop
->which
;
277 sel
.target
= V4L2_SEL_TGT_CROP
;
280 rval
= v4l2_subdev_call(
281 sd
, pad
, set_selection
, subdev_fh
, &sel
);
288 case VIDIOC_SUBDEV_ENUM_MBUS_CODE
: {
289 struct v4l2_subdev_mbus_code_enum
*code
= arg
;
291 if (code
->pad
>= sd
->entity
.num_pads
)
294 return v4l2_subdev_call(sd
, pad
, enum_mbus_code
, subdev_fh
,
298 case VIDIOC_SUBDEV_ENUM_FRAME_SIZE
: {
299 struct v4l2_subdev_frame_size_enum
*fse
= arg
;
301 if (fse
->pad
>= sd
->entity
.num_pads
)
304 return v4l2_subdev_call(sd
, pad
, enum_frame_size
, subdev_fh
,
308 case VIDIOC_SUBDEV_G_FRAME_INTERVAL
:
309 return v4l2_subdev_call(sd
, video
, g_frame_interval
, arg
);
311 case VIDIOC_SUBDEV_S_FRAME_INTERVAL
:
312 return v4l2_subdev_call(sd
, video
, s_frame_interval
, arg
);
314 case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL
: {
315 struct v4l2_subdev_frame_interval_enum
*fie
= arg
;
317 if (fie
->pad
>= sd
->entity
.num_pads
)
320 return v4l2_subdev_call(sd
, pad
, enum_frame_interval
, subdev_fh
,
324 case VIDIOC_SUBDEV_G_SELECTION
: {
325 struct v4l2_subdev_selection
*sel
= arg
;
327 if (sel
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
328 sel
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
331 if (sel
->pad
>= sd
->entity
.num_pads
)
334 return v4l2_subdev_call(
335 sd
, pad
, get_selection
, subdev_fh
, sel
);
338 case VIDIOC_SUBDEV_S_SELECTION
: {
339 struct v4l2_subdev_selection
*sel
= arg
;
341 if (sel
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
342 sel
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
345 if (sel
->pad
>= sd
->entity
.num_pads
)
348 return v4l2_subdev_call(
349 sd
, pad
, set_selection
, subdev_fh
, sel
);
352 case VIDIOC_SUBDEV_G_EDID
:
353 return v4l2_subdev_call(sd
, pad
, get_edid
, arg
);
355 case VIDIOC_SUBDEV_S_EDID
:
356 return v4l2_subdev_call(sd
, pad
, set_edid
, arg
);
359 return v4l2_subdev_call(sd
, core
, ioctl
, cmd
, arg
);
365 static long subdev_ioctl(struct file
*file
, unsigned int cmd
,
368 return video_usercopy(file
, cmd
, arg
, subdev_do_ioctl
);
371 static unsigned int subdev_poll(struct file
*file
, poll_table
*wait
)
373 struct video_device
*vdev
= video_devdata(file
);
374 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
375 struct v4l2_fh
*fh
= file
->private_data
;
377 if (!(sd
->flags
& V4L2_SUBDEV_FL_HAS_EVENTS
))
380 poll_wait(file
, &fh
->wait
, wait
);
382 if (v4l2_event_pending(fh
))
388 const struct v4l2_file_operations v4l2_subdev_fops
= {
389 .owner
= THIS_MODULE
,
391 .unlocked_ioctl
= subdev_ioctl
,
392 .release
= subdev_close
,
396 #ifdef CONFIG_MEDIA_CONTROLLER
397 int v4l2_subdev_link_validate_default(struct v4l2_subdev
*sd
,
398 struct media_link
*link
,
399 struct v4l2_subdev_format
*source_fmt
,
400 struct v4l2_subdev_format
*sink_fmt
)
402 if (source_fmt
->format
.width
!= sink_fmt
->format
.width
403 || source_fmt
->format
.height
!= sink_fmt
->format
.height
404 || source_fmt
->format
.code
!= sink_fmt
->format
.code
)
409 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default
);
412 v4l2_subdev_link_validate_get_format(struct media_pad
*pad
,
413 struct v4l2_subdev_format
*fmt
)
415 if (media_entity_type(pad
->entity
) == MEDIA_ENT_T_V4L2_SUBDEV
) {
416 struct v4l2_subdev
*sd
=
417 media_entity_to_v4l2_subdev(pad
->entity
);
419 fmt
->which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
420 fmt
->pad
= pad
->index
;
421 return v4l2_subdev_call(sd
, pad
, get_fmt
, NULL
, fmt
);
424 WARN(pad
->entity
->type
!= MEDIA_ENT_T_DEVNODE_V4L
,
425 "Driver bug! Wrong media entity type 0x%08x, entity %s\n",
426 pad
->entity
->type
, pad
->entity
->name
);
431 int v4l2_subdev_link_validate(struct media_link
*link
)
433 struct v4l2_subdev
*sink
;
434 struct v4l2_subdev_format sink_fmt
, source_fmt
;
437 rval
= v4l2_subdev_link_validate_get_format(
438 link
->source
, &source_fmt
);
442 rval
= v4l2_subdev_link_validate_get_format(
443 link
->sink
, &sink_fmt
);
447 sink
= media_entity_to_v4l2_subdev(link
->sink
->entity
);
449 rval
= v4l2_subdev_call(sink
, pad
, link_validate
, link
,
450 &source_fmt
, &sink_fmt
);
451 if (rval
!= -ENOIOCTLCMD
)
454 return v4l2_subdev_link_validate_default(
455 sink
, link
, &source_fmt
, &sink_fmt
);
457 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate
);
458 #endif /* CONFIG_MEDIA_CONTROLLER */
460 void v4l2_subdev_init(struct v4l2_subdev
*sd
, const struct v4l2_subdev_ops
*ops
)
462 INIT_LIST_HEAD(&sd
->list
);
470 sd
->host_priv
= NULL
;
471 #if defined(CONFIG_MEDIA_CONTROLLER)
472 sd
->entity
.name
= sd
->name
;
473 sd
->entity
.type
= MEDIA_ENT_T_V4L2_SUBDEV
;
476 EXPORT_SYMBOL(v4l2_subdev_init
);