Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.3-rc7 343 lines 8.5 kB view raw
1/* 2 * V4L2 sub-device 3 * 4 * Copyright (C) 2010 Nokia Corporation 5 * 6 * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 7 * Sakari Ailus <sakari.ailus@iki.fi> 8 * 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. 12 * 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. 17 * 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 21 */ 22 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> 28 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> 34 35static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) 36{ 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) 42 return -ENOMEM; 43 44 fh->try_crop = (struct v4l2_rect *) 45 (fh->try_fmt + sd->entity.num_pads); 46#endif 47 return 0; 48} 49 50static void subdev_fh_free(struct v4l2_subdev_fh *fh) 51{ 52#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 53 kfree(fh->try_fmt); 54 fh->try_fmt = NULL; 55 fh->try_crop = NULL; 56#endif 57} 58 59static int subdev_open(struct file *file) 60{ 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; 66#endif 67 int ret; 68 69 subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); 70 if (subdev_fh == NULL) 71 return -ENOMEM; 72 73 ret = subdev_fh_init(subdev_fh, sd); 74 if (ret) { 75 kfree(subdev_fh); 76 return ret; 77 } 78 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); 85 if (!entity) { 86 ret = -EBUSY; 87 goto err; 88 } 89 } 90#endif 91 92 if (sd->internal_ops && sd->internal_ops->open) { 93 ret = sd->internal_ops->open(sd, subdev_fh); 94 if (ret < 0) 95 goto err; 96 } 97 98 return 0; 99 100err: 101#if defined(CONFIG_MEDIA_CONTROLLER) 102 if (entity) 103 media_entity_put(entity); 104#endif 105 v4l2_fh_del(&subdev_fh->vfh); 106 v4l2_fh_exit(&subdev_fh->vfh); 107 subdev_fh_free(subdev_fh); 108 kfree(subdev_fh); 109 110 return ret; 111} 112 113static int subdev_close(struct file *file) 114{ 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); 119 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); 125#endif 126 v4l2_fh_del(vfh); 127 v4l2_fh_exit(vfh); 128 subdev_fh_free(subdev_fh); 129 kfree(subdev_fh); 130 file->private_data = NULL; 131 132 return 0; 133} 134 135static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) 136{ 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); 142#endif 143 144 switch (cmd) { 145 case VIDIOC_QUERYCTRL: 146 return v4l2_queryctrl(vfh->ctrl_handler, arg); 147 148 case VIDIOC_QUERYMENU: 149 return v4l2_querymenu(vfh->ctrl_handler, arg); 150 151 case VIDIOC_G_CTRL: 152 return v4l2_g_ctrl(vfh->ctrl_handler, arg); 153 154 case VIDIOC_S_CTRL: 155 return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); 156 157 case VIDIOC_G_EXT_CTRLS: 158 return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); 159 160 case VIDIOC_S_EXT_CTRLS: 161 return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); 162 163 case VIDIOC_TRY_EXT_CTRLS: 164 return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); 165 166 case VIDIOC_DQEVENT: 167 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 168 return -ENOIOCTLCMD; 169 170 return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); 171 172 case VIDIOC_SUBSCRIBE_EVENT: 173 return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); 174 175 case VIDIOC_UNSUBSCRIBE_EVENT: 176 return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); 177 178#ifdef CONFIG_VIDEO_ADV_DEBUG 179 case VIDIOC_DBG_G_REGISTER: 180 { 181 struct v4l2_dbg_register *p = arg; 182 183 if (!capable(CAP_SYS_ADMIN)) 184 return -EPERM; 185 return v4l2_subdev_call(sd, core, g_register, p); 186 } 187 case VIDIOC_DBG_S_REGISTER: 188 { 189 struct v4l2_dbg_register *p = arg; 190 191 if (!capable(CAP_SYS_ADMIN)) 192 return -EPERM; 193 return v4l2_subdev_call(sd, core, s_register, p); 194 } 195#endif 196 197 case VIDIOC_LOG_STATUS: 198 return v4l2_subdev_call(sd, core, log_status); 199 200#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 201 case VIDIOC_SUBDEV_G_FMT: { 202 struct v4l2_subdev_format *format = arg; 203 204 if (format->which != V4L2_SUBDEV_FORMAT_TRY && 205 format->which != V4L2_SUBDEV_FORMAT_ACTIVE) 206 return -EINVAL; 207 208 if (format->pad >= sd->entity.num_pads) 209 return -EINVAL; 210 211 return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); 212 } 213 214 case VIDIOC_SUBDEV_S_FMT: { 215 struct v4l2_subdev_format *format = arg; 216 217 if (format->which != V4L2_SUBDEV_FORMAT_TRY && 218 format->which != V4L2_SUBDEV_FORMAT_ACTIVE) 219 return -EINVAL; 220 221 if (format->pad >= sd->entity.num_pads) 222 return -EINVAL; 223 224 return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); 225 } 226 227 case VIDIOC_SUBDEV_G_CROP: { 228 struct v4l2_subdev_crop *crop = arg; 229 230 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 231 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 232 return -EINVAL; 233 234 if (crop->pad >= sd->entity.num_pads) 235 return -EINVAL; 236 237 return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); 238 } 239 240 case VIDIOC_SUBDEV_S_CROP: { 241 struct v4l2_subdev_crop *crop = arg; 242 243 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 244 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 245 return -EINVAL; 246 247 if (crop->pad >= sd->entity.num_pads) 248 return -EINVAL; 249 250 return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); 251 } 252 253 case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { 254 struct v4l2_subdev_mbus_code_enum *code = arg; 255 256 if (code->pad >= sd->entity.num_pads) 257 return -EINVAL; 258 259 return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, 260 code); 261 } 262 263 case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { 264 struct v4l2_subdev_frame_size_enum *fse = arg; 265 266 if (fse->pad >= sd->entity.num_pads) 267 return -EINVAL; 268 269 return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, 270 fse); 271 } 272 273 case VIDIOC_SUBDEV_G_FRAME_INTERVAL: 274 return v4l2_subdev_call(sd, video, g_frame_interval, arg); 275 276 case VIDIOC_SUBDEV_S_FRAME_INTERVAL: 277 return v4l2_subdev_call(sd, video, s_frame_interval, arg); 278 279 case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { 280 struct v4l2_subdev_frame_interval_enum *fie = arg; 281 282 if (fie->pad >= sd->entity.num_pads) 283 return -EINVAL; 284 285 return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, 286 fie); 287 } 288#endif 289 default: 290 return v4l2_subdev_call(sd, core, ioctl, cmd, arg); 291 } 292 293 return 0; 294} 295 296static long subdev_ioctl(struct file *file, unsigned int cmd, 297 unsigned long arg) 298{ 299 return video_usercopy(file, cmd, arg, subdev_do_ioctl); 300} 301 302static unsigned int subdev_poll(struct file *file, poll_table *wait) 303{ 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; 307 308 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 309 return POLLERR; 310 311 poll_wait(file, &fh->wait, wait); 312 313 if (v4l2_event_pending(fh)) 314 return POLLPRI; 315 316 return 0; 317} 318 319const struct v4l2_file_operations v4l2_subdev_fops = { 320 .owner = THIS_MODULE, 321 .open = subdev_open, 322 .unlocked_ioctl = subdev_ioctl, 323 .release = subdev_close, 324 .poll = subdev_poll, 325}; 326 327void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) 328{ 329 INIT_LIST_HEAD(&sd->list); 330 BUG_ON(!ops); 331 sd->ops = ops; 332 sd->v4l2_dev = NULL; 333 sd->flags = 0; 334 sd->name[0] = '\0'; 335 sd->grp_id = 0; 336 sd->dev_priv = NULL; 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; 341#endif 342} 343EXPORT_SYMBOL(v4l2_subdev_init);