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 /* Allocate try format and crop in the same memory block */
39 fh
->try_fmt
= kzalloc((sizeof(*fh
->try_fmt
) + sizeof(*fh
->try_crop
))
40 * sd
->entity
.num_pads
, GFP_KERNEL
);
41 if (fh
->try_fmt
== NULL
)
44 fh
->try_crop
= (struct v4l2_rect
*)
45 (fh
->try_fmt
+ sd
->entity
.num_pads
);
50 static void subdev_fh_free(struct v4l2_subdev_fh
*fh
)
52 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
59 static int subdev_open(struct file
*file
)
61 struct video_device
*vdev
= video_devdata(file
);
62 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
63 struct v4l2_subdev_fh
*subdev_fh
;
64 #if defined(CONFIG_MEDIA_CONTROLLER)
65 struct media_entity
*entity
= NULL
;
69 subdev_fh
= kzalloc(sizeof(*subdev_fh
), GFP_KERNEL
);
70 if (subdev_fh
== NULL
)
73 ret
= subdev_fh_init(subdev_fh
, sd
);
79 v4l2_fh_init(&subdev_fh
->vfh
, vdev
);
80 v4l2_fh_add(&subdev_fh
->vfh
);
81 file
->private_data
= &subdev_fh
->vfh
;
82 #if defined(CONFIG_MEDIA_CONTROLLER)
83 if (sd
->v4l2_dev
->mdev
) {
84 entity
= media_entity_get(&sd
->entity
);
92 if (sd
->internal_ops
&& sd
->internal_ops
->open
) {
93 ret
= sd
->internal_ops
->open(sd
, subdev_fh
);
101 #if defined(CONFIG_MEDIA_CONTROLLER)
103 media_entity_put(entity
);
105 v4l2_fh_del(&subdev_fh
->vfh
);
106 v4l2_fh_exit(&subdev_fh
->vfh
);
107 subdev_fh_free(subdev_fh
);
113 static int subdev_close(struct file
*file
)
115 struct video_device
*vdev
= video_devdata(file
);
116 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
117 struct v4l2_fh
*vfh
= file
->private_data
;
118 struct v4l2_subdev_fh
*subdev_fh
= to_v4l2_subdev_fh(vfh
);
120 if (sd
->internal_ops
&& sd
->internal_ops
->close
)
121 sd
->internal_ops
->close(sd
, subdev_fh
);
122 #if defined(CONFIG_MEDIA_CONTROLLER)
123 if (sd
->v4l2_dev
->mdev
)
124 media_entity_put(&sd
->entity
);
128 subdev_fh_free(subdev_fh
);
130 file
->private_data
= NULL
;
135 static long subdev_do_ioctl(struct file
*file
, unsigned int cmd
, void *arg
)
137 struct video_device
*vdev
= video_devdata(file
);
138 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
139 struct v4l2_fh
*vfh
= file
->private_data
;
140 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
141 struct v4l2_subdev_fh
*subdev_fh
= to_v4l2_subdev_fh(vfh
);
145 case VIDIOC_QUERYCTRL
:
146 return v4l2_queryctrl(vfh
->ctrl_handler
, arg
);
148 case VIDIOC_QUERYMENU
:
149 return v4l2_querymenu(vfh
->ctrl_handler
, arg
);
152 return v4l2_g_ctrl(vfh
->ctrl_handler
, arg
);
155 return v4l2_s_ctrl(vfh
, vfh
->ctrl_handler
, arg
);
157 case VIDIOC_G_EXT_CTRLS
:
158 return v4l2_g_ext_ctrls(vfh
->ctrl_handler
, arg
);
160 case VIDIOC_S_EXT_CTRLS
:
161 return v4l2_s_ext_ctrls(vfh
, vfh
->ctrl_handler
, arg
);
163 case VIDIOC_TRY_EXT_CTRLS
:
164 return v4l2_try_ext_ctrls(vfh
->ctrl_handler
, arg
);
167 if (!(sd
->flags
& V4L2_SUBDEV_FL_HAS_EVENTS
))
170 return v4l2_event_dequeue(vfh
, arg
, file
->f_flags
& O_NONBLOCK
);
172 case VIDIOC_SUBSCRIBE_EVENT
:
173 return v4l2_subdev_call(sd
, core
, subscribe_event
, vfh
, arg
);
175 case VIDIOC_UNSUBSCRIBE_EVENT
:
176 return v4l2_subdev_call(sd
, core
, unsubscribe_event
, vfh
, arg
);
178 #ifdef CONFIG_VIDEO_ADV_DEBUG
179 case VIDIOC_DBG_G_REGISTER
:
181 struct v4l2_dbg_register
*p
= arg
;
183 if (!capable(CAP_SYS_ADMIN
))
185 return v4l2_subdev_call(sd
, core
, g_register
, p
);
187 case VIDIOC_DBG_S_REGISTER
:
189 struct v4l2_dbg_register
*p
= arg
;
191 if (!capable(CAP_SYS_ADMIN
))
193 return v4l2_subdev_call(sd
, core
, s_register
, p
);
197 case VIDIOC_LOG_STATUS
:
198 return v4l2_subdev_call(sd
, core
, log_status
);
200 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
201 case VIDIOC_SUBDEV_G_FMT
: {
202 struct v4l2_subdev_format
*format
= arg
;
204 if (format
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
205 format
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
208 if (format
->pad
>= sd
->entity
.num_pads
)
211 return v4l2_subdev_call(sd
, pad
, get_fmt
, subdev_fh
, format
);
214 case VIDIOC_SUBDEV_S_FMT
: {
215 struct v4l2_subdev_format
*format
= arg
;
217 if (format
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
218 format
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
221 if (format
->pad
>= sd
->entity
.num_pads
)
224 return v4l2_subdev_call(sd
, pad
, set_fmt
, subdev_fh
, format
);
227 case VIDIOC_SUBDEV_G_CROP
: {
228 struct v4l2_subdev_crop
*crop
= arg
;
230 if (crop
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
231 crop
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
234 if (crop
->pad
>= sd
->entity
.num_pads
)
237 return v4l2_subdev_call(sd
, pad
, get_crop
, subdev_fh
, crop
);
240 case VIDIOC_SUBDEV_S_CROP
: {
241 struct v4l2_subdev_crop
*crop
= arg
;
243 if (crop
->which
!= V4L2_SUBDEV_FORMAT_TRY
&&
244 crop
->which
!= V4L2_SUBDEV_FORMAT_ACTIVE
)
247 if (crop
->pad
>= sd
->entity
.num_pads
)
250 return v4l2_subdev_call(sd
, pad
, set_crop
, subdev_fh
, crop
);
253 case VIDIOC_SUBDEV_ENUM_MBUS_CODE
: {
254 struct v4l2_subdev_mbus_code_enum
*code
= arg
;
256 if (code
->pad
>= sd
->entity
.num_pads
)
259 return v4l2_subdev_call(sd
, pad
, enum_mbus_code
, subdev_fh
,
263 case VIDIOC_SUBDEV_ENUM_FRAME_SIZE
: {
264 struct v4l2_subdev_frame_size_enum
*fse
= arg
;
266 if (fse
->pad
>= sd
->entity
.num_pads
)
269 return v4l2_subdev_call(sd
, pad
, enum_frame_size
, subdev_fh
,
273 case VIDIOC_SUBDEV_G_FRAME_INTERVAL
:
274 return v4l2_subdev_call(sd
, video
, g_frame_interval
, arg
);
276 case VIDIOC_SUBDEV_S_FRAME_INTERVAL
:
277 return v4l2_subdev_call(sd
, video
, s_frame_interval
, arg
);
279 case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL
: {
280 struct v4l2_subdev_frame_interval_enum
*fie
= arg
;
282 if (fie
->pad
>= sd
->entity
.num_pads
)
285 return v4l2_subdev_call(sd
, pad
, enum_frame_interval
, subdev_fh
,
290 return v4l2_subdev_call(sd
, core
, ioctl
, cmd
, arg
);
296 static long subdev_ioctl(struct file
*file
, unsigned int cmd
,
299 return video_usercopy(file
, cmd
, arg
, subdev_do_ioctl
);
302 static unsigned int subdev_poll(struct file
*file
, poll_table
*wait
)
304 struct video_device
*vdev
= video_devdata(file
);
305 struct v4l2_subdev
*sd
= vdev_to_v4l2_subdev(vdev
);
306 struct v4l2_fh
*fh
= file
->private_data
;
308 if (!(sd
->flags
& V4L2_SUBDEV_FL_HAS_EVENTS
))
311 poll_wait(file
, &fh
->wait
, wait
);
313 if (v4l2_event_pending(fh
))
319 const struct v4l2_file_operations v4l2_subdev_fops
= {
320 .owner
= THIS_MODULE
,
322 .unlocked_ioctl
= subdev_ioctl
,
323 .release
= subdev_close
,
327 void v4l2_subdev_init(struct v4l2_subdev
*sd
, const struct v4l2_subdev_ops
*ops
)
329 INIT_LIST_HEAD(&sd
->list
);
337 sd
->host_priv
= NULL
;
338 #if defined(CONFIG_MEDIA_CONTROLLER)
339 sd
->entity
.name
= sd
->name
;
340 sd
->entity
.type
= MEDIA_ENT_T_V4L2_SUBDEV
;
343 EXPORT_SYMBOL(v4l2_subdev_init
);