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 35 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) 36 { 37 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 38 fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL); 39 if (fh->pad == NULL) 40 return -ENOMEM; 41 #endif 42 return 0; 43 } 44 45 static void subdev_fh_free(struct v4l2_subdev_fh *fh) 46 { 47 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 48 kfree(fh->pad); 49 fh->pad = NULL; 50 #endif 51 } 52 53 static int subdev_open(struct file *file) 54 { 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; 60 #endif 61 int ret; 62 63 subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); 64 if (subdev_fh == NULL) 65 return -ENOMEM; 66 67 ret = subdev_fh_init(subdev_fh, sd); 68 if (ret) { 69 kfree(subdev_fh); 70 return ret; 71 } 72 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); 79 if (!entity) { 80 ret = -EBUSY; 81 goto err; 82 } 83 } 84 #endif 85 86 if (sd->internal_ops && sd->internal_ops->open) { 87 ret = sd->internal_ops->open(sd, subdev_fh); 88 if (ret < 0) 89 goto err; 90 } 91 92 return 0; 93 94 err: 95 #if defined(CONFIG_MEDIA_CONTROLLER) 96 if (entity) 97 media_entity_put(entity); 98 #endif 99 v4l2_fh_del(&subdev_fh->vfh); 100 v4l2_fh_exit(&subdev_fh->vfh); 101 subdev_fh_free(subdev_fh); 102 kfree(subdev_fh); 103 104 return ret; 105 } 106 107 static int subdev_close(struct file *file) 108 { 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); 113 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); 119 #endif 120 v4l2_fh_del(vfh); 121 v4l2_fh_exit(vfh); 122 subdev_fh_free(subdev_fh); 123 kfree(subdev_fh); 124 file->private_data = NULL; 125 126 return 0; 127 } 128 129 static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) 130 { 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); 136 #endif 137 138 switch (cmd) { 139 case VIDIOC_QUERYCTRL: 140 return v4l2_queryctrl(vfh->ctrl_handler, arg); 141 142 case VIDIOC_QUERYMENU: 143 return v4l2_querymenu(vfh->ctrl_handler, arg); 144 145 case VIDIOC_G_CTRL: 146 return v4l2_g_ctrl(vfh->ctrl_handler, arg); 147 148 case VIDIOC_S_CTRL: 149 return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); 150 151 case VIDIOC_G_EXT_CTRLS: 152 return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); 153 154 case VIDIOC_S_EXT_CTRLS: 155 return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); 156 157 case VIDIOC_TRY_EXT_CTRLS: 158 return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); 159 160 case VIDIOC_DQEVENT: 161 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 162 return -ENOIOCTLCMD; 163 164 return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); 165 166 case VIDIOC_SUBSCRIBE_EVENT: 167 return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); 168 169 case VIDIOC_UNSUBSCRIBE_EVENT: 170 return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); 171 172 #ifdef CONFIG_VIDEO_ADV_DEBUG 173 case VIDIOC_DBG_G_REGISTER: 174 { 175 struct v4l2_dbg_register *p = arg; 176 177 if (!capable(CAP_SYS_ADMIN)) 178 return -EPERM; 179 return v4l2_subdev_call(sd, core, g_register, p); 180 } 181 case VIDIOC_DBG_S_REGISTER: 182 { 183 struct v4l2_dbg_register *p = arg; 184 185 if (!capable(CAP_SYS_ADMIN)) 186 return -EPERM; 187 return v4l2_subdev_call(sd, core, s_register, p); 188 } 189 #endif 190 191 case VIDIOC_LOG_STATUS: { 192 int ret; 193 194 pr_info("%s: ================= START STATUS =================\n", 195 sd->name); 196 ret = v4l2_subdev_call(sd, core, log_status); 197 pr_info("%s: ================== END STATUS ==================\n", 198 sd->name); 199 return ret; 200 } 201 202 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 203 case VIDIOC_SUBDEV_G_FMT: { 204 struct v4l2_subdev_format *format = arg; 205 206 if (format->which != V4L2_SUBDEV_FORMAT_TRY && 207 format->which != V4L2_SUBDEV_FORMAT_ACTIVE) 208 return -EINVAL; 209 210 if (format->pad >= sd->entity.num_pads) 211 return -EINVAL; 212 213 return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); 214 } 215 216 case VIDIOC_SUBDEV_S_FMT: { 217 struct v4l2_subdev_format *format = arg; 218 219 if (format->which != V4L2_SUBDEV_FORMAT_TRY && 220 format->which != V4L2_SUBDEV_FORMAT_ACTIVE) 221 return -EINVAL; 222 223 if (format->pad >= sd->entity.num_pads) 224 return -EINVAL; 225 226 return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); 227 } 228 229 case VIDIOC_SUBDEV_G_CROP: { 230 struct v4l2_subdev_crop *crop = arg; 231 struct v4l2_subdev_selection sel; 232 int rval; 233 234 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 235 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 236 return -EINVAL; 237 238 if (crop->pad >= sd->entity.num_pads) 239 return -EINVAL; 240 241 rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); 242 if (rval != -ENOIOCTLCMD) 243 return rval; 244 245 memset(&sel, 0, sizeof(sel)); 246 sel.which = crop->which; 247 sel.pad = crop->pad; 248 sel.target = V4L2_SEL_TGT_CROP; 249 250 rval = v4l2_subdev_call( 251 sd, pad, get_selection, subdev_fh, &sel); 252 253 crop->rect = sel.r; 254 255 return rval; 256 } 257 258 case VIDIOC_SUBDEV_S_CROP: { 259 struct v4l2_subdev_crop *crop = arg; 260 struct v4l2_subdev_selection sel; 261 int rval; 262 263 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 264 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 265 return -EINVAL; 266 267 if (crop->pad >= sd->entity.num_pads) 268 return -EINVAL; 269 270 rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); 271 if (rval != -ENOIOCTLCMD) 272 return rval; 273 274 memset(&sel, 0, sizeof(sel)); 275 sel.which = crop->which; 276 sel.pad = crop->pad; 277 sel.target = V4L2_SEL_TGT_CROP; 278 sel.r = crop->rect; 279 280 rval = v4l2_subdev_call( 281 sd, pad, set_selection, subdev_fh, &sel); 282 283 crop->rect = sel.r; 284 285 return rval; 286 } 287 288 case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { 289 struct v4l2_subdev_mbus_code_enum *code = arg; 290 291 if (code->pad >= sd->entity.num_pads) 292 return -EINVAL; 293 294 return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, 295 code); 296 } 297 298 case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { 299 struct v4l2_subdev_frame_size_enum *fse = arg; 300 301 if (fse->pad >= sd->entity.num_pads) 302 return -EINVAL; 303 304 return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, 305 fse); 306 } 307 308 case VIDIOC_SUBDEV_G_FRAME_INTERVAL: 309 return v4l2_subdev_call(sd, video, g_frame_interval, arg); 310 311 case VIDIOC_SUBDEV_S_FRAME_INTERVAL: 312 return v4l2_subdev_call(sd, video, s_frame_interval, arg); 313 314 case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { 315 struct v4l2_subdev_frame_interval_enum *fie = arg; 316 317 if (fie->pad >= sd->entity.num_pads) 318 return -EINVAL; 319 320 return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, 321 fie); 322 } 323 324 case VIDIOC_SUBDEV_G_SELECTION: { 325 struct v4l2_subdev_selection *sel = arg; 326 327 if (sel->which != V4L2_SUBDEV_FORMAT_TRY && 328 sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 329 return -EINVAL; 330 331 if (sel->pad >= sd->entity.num_pads) 332 return -EINVAL; 333 334 return v4l2_subdev_call( 335 sd, pad, get_selection, subdev_fh, sel); 336 } 337 338 case VIDIOC_SUBDEV_S_SELECTION: { 339 struct v4l2_subdev_selection *sel = arg; 340 341 if (sel->which != V4L2_SUBDEV_FORMAT_TRY && 342 sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 343 return -EINVAL; 344 345 if (sel->pad >= sd->entity.num_pads) 346 return -EINVAL; 347 348 return v4l2_subdev_call( 349 sd, pad, set_selection, subdev_fh, sel); 350 } 351 352 case VIDIOC_SUBDEV_G_EDID: 353 return v4l2_subdev_call(sd, pad, get_edid, arg); 354 355 case VIDIOC_SUBDEV_S_EDID: 356 return v4l2_subdev_call(sd, pad, set_edid, arg); 357 #endif 358 default: 359 return v4l2_subdev_call(sd, core, ioctl, cmd, arg); 360 } 361 362 return 0; 363 } 364 365 static long subdev_ioctl(struct file *file, unsigned int cmd, 366 unsigned long arg) 367 { 368 return video_usercopy(file, cmd, arg, subdev_do_ioctl); 369 } 370 371 static unsigned int subdev_poll(struct file *file, poll_table *wait) 372 { 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; 376 377 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 378 return POLLERR; 379 380 poll_wait(file, &fh->wait, wait); 381 382 if (v4l2_event_pending(fh)) 383 return POLLPRI; 384 385 return 0; 386 } 387 388 const struct v4l2_file_operations v4l2_subdev_fops = { 389 .owner = THIS_MODULE, 390 .open = subdev_open, 391 .unlocked_ioctl = subdev_ioctl, 392 .release = subdev_close, 393 .poll = subdev_poll, 394 }; 395 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) 401 { 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) 405 return -EINVAL; 406 407 return 0; 408 } 409 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); 410 411 static int 412 v4l2_subdev_link_validate_get_format(struct media_pad *pad, 413 struct v4l2_subdev_format *fmt) 414 { 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); 418 419 fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; 420 fmt->pad = pad->index; 421 return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); 422 } 423 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); 427 428 return -EINVAL; 429 } 430 431 int v4l2_subdev_link_validate(struct media_link *link) 432 { 433 struct v4l2_subdev *sink; 434 struct v4l2_subdev_format sink_fmt, source_fmt; 435 int rval; 436 437 rval = v4l2_subdev_link_validate_get_format( 438 link->source, &source_fmt); 439 if (rval < 0) 440 return 0; 441 442 rval = v4l2_subdev_link_validate_get_format( 443 link->sink, &sink_fmt); 444 if (rval < 0) 445 return 0; 446 447 sink = media_entity_to_v4l2_subdev(link->sink->entity); 448 449 rval = v4l2_subdev_call(sink, pad, link_validate, link, 450 &source_fmt, &sink_fmt); 451 if (rval != -ENOIOCTLCMD) 452 return rval; 453 454 return v4l2_subdev_link_validate_default( 455 sink, link, &source_fmt, &sink_fmt); 456 } 457 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); 458 #endif /* CONFIG_MEDIA_CONTROLLER */ 459 460 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) 461 { 462 INIT_LIST_HEAD(&sd->list); 463 BUG_ON(!ops); 464 sd->ops = ops; 465 sd->v4l2_dev = NULL; 466 sd->flags = 0; 467 sd->name[0] = '\0'; 468 sd->grp_id = 0; 469 sd->dev_priv = NULL; 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; 474 #endif 475 } 476 EXPORT_SYMBOL(v4l2_subdev_init); 477