1/* 2 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. 3 * http://www.samsung.com 4 * 5 * Samsung EXYNOS5 SoC series G-Scaler driver 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published 9 * by the Free Software Foundation, either version 2 of the License, 10 * or (at your option) any later version. 11 */ 12 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/types.h> 16#include <linux/errno.h> 17#include <linux/bug.h> 18#include <linux/interrupt.h> 19#include <linux/workqueue.h> 20#include <linux/device.h> 21#include <linux/platform_device.h> 22#include <linux/list.h> 23#include <linux/io.h> 24#include <linux/slab.h> 25#include <linux/clk.h> 26 27#include <media/v4l2-ioctl.h> 28 29#include "gsc-core.h" 30 31static int gsc_m2m_ctx_stop_req(struct gsc_ctx *ctx) 32{ 33 struct gsc_ctx *curr_ctx; 34 struct gsc_dev *gsc = ctx->gsc_dev; 35 int ret; 36 37 curr_ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev); 38 if (!gsc_m2m_pending(gsc) || (curr_ctx != ctx)) 39 return 0; 40 41 gsc_ctx_state_lock_set(GSC_CTX_STOP_REQ, ctx); 42 ret = wait_event_timeout(gsc->irq_queue, 43 !gsc_ctx_state_is_set(GSC_CTX_STOP_REQ, ctx), 44 GSC_SHUTDOWN_TIMEOUT); 45 46 return ret == 0 ? -ETIMEDOUT : ret; 47} 48 49static void __gsc_m2m_job_abort(struct gsc_ctx *ctx) 50{ 51 int ret; 52 53 ret = gsc_m2m_ctx_stop_req(ctx); 54 if ((ret == -ETIMEDOUT) || (ctx->state & GSC_CTX_ABORT)) { 55 gsc_ctx_state_lock_clear(GSC_CTX_STOP_REQ | GSC_CTX_ABORT, ctx); 56 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); 57 } 58} 59 60static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count) 61{ 62 struct gsc_ctx *ctx = q->drv_priv; 63 int ret; 64 65 ret = pm_runtime_get_sync(&ctx->gsc_dev->pdev->dev); 66 return ret > 0 ? 0 : ret; 67} 68 69static void gsc_m2m_stop_streaming(struct vb2_queue *q) 70{ 71 struct gsc_ctx *ctx = q->drv_priv; 72 73 __gsc_m2m_job_abort(ctx); 74 75 pm_runtime_put(&ctx->gsc_dev->pdev->dev); 76} 77 78void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state) 79{ 80 struct vb2_buffer *src_vb, *dst_vb; 81 82 if (!ctx || !ctx->m2m_ctx) 83 return; 84 85 src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); 86 dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); 87 88 if (src_vb && dst_vb) { 89 dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; 90 dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; 91 dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 92 dst_vb->v4l2_buf.flags |= 93 src_vb->v4l2_buf.flags 94 & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 95 96 v4l2_m2m_buf_done(src_vb, vb_state); 97 v4l2_m2m_buf_done(dst_vb, vb_state); 98 99 v4l2_m2m_job_finish(ctx->gsc_dev->m2m.m2m_dev, 100 ctx->m2m_ctx); 101 } 102} 103 104static void gsc_m2m_job_abort(void *priv) 105{ 106 __gsc_m2m_job_abort((struct gsc_ctx *)priv); 107} 108 109static int gsc_get_bufs(struct gsc_ctx *ctx) 110{ 111 struct gsc_frame *s_frame, *d_frame; 112 struct vb2_buffer *src_vb, *dst_vb; 113 int ret; 114 115 s_frame = &ctx->s_frame; 116 d_frame = &ctx->d_frame; 117 118 src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); 119 ret = gsc_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr); 120 if (ret) 121 return ret; 122 123 dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); 124 ret = gsc_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr); 125 if (ret) 126 return ret; 127 128 dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; 129 130 return 0; 131} 132 133static void gsc_m2m_device_run(void *priv) 134{ 135 struct gsc_ctx *ctx = priv; 136 struct gsc_dev *gsc; 137 unsigned long flags; 138 int ret; 139 bool is_set = false; 140 141 if (WARN(!ctx, "null hardware context\n")) 142 return; 143 144 gsc = ctx->gsc_dev; 145 spin_lock_irqsave(&gsc->slock, flags); 146 147 set_bit(ST_M2M_PEND, &gsc->state); 148 149 /* Reconfigure hardware if the context has changed. */ 150 if (gsc->m2m.ctx != ctx) { 151 pr_debug("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p", 152 gsc->m2m.ctx, ctx); 153 ctx->state |= GSC_PARAMS; 154 gsc->m2m.ctx = ctx; 155 } 156 157 is_set = ctx->state & GSC_CTX_STOP_REQ; 158 if (is_set) { 159 ctx->state &= ~GSC_CTX_STOP_REQ; 160 ctx->state |= GSC_CTX_ABORT; 161 wake_up(&gsc->irq_queue); 162 goto put_device; 163 } 164 165 ret = gsc_get_bufs(ctx); 166 if (ret) { 167 pr_err("Wrong address"); 168 goto put_device; 169 } 170 171 gsc_set_prefbuf(gsc, &ctx->s_frame); 172 gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM); 173 gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM); 174 175 if (ctx->state & GSC_PARAMS) { 176 gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false); 177 gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false); 178 gsc_hw_set_frm_done_irq_mask(gsc, false); 179 gsc_hw_set_gsc_irq_enable(gsc, true); 180 181 if (gsc_set_scaler_info(ctx)) { 182 pr_err("Scaler setup error"); 183 goto put_device; 184 } 185 186 gsc_hw_set_input_path(ctx); 187 gsc_hw_set_in_size(ctx); 188 gsc_hw_set_in_image_format(ctx); 189 190 gsc_hw_set_output_path(ctx); 191 gsc_hw_set_out_size(ctx); 192 gsc_hw_set_out_image_format(ctx); 193 194 gsc_hw_set_prescaler(ctx); 195 gsc_hw_set_mainscaler(ctx); 196 gsc_hw_set_rotation(ctx); 197 gsc_hw_set_global_alpha(ctx); 198 } 199 200 /* update shadow registers */ 201 gsc_hw_set_sfr_update(ctx); 202 203 ctx->state &= ~GSC_PARAMS; 204 gsc_hw_enable_control(gsc, true); 205 206 spin_unlock_irqrestore(&gsc->slock, flags); 207 return; 208 209put_device: 210 ctx->state &= ~GSC_PARAMS; 211 spin_unlock_irqrestore(&gsc->slock, flags); 212} 213 214static int gsc_m2m_queue_setup(struct vb2_queue *vq, 215 const struct v4l2_format *fmt, 216 unsigned int *num_buffers, unsigned int *num_planes, 217 unsigned int sizes[], void *allocators[]) 218{ 219 struct gsc_ctx *ctx = vb2_get_drv_priv(vq); 220 struct gsc_frame *frame; 221 int i; 222 223 frame = ctx_get_frame(ctx, vq->type); 224 if (IS_ERR(frame)) 225 return PTR_ERR(frame); 226 227 if (!frame->fmt) 228 return -EINVAL; 229 230 *num_planes = frame->fmt->num_planes; 231 for (i = 0; i < frame->fmt->num_planes; i++) { 232 sizes[i] = frame->payload[i]; 233 allocators[i] = ctx->gsc_dev->alloc_ctx; 234 } 235 return 0; 236} 237 238static int gsc_m2m_buf_prepare(struct vb2_buffer *vb) 239{ 240 struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 241 struct gsc_frame *frame; 242 int i; 243 244 frame = ctx_get_frame(ctx, vb->vb2_queue->type); 245 if (IS_ERR(frame)) 246 return PTR_ERR(frame); 247 248 if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { 249 for (i = 0; i < frame->fmt->num_planes; i++) 250 vb2_set_plane_payload(vb, i, frame->payload[i]); 251 } 252 253 return 0; 254} 255 256static void gsc_m2m_buf_queue(struct vb2_buffer *vb) 257{ 258 struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 259 260 pr_debug("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); 261 262 if (ctx->m2m_ctx) 263 v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); 264} 265 266static struct vb2_ops gsc_m2m_qops = { 267 .queue_setup = gsc_m2m_queue_setup, 268 .buf_prepare = gsc_m2m_buf_prepare, 269 .buf_queue = gsc_m2m_buf_queue, 270 .wait_prepare = vb2_ops_wait_prepare, 271 .wait_finish = vb2_ops_wait_finish, 272 .stop_streaming = gsc_m2m_stop_streaming, 273 .start_streaming = gsc_m2m_start_streaming, 274}; 275 276static int gsc_m2m_querycap(struct file *file, void *fh, 277 struct v4l2_capability *cap) 278{ 279 struct gsc_ctx *ctx = fh_to_ctx(fh); 280 struct gsc_dev *gsc = ctx->gsc_dev; 281 282 strlcpy(cap->driver, gsc->pdev->name, sizeof(cap->driver)); 283 strlcpy(cap->card, gsc->pdev->name, sizeof(cap->card)); 284 strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info)); 285 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | 286 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; 287 288 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; 289 return 0; 290} 291 292static int gsc_m2m_enum_fmt_mplane(struct file *file, void *priv, 293 struct v4l2_fmtdesc *f) 294{ 295 return gsc_enum_fmt_mplane(f); 296} 297 298static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, 299 struct v4l2_format *f) 300{ 301 struct gsc_ctx *ctx = fh_to_ctx(fh); 302 303 return gsc_g_fmt_mplane(ctx, f); 304} 305 306static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh, 307 struct v4l2_format *f) 308{ 309 struct gsc_ctx *ctx = fh_to_ctx(fh); 310 311 return gsc_try_fmt_mplane(ctx, f); 312} 313 314static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh, 315 struct v4l2_format *f) 316{ 317 struct gsc_ctx *ctx = fh_to_ctx(fh); 318 struct vb2_queue *vq; 319 struct gsc_frame *frame; 320 struct v4l2_pix_format_mplane *pix; 321 int i, ret = 0; 322 323 ret = gsc_m2m_try_fmt_mplane(file, fh, f); 324 if (ret) 325 return ret; 326 327 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); 328 329 if (vb2_is_streaming(vq)) { 330 pr_err("queue (%d) busy", f->type); 331 return -EBUSY; 332 } 333 334 if (V4L2_TYPE_IS_OUTPUT(f->type)) 335 frame = &ctx->s_frame; 336 else 337 frame = &ctx->d_frame; 338 339 pix = &f->fmt.pix_mp; 340 frame->fmt = find_fmt(&pix->pixelformat, NULL, 0); 341 frame->colorspace = pix->colorspace; 342 if (!frame->fmt) 343 return -EINVAL; 344 345 for (i = 0; i < frame->fmt->num_planes; i++) 346 frame->payload[i] = pix->plane_fmt[i].sizeimage; 347 348 gsc_set_frame_size(frame, pix->width, pix->height); 349 350 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 351 gsc_ctx_state_lock_set(GSC_PARAMS | GSC_DST_FMT, ctx); 352 else 353 gsc_ctx_state_lock_set(GSC_PARAMS | GSC_SRC_FMT, ctx); 354 355 pr_debug("f_w: %d, f_h: %d", frame->f_width, frame->f_height); 356 357 return 0; 358} 359 360static int gsc_m2m_reqbufs(struct file *file, void *fh, 361 struct v4l2_requestbuffers *reqbufs) 362{ 363 struct gsc_ctx *ctx = fh_to_ctx(fh); 364 struct gsc_dev *gsc = ctx->gsc_dev; 365 u32 max_cnt; 366 367 max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? 368 gsc->variant->in_buf_cnt : gsc->variant->out_buf_cnt; 369 if (reqbufs->count > max_cnt) { 370 return -EINVAL; 371 } else if (reqbufs->count == 0) { 372 if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 373 gsc_ctx_state_lock_clear(GSC_SRC_FMT, ctx); 374 else 375 gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx); 376 } 377 378 return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); 379} 380 381static int gsc_m2m_expbuf(struct file *file, void *fh, 382 struct v4l2_exportbuffer *eb) 383{ 384 struct gsc_ctx *ctx = fh_to_ctx(fh); 385 return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); 386} 387 388static int gsc_m2m_querybuf(struct file *file, void *fh, 389 struct v4l2_buffer *buf) 390{ 391 struct gsc_ctx *ctx = fh_to_ctx(fh); 392 return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); 393} 394 395static int gsc_m2m_qbuf(struct file *file, void *fh, 396 struct v4l2_buffer *buf) 397{ 398 struct gsc_ctx *ctx = fh_to_ctx(fh); 399 return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); 400} 401 402static int gsc_m2m_dqbuf(struct file *file, void *fh, 403 struct v4l2_buffer *buf) 404{ 405 struct gsc_ctx *ctx = fh_to_ctx(fh); 406 return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); 407} 408 409static int gsc_m2m_streamon(struct file *file, void *fh, 410 enum v4l2_buf_type type) 411{ 412 struct gsc_ctx *ctx = fh_to_ctx(fh); 413 414 /* The source and target color format need to be set */ 415 if (V4L2_TYPE_IS_OUTPUT(type)) { 416 if (!gsc_ctx_state_is_set(GSC_SRC_FMT, ctx)) 417 return -EINVAL; 418 } else if (!gsc_ctx_state_is_set(GSC_DST_FMT, ctx)) { 419 return -EINVAL; 420 } 421 422 return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); 423} 424 425static int gsc_m2m_streamoff(struct file *file, void *fh, 426 enum v4l2_buf_type type) 427{ 428 struct gsc_ctx *ctx = fh_to_ctx(fh); 429 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); 430} 431 432/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ 433static int is_rectangle_enclosed(struct v4l2_rect *a, struct v4l2_rect *b) 434{ 435 if (a->left < b->left || a->top < b->top) 436 return 0; 437 438 if (a->left + a->width > b->left + b->width) 439 return 0; 440 441 if (a->top + a->height > b->top + b->height) 442 return 0; 443 444 return 1; 445} 446 447static int gsc_m2m_g_selection(struct file *file, void *fh, 448 struct v4l2_selection *s) 449{ 450 struct gsc_frame *frame; 451 struct gsc_ctx *ctx = fh_to_ctx(fh); 452 453 if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && 454 (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) 455 return -EINVAL; 456 457 frame = ctx_get_frame(ctx, s->type); 458 if (IS_ERR(frame)) 459 return PTR_ERR(frame); 460 461 switch (s->target) { 462 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 463 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 464 case V4L2_SEL_TGT_CROP_BOUNDS: 465 case V4L2_SEL_TGT_CROP_DEFAULT: 466 s->r.left = 0; 467 s->r.top = 0; 468 s->r.width = frame->f_width; 469 s->r.height = frame->f_height; 470 return 0; 471 472 case V4L2_SEL_TGT_COMPOSE: 473 case V4L2_SEL_TGT_CROP: 474 s->r.left = frame->crop.left; 475 s->r.top = frame->crop.top; 476 s->r.width = frame->crop.width; 477 s->r.height = frame->crop.height; 478 return 0; 479 } 480 481 return -EINVAL; 482} 483 484static int gsc_m2m_s_selection(struct file *file, void *fh, 485 struct v4l2_selection *s) 486{ 487 struct gsc_frame *frame; 488 struct gsc_ctx *ctx = fh_to_ctx(fh); 489 struct v4l2_crop cr; 490 struct gsc_variant *variant = ctx->gsc_dev->variant; 491 int ret; 492 493 cr.type = s->type; 494 cr.c = s->r; 495 496 if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && 497 (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) 498 return -EINVAL; 499 500 ret = gsc_try_crop(ctx, &cr); 501 if (ret) 502 return ret; 503 504 if (s->flags & V4L2_SEL_FLAG_LE && 505 !is_rectangle_enclosed(&cr.c, &s->r)) 506 return -ERANGE; 507 508 if (s->flags & V4L2_SEL_FLAG_GE && 509 !is_rectangle_enclosed(&s->r, &cr.c)) 510 return -ERANGE; 511 512 s->r = cr.c; 513 514 switch (s->target) { 515 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 516 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 517 case V4L2_SEL_TGT_COMPOSE: 518 frame = &ctx->s_frame; 519 break; 520 521 case V4L2_SEL_TGT_CROP_BOUNDS: 522 case V4L2_SEL_TGT_CROP: 523 case V4L2_SEL_TGT_CROP_DEFAULT: 524 frame = &ctx->d_frame; 525 break; 526 527 default: 528 return -EINVAL; 529 } 530 531 /* Check to see if scaling ratio is within supported range */ 532 if (gsc_ctx_state_is_set(GSC_DST_FMT | GSC_SRC_FMT, ctx)) { 533 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 534 ret = gsc_check_scaler_ratio(variant, cr.c.width, 535 cr.c.height, ctx->d_frame.crop.width, 536 ctx->d_frame.crop.height, 537 ctx->gsc_ctrls.rotate->val, ctx->out_path); 538 } else { 539 ret = gsc_check_scaler_ratio(variant, 540 ctx->s_frame.crop.width, 541 ctx->s_frame.crop.height, cr.c.width, 542 cr.c.height, ctx->gsc_ctrls.rotate->val, 543 ctx->out_path); 544 } 545 546 if (ret) { 547 pr_err("Out of scaler range"); 548 return -EINVAL; 549 } 550 } 551 552 frame->crop = cr.c; 553 554 gsc_ctx_state_lock_set(GSC_PARAMS, ctx); 555 return 0; 556} 557 558static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = { 559 .vidioc_querycap = gsc_m2m_querycap, 560 .vidioc_enum_fmt_vid_cap_mplane = gsc_m2m_enum_fmt_mplane, 561 .vidioc_enum_fmt_vid_out_mplane = gsc_m2m_enum_fmt_mplane, 562 .vidioc_g_fmt_vid_cap_mplane = gsc_m2m_g_fmt_mplane, 563 .vidioc_g_fmt_vid_out_mplane = gsc_m2m_g_fmt_mplane, 564 .vidioc_try_fmt_vid_cap_mplane = gsc_m2m_try_fmt_mplane, 565 .vidioc_try_fmt_vid_out_mplane = gsc_m2m_try_fmt_mplane, 566 .vidioc_s_fmt_vid_cap_mplane = gsc_m2m_s_fmt_mplane, 567 .vidioc_s_fmt_vid_out_mplane = gsc_m2m_s_fmt_mplane, 568 .vidioc_reqbufs = gsc_m2m_reqbufs, 569 .vidioc_expbuf = gsc_m2m_expbuf, 570 .vidioc_querybuf = gsc_m2m_querybuf, 571 .vidioc_qbuf = gsc_m2m_qbuf, 572 .vidioc_dqbuf = gsc_m2m_dqbuf, 573 .vidioc_streamon = gsc_m2m_streamon, 574 .vidioc_streamoff = gsc_m2m_streamoff, 575 .vidioc_g_selection = gsc_m2m_g_selection, 576 .vidioc_s_selection = gsc_m2m_s_selection 577}; 578 579static int queue_init(void *priv, struct vb2_queue *src_vq, 580 struct vb2_queue *dst_vq) 581{ 582 struct gsc_ctx *ctx = priv; 583 int ret; 584 585 memset(src_vq, 0, sizeof(*src_vq)); 586 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 587 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 588 src_vq->drv_priv = ctx; 589 src_vq->ops = &gsc_m2m_qops; 590 src_vq->mem_ops = &vb2_dma_contig_memops; 591 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 592 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 593 src_vq->lock = &ctx->gsc_dev->lock; 594 595 ret = vb2_queue_init(src_vq); 596 if (ret) 597 return ret; 598 599 memset(dst_vq, 0, sizeof(*dst_vq)); 600 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 601 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 602 dst_vq->drv_priv = ctx; 603 dst_vq->ops = &gsc_m2m_qops; 604 dst_vq->mem_ops = &vb2_dma_contig_memops; 605 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 606 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 607 dst_vq->lock = &ctx->gsc_dev->lock; 608 609 return vb2_queue_init(dst_vq); 610} 611 612static int gsc_m2m_open(struct file *file) 613{ 614 struct gsc_dev *gsc = video_drvdata(file); 615 struct gsc_ctx *ctx = NULL; 616 int ret; 617 618 pr_debug("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state); 619 620 if (mutex_lock_interruptible(&gsc->lock)) 621 return -ERESTARTSYS; 622 623 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 624 if (!ctx) { 625 ret = -ENOMEM; 626 goto unlock; 627 } 628 629 v4l2_fh_init(&ctx->fh, gsc->m2m.vfd); 630 ret = gsc_ctrls_create(ctx); 631 if (ret) 632 goto error_fh; 633 634 /* Use separate control handler per file handle */ 635 ctx->fh.ctrl_handler = &ctx->ctrl_handler; 636 file->private_data = &ctx->fh; 637 v4l2_fh_add(&ctx->fh); 638 639 ctx->gsc_dev = gsc; 640 /* Default color format */ 641 ctx->s_frame.fmt = get_format(0); 642 ctx->d_frame.fmt = get_format(0); 643 /* Setup the device context for mem2mem mode. */ 644 ctx->state = GSC_CTX_M2M; 645 ctx->flags = 0; 646 ctx->in_path = GSC_DMA; 647 ctx->out_path = GSC_DMA; 648 649 ctx->m2m_ctx = v4l2_m2m_ctx_init(gsc->m2m.m2m_dev, ctx, queue_init); 650 if (IS_ERR(ctx->m2m_ctx)) { 651 pr_err("Failed to initialize m2m context"); 652 ret = PTR_ERR(ctx->m2m_ctx); 653 goto error_ctrls; 654 } 655 656 if (gsc->m2m.refcnt++ == 0) 657 set_bit(ST_M2M_OPEN, &gsc->state); 658 659 pr_debug("gsc m2m driver is opened, ctx(0x%p)", ctx); 660 661 mutex_unlock(&gsc->lock); 662 return 0; 663 664error_ctrls: 665 gsc_ctrls_delete(ctx); 666error_fh: 667 v4l2_fh_del(&ctx->fh); 668 v4l2_fh_exit(&ctx->fh); 669 kfree(ctx); 670unlock: 671 mutex_unlock(&gsc->lock); 672 return ret; 673} 674 675static int gsc_m2m_release(struct file *file) 676{ 677 struct gsc_ctx *ctx = fh_to_ctx(file->private_data); 678 struct gsc_dev *gsc = ctx->gsc_dev; 679 680 pr_debug("pid: %d, state: 0x%lx, refcnt= %d", 681 task_pid_nr(current), gsc->state, gsc->m2m.refcnt); 682 683 mutex_lock(&gsc->lock); 684 685 v4l2_m2m_ctx_release(ctx->m2m_ctx); 686 gsc_ctrls_delete(ctx); 687 v4l2_fh_del(&ctx->fh); 688 v4l2_fh_exit(&ctx->fh); 689 690 if (--gsc->m2m.refcnt <= 0) 691 clear_bit(ST_M2M_OPEN, &gsc->state); 692 kfree(ctx); 693 694 mutex_unlock(&gsc->lock); 695 return 0; 696} 697 698static unsigned int gsc_m2m_poll(struct file *file, 699 struct poll_table_struct *wait) 700{ 701 struct gsc_ctx *ctx = fh_to_ctx(file->private_data); 702 struct gsc_dev *gsc = ctx->gsc_dev; 703 int ret; 704 705 if (mutex_lock_interruptible(&gsc->lock)) 706 return -ERESTARTSYS; 707 708 ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); 709 mutex_unlock(&gsc->lock); 710 711 return ret; 712} 713 714static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma) 715{ 716 struct gsc_ctx *ctx = fh_to_ctx(file->private_data); 717 struct gsc_dev *gsc = ctx->gsc_dev; 718 int ret; 719 720 if (mutex_lock_interruptible(&gsc->lock)) 721 return -ERESTARTSYS; 722 723 ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); 724 mutex_unlock(&gsc->lock); 725 726 return ret; 727} 728 729static const struct v4l2_file_operations gsc_m2m_fops = { 730 .owner = THIS_MODULE, 731 .open = gsc_m2m_open, 732 .release = gsc_m2m_release, 733 .poll = gsc_m2m_poll, 734 .unlocked_ioctl = video_ioctl2, 735 .mmap = gsc_m2m_mmap, 736}; 737 738static struct v4l2_m2m_ops gsc_m2m_ops = { 739 .device_run = gsc_m2m_device_run, 740 .job_abort = gsc_m2m_job_abort, 741}; 742 743int gsc_register_m2m_device(struct gsc_dev *gsc) 744{ 745 struct platform_device *pdev; 746 int ret; 747 748 if (!gsc) 749 return -ENODEV; 750 751 pdev = gsc->pdev; 752 753 gsc->vdev.fops = &gsc_m2m_fops; 754 gsc->vdev.ioctl_ops = &gsc_m2m_ioctl_ops; 755 gsc->vdev.release = video_device_release_empty; 756 gsc->vdev.lock = &gsc->lock; 757 gsc->vdev.vfl_dir = VFL_DIR_M2M; 758 gsc->vdev.v4l2_dev = &gsc->v4l2_dev; 759 snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m", 760 GSC_MODULE_NAME, gsc->id); 761 762 video_set_drvdata(&gsc->vdev, gsc); 763 764 gsc->m2m.vfd = &gsc->vdev; 765 gsc->m2m.m2m_dev = v4l2_m2m_init(&gsc_m2m_ops); 766 if (IS_ERR(gsc->m2m.m2m_dev)) { 767 dev_err(&pdev->dev, "failed to initialize v4l2-m2m device\n"); 768 ret = PTR_ERR(gsc->m2m.m2m_dev); 769 goto err_m2m_r1; 770 } 771 772 ret = video_register_device(&gsc->vdev, VFL_TYPE_GRABBER, -1); 773 if (ret) { 774 dev_err(&pdev->dev, 775 "%s(): failed to register video device\n", __func__); 776 goto err_m2m_r2; 777 } 778 779 pr_debug("gsc m2m driver registered as /dev/video%d", gsc->vdev.num); 780 return 0; 781 782err_m2m_r2: 783 v4l2_m2m_release(gsc->m2m.m2m_dev); 784err_m2m_r1: 785 video_device_release(gsc->m2m.vfd); 786 787 return ret; 788} 789 790void gsc_unregister_m2m_device(struct gsc_dev *gsc) 791{ 792 if (gsc) 793 v4l2_m2m_release(gsc->m2m.m2m_dev); 794} 795