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 19 #include <linux/ioctl.h> 20 #include <linux/slab.h> 21 #include <linux/types.h> 22 #include <linux/videodev2.h> 23 #include <linux/export.h> 24 25 #include <media/v4l2-ctrls.h> 26 #include <media/v4l2-device.h> 27 #include <media/v4l2-ioctl.h> 28 #include <media/v4l2-fh.h> 29 #include <media/v4l2-event.h> 30 31 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) 32 { 33 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 34 if (sd->entity.num_pads) { 35 fh->pad = v4l2_subdev_alloc_pad_config(sd); 36 if (fh->pad == NULL) 37 return -ENOMEM; 38 } 39 #endif 40 return 0; 41 } 42 43 static void subdev_fh_free(struct v4l2_subdev_fh *fh) 44 { 45 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 46 v4l2_subdev_free_pad_config(fh->pad); 47 fh->pad = NULL; 48 #endif 49 } 50 51 static int subdev_open(struct file *file) 52 { 53 struct video_device *vdev = video_devdata(file); 54 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 55 struct v4l2_subdev_fh *subdev_fh; 56 #if defined(CONFIG_MEDIA_CONTROLLER) 57 struct media_entity *entity = NULL; 58 #endif 59 int ret; 60 61 subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); 62 if (subdev_fh == NULL) 63 return -ENOMEM; 64 65 ret = subdev_fh_init(subdev_fh, sd); 66 if (ret) { 67 kfree(subdev_fh); 68 return ret; 69 } 70 71 v4l2_fh_init(&subdev_fh->vfh, vdev); 72 v4l2_fh_add(&subdev_fh->vfh); 73 file->private_data = &subdev_fh->vfh; 74 #if defined(CONFIG_MEDIA_CONTROLLER) 75 if (sd->v4l2_dev->mdev) { 76 entity = media_entity_get(&sd->entity); 77 if (!entity) { 78 ret = -EBUSY; 79 goto err; 80 } 81 } 82 #endif 83 84 if (sd->internal_ops && sd->internal_ops->open) { 85 ret = sd->internal_ops->open(sd, subdev_fh); 86 if (ret < 0) 87 goto err; 88 } 89 90 return 0; 91 92 err: 93 #if defined(CONFIG_MEDIA_CONTROLLER) 94 media_entity_put(entity); 95 #endif 96 v4l2_fh_del(&subdev_fh->vfh); 97 v4l2_fh_exit(&subdev_fh->vfh); 98 subdev_fh_free(subdev_fh); 99 kfree(subdev_fh); 100 101 return ret; 102 } 103 104 static int subdev_close(struct file *file) 105 { 106 struct video_device *vdev = video_devdata(file); 107 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 108 struct v4l2_fh *vfh = file->private_data; 109 struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); 110 111 if (sd->internal_ops && sd->internal_ops->close) 112 sd->internal_ops->close(sd, subdev_fh); 113 #if defined(CONFIG_MEDIA_CONTROLLER) 114 if (sd->v4l2_dev->mdev) 115 media_entity_put(&sd->entity); 116 #endif 117 v4l2_fh_del(vfh); 118 v4l2_fh_exit(vfh); 119 subdev_fh_free(subdev_fh); 120 kfree(subdev_fh); 121 file->private_data = NULL; 122 123 return 0; 124 } 125 126 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 127 static int check_format(struct v4l2_subdev *sd, 128 struct v4l2_subdev_format *format) 129 { 130 if (format->which != V4L2_SUBDEV_FORMAT_TRY && 131 format->which != V4L2_SUBDEV_FORMAT_ACTIVE) 132 return -EINVAL; 133 134 if (format->pad >= sd->entity.num_pads) 135 return -EINVAL; 136 137 return 0; 138 } 139 140 static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop) 141 { 142 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 143 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 144 return -EINVAL; 145 146 if (crop->pad >= sd->entity.num_pads) 147 return -EINVAL; 148 149 return 0; 150 } 151 152 static int check_selection(struct v4l2_subdev *sd, 153 struct v4l2_subdev_selection *sel) 154 { 155 if (sel->which != V4L2_SUBDEV_FORMAT_TRY && 156 sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 157 return -EINVAL; 158 159 if (sel->pad >= sd->entity.num_pads) 160 return -EINVAL; 161 162 return 0; 163 } 164 165 static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) 166 { 167 if (edid->pad >= sd->entity.num_pads) 168 return -EINVAL; 169 170 if (edid->blocks && edid->edid == NULL) 171 return -EINVAL; 172 173 return 0; 174 } 175 #endif 176 177 static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) 178 { 179 struct video_device *vdev = video_devdata(file); 180 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 181 struct v4l2_fh *vfh = file->private_data; 182 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 183 struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); 184 int rval; 185 #endif 186 187 switch (cmd) { 188 case VIDIOC_QUERYCTRL: 189 return v4l2_queryctrl(vfh->ctrl_handler, arg); 190 191 case VIDIOC_QUERY_EXT_CTRL: 192 return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg); 193 194 case VIDIOC_QUERYMENU: 195 return v4l2_querymenu(vfh->ctrl_handler, arg); 196 197 case VIDIOC_G_CTRL: 198 return v4l2_g_ctrl(vfh->ctrl_handler, arg); 199 200 case VIDIOC_S_CTRL: 201 return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); 202 203 case VIDIOC_G_EXT_CTRLS: 204 return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); 205 206 case VIDIOC_S_EXT_CTRLS: 207 return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); 208 209 case VIDIOC_TRY_EXT_CTRLS: 210 return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); 211 212 case VIDIOC_DQEVENT: 213 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 214 return -ENOIOCTLCMD; 215 216 return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); 217 218 case VIDIOC_SUBSCRIBE_EVENT: 219 return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); 220 221 case VIDIOC_UNSUBSCRIBE_EVENT: 222 return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); 223 224 #ifdef CONFIG_VIDEO_ADV_DEBUG 225 case VIDIOC_DBG_G_REGISTER: 226 { 227 struct v4l2_dbg_register *p = arg; 228 229 if (!capable(CAP_SYS_ADMIN)) 230 return -EPERM; 231 return v4l2_subdev_call(sd, core, g_register, p); 232 } 233 case VIDIOC_DBG_S_REGISTER: 234 { 235 struct v4l2_dbg_register *p = arg; 236 237 if (!capable(CAP_SYS_ADMIN)) 238 return -EPERM; 239 return v4l2_subdev_call(sd, core, s_register, p); 240 } 241 #endif 242 243 case VIDIOC_LOG_STATUS: { 244 int ret; 245 246 pr_info("%s: ================= START STATUS =================\n", 247 sd->name); 248 ret = v4l2_subdev_call(sd, core, log_status); 249 pr_info("%s: ================== END STATUS ==================\n", 250 sd->name); 251 return ret; 252 } 253 254 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 255 case VIDIOC_SUBDEV_G_FMT: { 256 struct v4l2_subdev_format *format = arg; 257 258 rval = check_format(sd, format); 259 if (rval) 260 return rval; 261 262 return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); 263 } 264 265 case VIDIOC_SUBDEV_S_FMT: { 266 struct v4l2_subdev_format *format = arg; 267 268 rval = check_format(sd, format); 269 if (rval) 270 return rval; 271 272 return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); 273 } 274 275 case VIDIOC_SUBDEV_G_CROP: { 276 struct v4l2_subdev_crop *crop = arg; 277 struct v4l2_subdev_selection sel; 278 279 rval = check_crop(sd, crop); 280 if (rval) 281 return rval; 282 283 memset(&sel, 0, sizeof(sel)); 284 sel.which = crop->which; 285 sel.pad = crop->pad; 286 sel.target = V4L2_SEL_TGT_CROP; 287 288 rval = v4l2_subdev_call( 289 sd, pad, get_selection, subdev_fh->pad, &sel); 290 291 crop->rect = sel.r; 292 293 return rval; 294 } 295 296 case VIDIOC_SUBDEV_S_CROP: { 297 struct v4l2_subdev_crop *crop = arg; 298 struct v4l2_subdev_selection sel; 299 300 rval = check_crop(sd, crop); 301 if (rval) 302 return rval; 303 304 memset(&sel, 0, sizeof(sel)); 305 sel.which = crop->which; 306 sel.pad = crop->pad; 307 sel.target = V4L2_SEL_TGT_CROP; 308 sel.r = crop->rect; 309 310 rval = v4l2_subdev_call( 311 sd, pad, set_selection, subdev_fh->pad, &sel); 312 313 crop->rect = sel.r; 314 315 return rval; 316 } 317 318 case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { 319 struct v4l2_subdev_mbus_code_enum *code = arg; 320 321 if (code->which != V4L2_SUBDEV_FORMAT_TRY && 322 code->which != V4L2_SUBDEV_FORMAT_ACTIVE) 323 return -EINVAL; 324 325 if (code->pad >= sd->entity.num_pads) 326 return -EINVAL; 327 328 return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, 329 code); 330 } 331 332 case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { 333 struct v4l2_subdev_frame_size_enum *fse = arg; 334 335 if (fse->which != V4L2_SUBDEV_FORMAT_TRY && 336 fse->which != V4L2_SUBDEV_FORMAT_ACTIVE) 337 return -EINVAL; 338 339 if (fse->pad >= sd->entity.num_pads) 340 return -EINVAL; 341 342 return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, 343 fse); 344 } 345 346 case VIDIOC_SUBDEV_G_FRAME_INTERVAL: { 347 struct v4l2_subdev_frame_interval *fi = arg; 348 349 if (fi->pad >= sd->entity.num_pads) 350 return -EINVAL; 351 352 return v4l2_subdev_call(sd, video, g_frame_interval, arg); 353 } 354 355 case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { 356 struct v4l2_subdev_frame_interval *fi = arg; 357 358 if (fi->pad >= sd->entity.num_pads) 359 return -EINVAL; 360 361 return v4l2_subdev_call(sd, video, s_frame_interval, arg); 362 } 363 364 case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { 365 struct v4l2_subdev_frame_interval_enum *fie = arg; 366 367 if (fie->which != V4L2_SUBDEV_FORMAT_TRY && 368 fie->which != V4L2_SUBDEV_FORMAT_ACTIVE) 369 return -EINVAL; 370 371 if (fie->pad >= sd->entity.num_pads) 372 return -EINVAL; 373 374 return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, 375 fie); 376 } 377 378 case VIDIOC_SUBDEV_G_SELECTION: { 379 struct v4l2_subdev_selection *sel = arg; 380 381 rval = check_selection(sd, sel); 382 if (rval) 383 return rval; 384 385 return v4l2_subdev_call( 386 sd, pad, get_selection, subdev_fh->pad, sel); 387 } 388 389 case VIDIOC_SUBDEV_S_SELECTION: { 390 struct v4l2_subdev_selection *sel = arg; 391 392 rval = check_selection(sd, sel); 393 if (rval) 394 return rval; 395 396 return v4l2_subdev_call( 397 sd, pad, set_selection, subdev_fh->pad, sel); 398 } 399 400 case VIDIOC_G_EDID: { 401 struct v4l2_subdev_edid *edid = arg; 402 403 rval = check_edid(sd, edid); 404 if (rval) 405 return rval; 406 407 return v4l2_subdev_call(sd, pad, get_edid, edid); 408 } 409 410 case VIDIOC_S_EDID: { 411 struct v4l2_subdev_edid *edid = arg; 412 413 rval = check_edid(sd, edid); 414 if (rval) 415 return rval; 416 417 return v4l2_subdev_call(sd, pad, set_edid, edid); 418 } 419 420 case VIDIOC_SUBDEV_DV_TIMINGS_CAP: { 421 struct v4l2_dv_timings_cap *cap = arg; 422 423 if (cap->pad >= sd->entity.num_pads) 424 return -EINVAL; 425 426 return v4l2_subdev_call(sd, pad, dv_timings_cap, cap); 427 } 428 429 case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: { 430 struct v4l2_enum_dv_timings *dvt = arg; 431 432 if (dvt->pad >= sd->entity.num_pads) 433 return -EINVAL; 434 435 return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt); 436 } 437 438 case VIDIOC_SUBDEV_QUERY_DV_TIMINGS: 439 return v4l2_subdev_call(sd, video, query_dv_timings, arg); 440 441 case VIDIOC_SUBDEV_G_DV_TIMINGS: 442 return v4l2_subdev_call(sd, video, g_dv_timings, arg); 443 444 case VIDIOC_SUBDEV_S_DV_TIMINGS: 445 return v4l2_subdev_call(sd, video, s_dv_timings, arg); 446 #endif 447 default: 448 return v4l2_subdev_call(sd, core, ioctl, cmd, arg); 449 } 450 451 return 0; 452 } 453 454 static long subdev_ioctl(struct file *file, unsigned int cmd, 455 unsigned long arg) 456 { 457 return video_usercopy(file, cmd, arg, subdev_do_ioctl); 458 } 459 460 #ifdef CONFIG_COMPAT 461 static long subdev_compat_ioctl32(struct file *file, unsigned int cmd, 462 unsigned long arg) 463 { 464 struct video_device *vdev = video_devdata(file); 465 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 466 467 return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg); 468 } 469 #endif 470 471 static unsigned int subdev_poll(struct file *file, poll_table *wait) 472 { 473 struct video_device *vdev = video_devdata(file); 474 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 475 struct v4l2_fh *fh = file->private_data; 476 477 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 478 return POLLERR; 479 480 poll_wait(file, &fh->wait, wait); 481 482 if (v4l2_event_pending(fh)) 483 return POLLPRI; 484 485 return 0; 486 } 487 488 const struct v4l2_file_operations v4l2_subdev_fops = { 489 .owner = THIS_MODULE, 490 .open = subdev_open, 491 .unlocked_ioctl = subdev_ioctl, 492 #ifdef CONFIG_COMPAT 493 .compat_ioctl32 = subdev_compat_ioctl32, 494 #endif 495 .release = subdev_close, 496 .poll = subdev_poll, 497 }; 498 499 #ifdef CONFIG_MEDIA_CONTROLLER 500 int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, 501 struct media_link *link, 502 struct v4l2_subdev_format *source_fmt, 503 struct v4l2_subdev_format *sink_fmt) 504 { 505 /* The width, height and code must match. */ 506 if (source_fmt->format.width != sink_fmt->format.width 507 || source_fmt->format.height != sink_fmt->format.height 508 || source_fmt->format.code != sink_fmt->format.code) 509 return -EPIPE; 510 511 /* The field order must match, or the sink field order must be NONE 512 * to support interlaced hardware connected to bridges that support 513 * progressive formats only. 514 */ 515 if (source_fmt->format.field != sink_fmt->format.field && 516 sink_fmt->format.field != V4L2_FIELD_NONE) 517 return -EPIPE; 518 519 return 0; 520 } 521 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); 522 523 static int 524 v4l2_subdev_link_validate_get_format(struct media_pad *pad, 525 struct v4l2_subdev_format *fmt) 526 { 527 if (is_media_entity_v4l2_subdev(pad->entity)) { 528 struct v4l2_subdev *sd = 529 media_entity_to_v4l2_subdev(pad->entity); 530 531 fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; 532 fmt->pad = pad->index; 533 return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); 534 } 535 536 WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L, 537 "Driver bug! Wrong media entity type 0x%08x, entity %s\n", 538 pad->entity->function, pad->entity->name); 539 540 return -EINVAL; 541 } 542 543 int v4l2_subdev_link_validate(struct media_link *link) 544 { 545 struct v4l2_subdev *sink; 546 struct v4l2_subdev_format sink_fmt, source_fmt; 547 int rval; 548 549 rval = v4l2_subdev_link_validate_get_format( 550 link->source, &source_fmt); 551 if (rval < 0) 552 return 0; 553 554 rval = v4l2_subdev_link_validate_get_format( 555 link->sink, &sink_fmt); 556 if (rval < 0) 557 return 0; 558 559 sink = media_entity_to_v4l2_subdev(link->sink->entity); 560 561 rval = v4l2_subdev_call(sink, pad, link_validate, link, 562 &source_fmt, &sink_fmt); 563 if (rval != -ENOIOCTLCMD) 564 return rval; 565 566 return v4l2_subdev_link_validate_default( 567 sink, link, &source_fmt, &sink_fmt); 568 } 569 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); 570 571 struct v4l2_subdev_pad_config * 572 v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd) 573 { 574 struct v4l2_subdev_pad_config *cfg; 575 int ret; 576 577 if (!sd->entity.num_pads) 578 return NULL; 579 580 cfg = kcalloc(sd->entity.num_pads, sizeof(*cfg), GFP_KERNEL); 581 if (!cfg) 582 return NULL; 583 584 ret = v4l2_subdev_call(sd, pad, init_cfg, cfg); 585 if (ret < 0 && ret != -ENOIOCTLCMD) { 586 kfree(cfg); 587 return NULL; 588 } 589 590 return cfg; 591 } 592 EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config); 593 594 void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg) 595 { 596 kfree(cfg); 597 } 598 EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config); 599 #endif /* CONFIG_MEDIA_CONTROLLER */ 600 601 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) 602 { 603 INIT_LIST_HEAD(&sd->list); 604 BUG_ON(!ops); 605 sd->ops = ops; 606 sd->v4l2_dev = NULL; 607 sd->flags = 0; 608 sd->name[0] = '\0'; 609 sd->grp_id = 0; 610 sd->dev_priv = NULL; 611 sd->host_priv = NULL; 612 #if defined(CONFIG_MEDIA_CONTROLLER) 613 sd->entity.name = sd->name; 614 sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; 615 sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; 616 #endif 617 } 618 EXPORT_SYMBOL(v4l2_subdev_init); 619 620 void v4l2_subdev_notify_event(struct v4l2_subdev *sd, 621 const struct v4l2_event *ev) 622 { 623 v4l2_event_queue(sd->devnode, ev); 624 v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev); 625 } 626 EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); 627