This source file includes following definitions.
- rvin_format_from_pixel
- rvin_format_bytesperline
- rvin_format_sizeimage
- rvin_format_align
- rvin_reset_format
- rvin_try_format
- rvin_querycap
- rvin_try_fmt_vid_cap
- rvin_s_fmt_vid_cap
- rvin_g_fmt_vid_cap
- rvin_enum_fmt_vid_cap
- rvin_g_selection
- rvin_s_selection
- rvin_g_pixelaspect
- rvin_enum_input
- rvin_g_input
- rvin_s_input
- rvin_querystd
- rvin_s_std
- rvin_g_std
- rvin_subscribe_event
- rvin_enum_dv_timings
- rvin_s_dv_timings
- rvin_g_dv_timings
- rvin_query_dv_timings
- rvin_dv_timings_cap
- rvin_g_edid
- rvin_s_edid
- rvin_mc_try_format
- rvin_mc_try_fmt_vid_cap
- rvin_mc_s_fmt_vid_cap
- rvin_mc_enum_input
- rvin_power_parallel
- rvin_open
- rvin_release
- rvin_v4l2_unregister
- rvin_notify
- rvin_v4l2_register
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/pm_runtime.h>
14
15 #include <media/v4l2-event.h>
16 #include <media/v4l2-ioctl.h>
17 #include <media/v4l2-mc.h>
18 #include <media/v4l2-rect.h>
19
20 #include "rcar-vin.h"
21
22 #define RVIN_DEFAULT_FORMAT V4L2_PIX_FMT_YUYV
23 #define RVIN_DEFAULT_WIDTH 800
24 #define RVIN_DEFAULT_HEIGHT 600
25 #define RVIN_DEFAULT_FIELD V4L2_FIELD_NONE
26 #define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB
27
28
29
30
31
32 static const struct rvin_video_format rvin_formats[] = {
33 {
34 .fourcc = V4L2_PIX_FMT_NV16,
35 .bpp = 1,
36 },
37 {
38 .fourcc = V4L2_PIX_FMT_YUYV,
39 .bpp = 2,
40 },
41 {
42 .fourcc = V4L2_PIX_FMT_UYVY,
43 .bpp = 2,
44 },
45 {
46 .fourcc = V4L2_PIX_FMT_RGB565,
47 .bpp = 2,
48 },
49 {
50 .fourcc = V4L2_PIX_FMT_XRGB555,
51 .bpp = 2,
52 },
53 {
54 .fourcc = V4L2_PIX_FMT_XBGR32,
55 .bpp = 4,
56 },
57 {
58 .fourcc = V4L2_PIX_FMT_ARGB555,
59 .bpp = 2,
60 },
61 {
62 .fourcc = V4L2_PIX_FMT_ABGR32,
63 .bpp = 4,
64 },
65 };
66
67 const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
68 u32 pixelformat)
69 {
70 int i;
71
72 if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32)
73 return NULL;
74
75 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
76 if (rvin_formats[i].fourcc == pixelformat)
77 return rvin_formats + i;
78
79 return NULL;
80 }
81
82 static u32 rvin_format_bytesperline(struct rvin_dev *vin,
83 struct v4l2_pix_format *pix)
84 {
85 const struct rvin_video_format *fmt;
86 u32 align;
87
88 fmt = rvin_format_from_pixel(vin, pix->pixelformat);
89
90 if (WARN_ON(!fmt))
91 return -EINVAL;
92
93 align = pix->pixelformat == V4L2_PIX_FMT_NV16 ? 0x20 : 0x10;
94
95 return ALIGN(pix->width, align) * fmt->bpp;
96 }
97
98 static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
99 {
100 if (pix->pixelformat == V4L2_PIX_FMT_NV16)
101 return pix->bytesperline * pix->height * 2;
102
103 return pix->bytesperline * pix->height;
104 }
105
106 static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
107 {
108 u32 walign;
109
110 if (!rvin_format_from_pixel(vin, pix->pixelformat))
111 pix->pixelformat = RVIN_DEFAULT_FORMAT;
112
113 switch (pix->field) {
114 case V4L2_FIELD_TOP:
115 case V4L2_FIELD_BOTTOM:
116 case V4L2_FIELD_NONE:
117 case V4L2_FIELD_INTERLACED_TB:
118 case V4L2_FIELD_INTERLACED_BT:
119 case V4L2_FIELD_INTERLACED:
120 break;
121 case V4L2_FIELD_ALTERNATE:
122
123
124
125
126
127 pix->field = V4L2_FIELD_INTERLACED;
128 pix->height *= 2;
129 break;
130 default:
131 pix->field = RVIN_DEFAULT_FIELD;
132 break;
133 }
134
135
136 walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1;
137
138
139 v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
140 &pix->height, 4, vin->info->max_height, 2, 0);
141
142 pix->bytesperline = rvin_format_bytesperline(vin, pix);
143 pix->sizeimage = rvin_format_sizeimage(pix);
144
145 vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
146 pix->width, pix->height, pix->bytesperline, pix->sizeimage);
147 }
148
149
150
151
152
153 static int rvin_reset_format(struct rvin_dev *vin)
154 {
155 struct v4l2_subdev_format fmt = {
156 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
157 .pad = vin->parallel->source_pad,
158 };
159 int ret;
160
161 ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
162 if (ret)
163 return ret;
164
165 v4l2_fill_pix_format(&vin->format, &fmt.format);
166
167 rvin_format_align(vin, &vin->format);
168
169 vin->source.top = 0;
170 vin->source.left = 0;
171 vin->source.width = vin->format.width;
172 vin->source.height = vin->format.height;
173
174 vin->crop = vin->source;
175 vin->compose = vin->source;
176
177 return 0;
178 }
179
180 static int rvin_try_format(struct rvin_dev *vin, u32 which,
181 struct v4l2_pix_format *pix,
182 struct v4l2_rect *crop, struct v4l2_rect *compose)
183 {
184 struct v4l2_subdev *sd = vin_to_source(vin);
185 struct v4l2_subdev_pad_config *pad_cfg;
186 struct v4l2_subdev_format format = {
187 .which = which,
188 .pad = vin->parallel->source_pad,
189 };
190 enum v4l2_field field;
191 u32 width, height;
192 int ret;
193
194 pad_cfg = v4l2_subdev_alloc_pad_config(sd);
195 if (pad_cfg == NULL)
196 return -ENOMEM;
197
198 if (!rvin_format_from_pixel(vin, pix->pixelformat))
199 pix->pixelformat = RVIN_DEFAULT_FORMAT;
200
201 v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
202
203
204 field = pix->field;
205 width = pix->width;
206 height = pix->height;
207
208 ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
209 if (ret < 0 && ret != -ENOIOCTLCMD)
210 goto done;
211 ret = 0;
212
213 v4l2_fill_pix_format(pix, &format.format);
214
215 if (crop) {
216 crop->top = 0;
217 crop->left = 0;
218 crop->width = pix->width;
219 crop->height = pix->height;
220
221
222
223
224
225 if (pix->field == V4L2_FIELD_ALTERNATE)
226 crop->height *= 2;
227 }
228
229 if (field != V4L2_FIELD_ANY)
230 pix->field = field;
231
232 pix->width = width;
233 pix->height = height;
234
235 rvin_format_align(vin, pix);
236
237 if (compose) {
238 compose->top = 0;
239 compose->left = 0;
240 compose->width = pix->width;
241 compose->height = pix->height;
242 }
243 done:
244 v4l2_subdev_free_pad_config(pad_cfg);
245
246 return ret;
247 }
248
249 static int rvin_querycap(struct file *file, void *priv,
250 struct v4l2_capability *cap)
251 {
252 struct rvin_dev *vin = video_drvdata(file);
253
254 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
255 strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
256 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
257 dev_name(vin->dev));
258 return 0;
259 }
260
261 static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
262 struct v4l2_format *f)
263 {
264 struct rvin_dev *vin = video_drvdata(file);
265
266 return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
267 NULL);
268 }
269
270 static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
271 struct v4l2_format *f)
272 {
273 struct rvin_dev *vin = video_drvdata(file);
274 struct v4l2_rect crop, compose;
275 int ret;
276
277 if (vb2_is_busy(&vin->queue))
278 return -EBUSY;
279
280 ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
281 &crop, &compose);
282 if (ret)
283 return ret;
284
285 vin->format = f->fmt.pix;
286 vin->crop = crop;
287 vin->compose = compose;
288 vin->source = crop;
289
290 return 0;
291 }
292
293 static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
294 struct v4l2_format *f)
295 {
296 struct rvin_dev *vin = video_drvdata(file);
297
298 f->fmt.pix = vin->format;
299
300 return 0;
301 }
302
303 static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
304 struct v4l2_fmtdesc *f)
305 {
306 if (f->index >= ARRAY_SIZE(rvin_formats))
307 return -EINVAL;
308
309 f->pixelformat = rvin_formats[f->index].fourcc;
310
311 return 0;
312 }
313
314 static int rvin_g_selection(struct file *file, void *fh,
315 struct v4l2_selection *s)
316 {
317 struct rvin_dev *vin = video_drvdata(file);
318
319 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
320 return -EINVAL;
321
322 switch (s->target) {
323 case V4L2_SEL_TGT_CROP_BOUNDS:
324 case V4L2_SEL_TGT_CROP_DEFAULT:
325 s->r.left = s->r.top = 0;
326 s->r.width = vin->source.width;
327 s->r.height = vin->source.height;
328 break;
329 case V4L2_SEL_TGT_CROP:
330 s->r = vin->crop;
331 break;
332 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
333 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
334 s->r.left = s->r.top = 0;
335 s->r.width = vin->format.width;
336 s->r.height = vin->format.height;
337 break;
338 case V4L2_SEL_TGT_COMPOSE:
339 s->r = vin->compose;
340 break;
341 default:
342 return -EINVAL;
343 }
344
345 return 0;
346 }
347
348 static int rvin_s_selection(struct file *file, void *fh,
349 struct v4l2_selection *s)
350 {
351 struct rvin_dev *vin = video_drvdata(file);
352 const struct rvin_video_format *fmt;
353 struct v4l2_rect r = s->r;
354 struct v4l2_rect max_rect;
355 struct v4l2_rect min_rect = {
356 .width = 6,
357 .height = 2,
358 };
359
360 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
361 return -EINVAL;
362
363 v4l2_rect_set_min_size(&r, &min_rect);
364
365 switch (s->target) {
366 case V4L2_SEL_TGT_CROP:
367
368 max_rect.top = max_rect.left = 0;
369 max_rect.width = vin->source.width;
370 max_rect.height = vin->source.height;
371 v4l2_rect_map_inside(&r, &max_rect);
372
373 v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
374 &r.height, 2, vin->source.height, 0, 0);
375
376 r.top = clamp_t(s32, r.top, 0, vin->source.height - r.height);
377 r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);
378
379 vin->crop = s->r = r;
380
381 vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
382 r.width, r.height, r.left, r.top,
383 vin->source.width, vin->source.height);
384 break;
385 case V4L2_SEL_TGT_COMPOSE:
386
387 max_rect.top = max_rect.left = 0;
388 max_rect.width = vin->format.width;
389 max_rect.height = vin->format.height;
390 v4l2_rect_map_inside(&r, &max_rect);
391
392
393
394
395
396
397 while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
398 r.top--;
399
400 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
401 while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
402 r.left--;
403
404 vin->compose = s->r = r;
405
406 vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
407 r.width, r.height, r.left, r.top,
408 vin->format.width, vin->format.height);
409 break;
410 default:
411 return -EINVAL;
412 }
413
414
415 rvin_crop_scale_comp(vin);
416
417 return 0;
418 }
419
420 static int rvin_g_pixelaspect(struct file *file, void *priv,
421 int type, struct v4l2_fract *f)
422 {
423 struct rvin_dev *vin = video_drvdata(file);
424 struct v4l2_subdev *sd = vin_to_source(vin);
425
426 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
427 return -EINVAL;
428
429 return v4l2_subdev_call(sd, video, g_pixelaspect, f);
430 }
431
432 static int rvin_enum_input(struct file *file, void *priv,
433 struct v4l2_input *i)
434 {
435 struct rvin_dev *vin = video_drvdata(file);
436 struct v4l2_subdev *sd = vin_to_source(vin);
437 int ret;
438
439 if (i->index != 0)
440 return -EINVAL;
441
442 ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
443 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
444 return ret;
445
446 i->type = V4L2_INPUT_TYPE_CAMERA;
447
448 if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
449 i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
450 i->std = 0;
451 } else {
452 i->capabilities = V4L2_IN_CAP_STD;
453 i->std = vin->vdev.tvnorms;
454 }
455
456 strscpy(i->name, "Camera", sizeof(i->name));
457
458 return 0;
459 }
460
461 static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
462 {
463 *i = 0;
464 return 0;
465 }
466
467 static int rvin_s_input(struct file *file, void *priv, unsigned int i)
468 {
469 if (i > 0)
470 return -EINVAL;
471 return 0;
472 }
473
474 static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
475 {
476 struct rvin_dev *vin = video_drvdata(file);
477 struct v4l2_subdev *sd = vin_to_source(vin);
478
479 return v4l2_subdev_call(sd, video, querystd, a);
480 }
481
482 static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
483 {
484 struct rvin_dev *vin = video_drvdata(file);
485 int ret;
486
487 ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
488 if (ret < 0)
489 return ret;
490
491 vin->std = a;
492
493
494 return rvin_reset_format(vin);
495 }
496
497 static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
498 {
499 struct rvin_dev *vin = video_drvdata(file);
500
501 if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
502 return -ENOIOCTLCMD;
503
504 *a = vin->std;
505
506 return 0;
507 }
508
509 static int rvin_subscribe_event(struct v4l2_fh *fh,
510 const struct v4l2_event_subscription *sub)
511 {
512 switch (sub->type) {
513 case V4L2_EVENT_SOURCE_CHANGE:
514 return v4l2_event_subscribe(fh, sub, 4, NULL);
515 }
516 return v4l2_ctrl_subscribe_event(fh, sub);
517 }
518
519 static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
520 struct v4l2_enum_dv_timings *timings)
521 {
522 struct rvin_dev *vin = video_drvdata(file);
523 struct v4l2_subdev *sd = vin_to_source(vin);
524 int ret;
525
526 if (timings->pad)
527 return -EINVAL;
528
529 timings->pad = vin->parallel->sink_pad;
530
531 ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
532
533 timings->pad = 0;
534
535 return ret;
536 }
537
538 static int rvin_s_dv_timings(struct file *file, void *priv_fh,
539 struct v4l2_dv_timings *timings)
540 {
541 struct rvin_dev *vin = video_drvdata(file);
542 struct v4l2_subdev *sd = vin_to_source(vin);
543 int ret;
544
545 ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
546 if (ret)
547 return ret;
548
549
550 return rvin_reset_format(vin);
551 }
552
553 static int rvin_g_dv_timings(struct file *file, void *priv_fh,
554 struct v4l2_dv_timings *timings)
555 {
556 struct rvin_dev *vin = video_drvdata(file);
557 struct v4l2_subdev *sd = vin_to_source(vin);
558
559 return v4l2_subdev_call(sd, video, g_dv_timings, timings);
560 }
561
562 static int rvin_query_dv_timings(struct file *file, void *priv_fh,
563 struct v4l2_dv_timings *timings)
564 {
565 struct rvin_dev *vin = video_drvdata(file);
566 struct v4l2_subdev *sd = vin_to_source(vin);
567
568 return v4l2_subdev_call(sd, video, query_dv_timings, timings);
569 }
570
571 static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
572 struct v4l2_dv_timings_cap *cap)
573 {
574 struct rvin_dev *vin = video_drvdata(file);
575 struct v4l2_subdev *sd = vin_to_source(vin);
576 int ret;
577
578 if (cap->pad)
579 return -EINVAL;
580
581 cap->pad = vin->parallel->sink_pad;
582
583 ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
584
585 cap->pad = 0;
586
587 return ret;
588 }
589
590 static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
591 {
592 struct rvin_dev *vin = video_drvdata(file);
593 struct v4l2_subdev *sd = vin_to_source(vin);
594 int ret;
595
596 if (edid->pad)
597 return -EINVAL;
598
599 edid->pad = vin->parallel->sink_pad;
600
601 ret = v4l2_subdev_call(sd, pad, get_edid, edid);
602
603 edid->pad = 0;
604
605 return ret;
606 }
607
608 static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
609 {
610 struct rvin_dev *vin = video_drvdata(file);
611 struct v4l2_subdev *sd = vin_to_source(vin);
612 int ret;
613
614 if (edid->pad)
615 return -EINVAL;
616
617 edid->pad = vin->parallel->sink_pad;
618
619 ret = v4l2_subdev_call(sd, pad, set_edid, edid);
620
621 edid->pad = 0;
622
623 return ret;
624 }
625
626 static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
627 .vidioc_querycap = rvin_querycap,
628 .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap,
629 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
630 .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap,
631 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
632
633 .vidioc_g_selection = rvin_g_selection,
634 .vidioc_s_selection = rvin_s_selection,
635
636 .vidioc_g_pixelaspect = rvin_g_pixelaspect,
637
638 .vidioc_enum_input = rvin_enum_input,
639 .vidioc_g_input = rvin_g_input,
640 .vidioc_s_input = rvin_s_input,
641
642 .vidioc_dv_timings_cap = rvin_dv_timings_cap,
643 .vidioc_enum_dv_timings = rvin_enum_dv_timings,
644 .vidioc_g_dv_timings = rvin_g_dv_timings,
645 .vidioc_s_dv_timings = rvin_s_dv_timings,
646 .vidioc_query_dv_timings = rvin_query_dv_timings,
647
648 .vidioc_g_edid = rvin_g_edid,
649 .vidioc_s_edid = rvin_s_edid,
650
651 .vidioc_querystd = rvin_querystd,
652 .vidioc_g_std = rvin_g_std,
653 .vidioc_s_std = rvin_s_std,
654
655 .vidioc_reqbufs = vb2_ioctl_reqbufs,
656 .vidioc_create_bufs = vb2_ioctl_create_bufs,
657 .vidioc_querybuf = vb2_ioctl_querybuf,
658 .vidioc_qbuf = vb2_ioctl_qbuf,
659 .vidioc_dqbuf = vb2_ioctl_dqbuf,
660 .vidioc_expbuf = vb2_ioctl_expbuf,
661 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
662 .vidioc_streamon = vb2_ioctl_streamon,
663 .vidioc_streamoff = vb2_ioctl_streamoff,
664
665 .vidioc_log_status = v4l2_ctrl_log_status,
666 .vidioc_subscribe_event = rvin_subscribe_event,
667 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
668 };
669
670
671
672
673
674 static void rvin_mc_try_format(struct rvin_dev *vin,
675 struct v4l2_pix_format *pix)
676 {
677
678
679
680
681
682
683 pix->colorspace = RVIN_DEFAULT_COLORSPACE;
684 pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
685 pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
686 pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
687 pix->ycbcr_enc);
688
689 rvin_format_align(vin, pix);
690 }
691
692 static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
693 struct v4l2_format *f)
694 {
695 struct rvin_dev *vin = video_drvdata(file);
696
697 rvin_mc_try_format(vin, &f->fmt.pix);
698
699 return 0;
700 }
701
702 static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
703 struct v4l2_format *f)
704 {
705 struct rvin_dev *vin = video_drvdata(file);
706
707 if (vb2_is_busy(&vin->queue))
708 return -EBUSY;
709
710 rvin_mc_try_format(vin, &f->fmt.pix);
711
712 vin->format = f->fmt.pix;
713
714 vin->crop.top = 0;
715 vin->crop.left = 0;
716 vin->crop.width = vin->format.width;
717 vin->crop.height = vin->format.height;
718 vin->compose = vin->crop;
719
720 return 0;
721 }
722
723 static int rvin_mc_enum_input(struct file *file, void *priv,
724 struct v4l2_input *i)
725 {
726 if (i->index != 0)
727 return -EINVAL;
728
729 i->type = V4L2_INPUT_TYPE_CAMERA;
730 strscpy(i->name, "Camera", sizeof(i->name));
731
732 return 0;
733 }
734
735 static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
736 .vidioc_querycap = rvin_querycap,
737 .vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap,
738 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
739 .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap,
740 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
741
742 .vidioc_enum_input = rvin_mc_enum_input,
743 .vidioc_g_input = rvin_g_input,
744 .vidioc_s_input = rvin_s_input,
745
746 .vidioc_reqbufs = vb2_ioctl_reqbufs,
747 .vidioc_create_bufs = vb2_ioctl_create_bufs,
748 .vidioc_querybuf = vb2_ioctl_querybuf,
749 .vidioc_qbuf = vb2_ioctl_qbuf,
750 .vidioc_dqbuf = vb2_ioctl_dqbuf,
751 .vidioc_expbuf = vb2_ioctl_expbuf,
752 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
753 .vidioc_streamon = vb2_ioctl_streamon,
754 .vidioc_streamoff = vb2_ioctl_streamoff,
755
756 .vidioc_log_status = v4l2_ctrl_log_status,
757 .vidioc_subscribe_event = rvin_subscribe_event,
758 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
759 };
760
761
762
763
764
765 static int rvin_power_parallel(struct rvin_dev *vin, bool on)
766 {
767 struct v4l2_subdev *sd = vin_to_source(vin);
768 int power = on ? 1 : 0;
769 int ret;
770
771 ret = v4l2_subdev_call(sd, core, s_power, power);
772 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
773 return ret;
774
775 return 0;
776 }
777
778 static int rvin_open(struct file *file)
779 {
780 struct rvin_dev *vin = video_drvdata(file);
781 int ret;
782
783 ret = pm_runtime_get_sync(vin->dev);
784 if (ret < 0)
785 return ret;
786
787 ret = mutex_lock_interruptible(&vin->lock);
788 if (ret)
789 goto err_pm;
790
791 file->private_data = vin;
792
793 ret = v4l2_fh_open(file);
794 if (ret)
795 goto err_unlock;
796
797 if (vin->info->use_mc)
798 ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
799 else if (v4l2_fh_is_singular_file(file))
800 ret = rvin_power_parallel(vin, true);
801
802 if (ret < 0)
803 goto err_open;
804
805 ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
806 if (ret)
807 goto err_power;
808
809 mutex_unlock(&vin->lock);
810
811 return 0;
812 err_power:
813 if (vin->info->use_mc)
814 v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
815 else if (v4l2_fh_is_singular_file(file))
816 rvin_power_parallel(vin, false);
817 err_open:
818 v4l2_fh_release(file);
819 err_unlock:
820 mutex_unlock(&vin->lock);
821 err_pm:
822 pm_runtime_put(vin->dev);
823
824 return ret;
825 }
826
827 static int rvin_release(struct file *file)
828 {
829 struct rvin_dev *vin = video_drvdata(file);
830 bool fh_singular;
831 int ret;
832
833 mutex_lock(&vin->lock);
834
835
836 fh_singular = v4l2_fh_is_singular_file(file);
837
838
839 ret = _vb2_fop_release(file, NULL);
840
841 if (vin->info->use_mc) {
842 v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
843 } else {
844 if (fh_singular)
845 rvin_power_parallel(vin, false);
846 }
847
848 mutex_unlock(&vin->lock);
849
850 pm_runtime_put(vin->dev);
851
852 return ret;
853 }
854
855 static const struct v4l2_file_operations rvin_fops = {
856 .owner = THIS_MODULE,
857 .unlocked_ioctl = video_ioctl2,
858 .open = rvin_open,
859 .release = rvin_release,
860 .poll = vb2_fop_poll,
861 .mmap = vb2_fop_mmap,
862 .read = vb2_fop_read,
863 };
864
865 void rvin_v4l2_unregister(struct rvin_dev *vin)
866 {
867 if (!video_is_registered(&vin->vdev))
868 return;
869
870 v4l2_info(&vin->v4l2_dev, "Removing %s\n",
871 video_device_node_name(&vin->vdev));
872
873
874 video_unregister_device(&vin->vdev);
875 }
876
877 static void rvin_notify(struct v4l2_subdev *sd,
878 unsigned int notification, void *arg)
879 {
880 struct rvin_dev *vin =
881 container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
882
883 switch (notification) {
884 case V4L2_DEVICE_NOTIFY_EVENT:
885 v4l2_event_queue(&vin->vdev, arg);
886 break;
887 default:
888 break;
889 }
890 }
891
892 int rvin_v4l2_register(struct rvin_dev *vin)
893 {
894 struct video_device *vdev = &vin->vdev;
895 int ret;
896
897 vin->v4l2_dev.notify = rvin_notify;
898
899
900 vdev->v4l2_dev = &vin->v4l2_dev;
901 vdev->queue = &vin->queue;
902 snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
903 vdev->release = video_device_release_empty;
904 vdev->lock = &vin->lock;
905 vdev->fops = &rvin_fops;
906 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
907 V4L2_CAP_READWRITE;
908
909
910 vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
911 vin->format.width = RVIN_DEFAULT_WIDTH;
912 vin->format.height = RVIN_DEFAULT_HEIGHT;
913 vin->format.field = RVIN_DEFAULT_FIELD;
914 vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
915
916 if (vin->info->use_mc) {
917 vdev->ioctl_ops = &rvin_mc_ioctl_ops;
918 } else {
919 vdev->ioctl_ops = &rvin_ioctl_ops;
920 rvin_reset_format(vin);
921 }
922
923 rvin_format_align(vin, &vin->format);
924
925 ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
926 if (ret) {
927 vin_err(vin, "Failed to register video device\n");
928 return ret;
929 }
930
931 video_set_drvdata(&vin->vdev, vin);
932
933 v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
934 video_device_node_name(&vin->vdev));
935
936 return ret;
937 }