1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Contains the driver implementation for the V4L2 stateless interface. |
4 | */ |
5 | |
6 | #include <linux/debugfs.h> |
7 | #include <linux/font.h> |
8 | #include <media/v4l2-event.h> |
9 | #include <media/v4l2-ioctl.h> |
10 | #include <media/videobuf2-vmalloc.h> |
11 | #include <media/videobuf2-v4l2.h> |
12 | |
13 | #include "visl-video.h" |
14 | |
15 | #include "visl.h" |
16 | #include "visl-debugfs.h" |
17 | |
18 | #define MIN_CODED_SZ (1024U * 256U) |
19 | |
20 | static void visl_set_current_codec(struct visl_ctx *ctx) |
21 | { |
22 | u32 fourcc = ctx->coded_fmt.fmt.pix_mp.pixelformat; |
23 | |
24 | switch (fourcc) { |
25 | case V4L2_PIX_FMT_FWHT_STATELESS: |
26 | ctx->current_codec = VISL_CODEC_FWHT; |
27 | break; |
28 | case V4L2_PIX_FMT_MPEG2_SLICE: |
29 | ctx->current_codec = VISL_CODEC_MPEG2; |
30 | break; |
31 | case V4L2_PIX_FMT_VP8_FRAME: |
32 | ctx->current_codec = VISL_CODEC_VP8; |
33 | break; |
34 | case V4L2_PIX_FMT_VP9_FRAME: |
35 | ctx->current_codec = VISL_CODEC_VP9; |
36 | break; |
37 | case V4L2_PIX_FMT_H264_SLICE: |
38 | ctx->current_codec = VISL_CODEC_H264; |
39 | break; |
40 | case V4L2_PIX_FMT_HEVC_SLICE: |
41 | ctx->current_codec = VISL_CODEC_HEVC; |
42 | break; |
43 | case V4L2_PIX_FMT_AV1_FRAME: |
44 | ctx->current_codec = VISL_CODEC_AV1; |
45 | break; |
46 | default: |
47 | dprintk(ctx->dev, "Warning: unsupported fourcc: %d\n" , fourcc); |
48 | ctx->current_codec = VISL_CODEC_NONE; |
49 | break; |
50 | } |
51 | } |
52 | |
53 | static void visl_print_fmt(struct visl_ctx *ctx, const struct v4l2_format *f) |
54 | { |
55 | const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; |
56 | u32 i; |
57 | |
58 | dprintk(ctx->dev, "width: %d\n" , pix_mp->width); |
59 | dprintk(ctx->dev, "height: %d\n" , pix_mp->height); |
60 | dprintk(ctx->dev, "pixelformat: %c%c%c%c\n" , |
61 | pix_mp->pixelformat, |
62 | (pix_mp->pixelformat >> 8) & 0xff, |
63 | (pix_mp->pixelformat >> 16) & 0xff, |
64 | (pix_mp->pixelformat >> 24) & 0xff); |
65 | |
66 | dprintk(ctx->dev, "field: %d\n" , pix_mp->field); |
67 | dprintk(ctx->dev, "colorspace: %d\n" , pix_mp->colorspace); |
68 | dprintk(ctx->dev, "num_planes: %d\n" , pix_mp->num_planes); |
69 | dprintk(ctx->dev, "flags: %d\n" , pix_mp->flags); |
70 | dprintk(ctx->dev, "quantization: %d\n" , pix_mp->quantization); |
71 | dprintk(ctx->dev, "xfer_func: %d\n" , pix_mp->xfer_func); |
72 | |
73 | for (i = 0; i < pix_mp->num_planes; i++) { |
74 | dprintk(ctx->dev, |
75 | "plane[%d]: sizeimage: %d\n" , i, pix_mp->plane_fmt[i].sizeimage); |
76 | dprintk(ctx->dev, |
77 | "plane[%d]: bytesperline: %d\n" , i, pix_mp->plane_fmt[i].bytesperline); |
78 | } |
79 | } |
80 | |
81 | static int visl_tpg_init(struct visl_ctx *ctx) |
82 | { |
83 | const struct font_desc *font; |
84 | const char *font_name = "VGA8x16" ; |
85 | int ret; |
86 | u32 width = ctx->decoded_fmt.fmt.pix_mp.width; |
87 | u32 height = ctx->decoded_fmt.fmt.pix_mp.height; |
88 | struct v4l2_pix_format_mplane *f = &ctx->decoded_fmt.fmt.pix_mp; |
89 | |
90 | tpg_free(tpg: &ctx->tpg); |
91 | |
92 | font = find_font(name: font_name); |
93 | if (font) { |
94 | tpg_init(tpg: &ctx->tpg, w: width, h: height); |
95 | |
96 | ret = tpg_alloc(tpg: &ctx->tpg, max_w: width); |
97 | if (ret) |
98 | goto err_alloc; |
99 | |
100 | tpg_set_font(f: font->data); |
101 | ret = tpg_s_fourcc(tpg: &ctx->tpg, |
102 | fourcc: f->pixelformat); |
103 | |
104 | if (!ret) |
105 | goto err_fourcc; |
106 | |
107 | tpg_reset_source(tpg: &ctx->tpg, width, height, field: f->field); |
108 | |
109 | tpg_s_pattern(tpg: &ctx->tpg, pattern: TPG_PAT_75_COLORBAR); |
110 | |
111 | tpg_s_field(tpg: &ctx->tpg, field: f->field, alternate: false); |
112 | tpg_s_colorspace(tpg: &ctx->tpg, colorspace: f->colorspace); |
113 | tpg_s_ycbcr_enc(tpg: &ctx->tpg, ycbcr_enc: f->ycbcr_enc); |
114 | tpg_s_quantization(tpg: &ctx->tpg, quantization: f->quantization); |
115 | tpg_s_xfer_func(tpg: &ctx->tpg, xfer_func: f->xfer_func); |
116 | } else { |
117 | v4l2_err(&ctx->dev->v4l2_dev, |
118 | "Font %s not found\n" , font_name); |
119 | |
120 | return -EINVAL; |
121 | } |
122 | |
123 | dprintk(ctx->dev, "Initialized the V4L2 test pattern generator, w=%d, h=%d, max_w=%d\n" , |
124 | width, height, width); |
125 | |
126 | return 0; |
127 | err_alloc: |
128 | return ret; |
129 | err_fourcc: |
130 | tpg_free(tpg: &ctx->tpg); |
131 | return ret; |
132 | } |
133 | |
134 | static const u32 visl_decoded_fmts[] = { |
135 | V4L2_PIX_FMT_NV12, |
136 | V4L2_PIX_FMT_YUV420, |
137 | }; |
138 | |
139 | const struct visl_coded_format_desc visl_coded_fmts[] = { |
140 | { |
141 | .pixelformat = V4L2_PIX_FMT_FWHT_STATELESS, |
142 | .frmsize = { |
143 | .min_width = 640, |
144 | .max_width = 4096, |
145 | .step_width = 1, |
146 | .min_height = 360, |
147 | .max_height = 2160, |
148 | .step_height = 1, |
149 | }, |
150 | .ctrls = &visl_fwht_ctrls, |
151 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
152 | .decoded_fmts = visl_decoded_fmts, |
153 | }, |
154 | { |
155 | .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE, |
156 | .frmsize = { |
157 | .min_width = 16, |
158 | .max_width = 1920, |
159 | .step_width = 1, |
160 | .min_height = 16, |
161 | .max_height = 1152, |
162 | .step_height = 1, |
163 | }, |
164 | .ctrls = &visl_mpeg2_ctrls, |
165 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
166 | .decoded_fmts = visl_decoded_fmts, |
167 | }, |
168 | { |
169 | .pixelformat = V4L2_PIX_FMT_VP8_FRAME, |
170 | .frmsize = { |
171 | .min_width = 64, |
172 | .max_width = 16383, |
173 | .step_width = 1, |
174 | .min_height = 64, |
175 | .max_height = 16383, |
176 | .step_height = 1, |
177 | }, |
178 | .ctrls = &visl_vp8_ctrls, |
179 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
180 | .decoded_fmts = visl_decoded_fmts, |
181 | }, |
182 | { |
183 | .pixelformat = V4L2_PIX_FMT_VP9_FRAME, |
184 | .frmsize = { |
185 | .min_width = 64, |
186 | .max_width = 8192, |
187 | .step_width = 1, |
188 | .min_height = 64, |
189 | .max_height = 4352, |
190 | .step_height = 1, |
191 | }, |
192 | .ctrls = &visl_vp9_ctrls, |
193 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
194 | .decoded_fmts = visl_decoded_fmts, |
195 | }, |
196 | { |
197 | .pixelformat = V4L2_PIX_FMT_H264_SLICE, |
198 | .frmsize = { |
199 | .min_width = 64, |
200 | .max_width = 4096, |
201 | .step_width = 1, |
202 | .min_height = 64, |
203 | .max_height = 2304, |
204 | .step_height = 1, |
205 | }, |
206 | .ctrls = &visl_h264_ctrls, |
207 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
208 | .decoded_fmts = visl_decoded_fmts, |
209 | }, |
210 | { |
211 | .pixelformat = V4L2_PIX_FMT_HEVC_SLICE, |
212 | .frmsize = { |
213 | .min_width = 64, |
214 | .max_width = 4096, |
215 | .step_width = 1, |
216 | .min_height = 64, |
217 | .max_height = 2304, |
218 | .step_height = 1, |
219 | }, |
220 | .ctrls = &visl_hevc_ctrls, |
221 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
222 | .decoded_fmts = visl_decoded_fmts, |
223 | }, |
224 | { |
225 | .pixelformat = V4L2_PIX_FMT_AV1_FRAME, |
226 | .frmsize = { |
227 | .min_width = 64, |
228 | .max_width = 4096, |
229 | .step_width = 1, |
230 | .min_height = 64, |
231 | .max_height = 2304, |
232 | .step_height = 1, |
233 | }, |
234 | .ctrls = &visl_av1_ctrls, |
235 | .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts), |
236 | .decoded_fmts = visl_decoded_fmts, |
237 | }, |
238 | |
239 | }; |
240 | |
241 | const size_t num_coded_fmts = ARRAY_SIZE(visl_coded_fmts); |
242 | |
243 | static const struct visl_coded_format_desc* |
244 | visl_find_coded_fmt_desc(u32 fourcc) |
245 | { |
246 | unsigned int i; |
247 | |
248 | for (i = 0; i < ARRAY_SIZE(visl_coded_fmts); i++) { |
249 | if (visl_coded_fmts[i].pixelformat == fourcc) |
250 | return &visl_coded_fmts[i]; |
251 | } |
252 | |
253 | return NULL; |
254 | } |
255 | |
256 | static void visl_init_fmt(struct v4l2_format *f, u32 fourcc) |
257 | { memset(f, 0, sizeof(*f)); |
258 | f->fmt.pix_mp.pixelformat = fourcc; |
259 | f->fmt.pix_mp.field = V4L2_FIELD_NONE; |
260 | f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; |
261 | f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
262 | f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; |
263 | f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; |
264 | } |
265 | |
266 | static void visl_reset_coded_fmt(struct visl_ctx *ctx) |
267 | { |
268 | struct v4l2_format *f = &ctx->coded_fmt; |
269 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; |
270 | |
271 | ctx->coded_format_desc = &visl_coded_fmts[0]; |
272 | visl_init_fmt(f, fourcc: ctx->coded_format_desc->pixelformat); |
273 | |
274 | f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
275 | f->fmt.pix_mp.width = ctx->coded_format_desc->frmsize.min_width; |
276 | f->fmt.pix_mp.height = ctx->coded_format_desc->frmsize.min_height; |
277 | |
278 | pix_mp->num_planes = 1; |
279 | pix_mp->plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * 8; |
280 | |
281 | dprintk(ctx->dev, "OUTPUT format was set to:\n" ); |
282 | visl_print_fmt(ctx, f: &ctx->coded_fmt); |
283 | |
284 | visl_set_current_codec(ctx); |
285 | } |
286 | |
287 | static int visl_reset_decoded_fmt(struct visl_ctx *ctx) |
288 | { |
289 | struct v4l2_format *f = &ctx->decoded_fmt; |
290 | u32 decoded_fmt = ctx->coded_format_desc[0].decoded_fmts[0]; |
291 | |
292 | visl_init_fmt(f, fourcc: decoded_fmt); |
293 | |
294 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
295 | |
296 | v4l2_fill_pixfmt_mp(pixfmt: &f->fmt.pix_mp, |
297 | pixelformat: ctx->coded_format_desc->decoded_fmts[0], |
298 | width: ctx->coded_fmt.fmt.pix_mp.width, |
299 | height: ctx->coded_fmt.fmt.pix_mp.height); |
300 | |
301 | dprintk(ctx->dev, "CAPTURE format was set to:\n" ); |
302 | visl_print_fmt(ctx, f: &ctx->decoded_fmt); |
303 | |
304 | return visl_tpg_init(ctx); |
305 | } |
306 | |
307 | int visl_set_default_format(struct visl_ctx *ctx) |
308 | { |
309 | visl_reset_coded_fmt(ctx); |
310 | return visl_reset_decoded_fmt(ctx); |
311 | } |
312 | |
313 | static struct visl_q_data *get_q_data(struct visl_ctx *ctx, |
314 | enum v4l2_buf_type type) |
315 | { |
316 | switch (type) { |
317 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
318 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
319 | return &ctx->q_data[V4L2_M2M_SRC]; |
320 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
321 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
322 | return &ctx->q_data[V4L2_M2M_DST]; |
323 | default: |
324 | break; |
325 | } |
326 | return NULL; |
327 | } |
328 | |
329 | static int visl_querycap(struct file *file, void *priv, |
330 | struct v4l2_capability *cap) |
331 | { |
332 | strscpy(cap->driver, VISL_NAME, sizeof(cap->driver)); |
333 | strscpy(cap->card, VISL_NAME, sizeof(cap->card)); |
334 | snprintf(buf: cap->bus_info, size: sizeof(cap->bus_info), |
335 | fmt: "platform:%s" , VISL_NAME); |
336 | |
337 | return 0; |
338 | } |
339 | |
340 | static int visl_enum_fmt_vid_cap(struct file *file, void *priv, |
341 | struct v4l2_fmtdesc *f) |
342 | { |
343 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
344 | |
345 | if (f->index >= ctx->coded_format_desc->num_decoded_fmts) |
346 | return -EINVAL; |
347 | |
348 | f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index]; |
349 | return 0; |
350 | } |
351 | |
352 | static int visl_enum_fmt_vid_out(struct file *file, void *priv, |
353 | struct v4l2_fmtdesc *f) |
354 | { |
355 | if (f->index >= ARRAY_SIZE(visl_coded_fmts)) |
356 | return -EINVAL; |
357 | |
358 | f->pixelformat = visl_coded_fmts[f->index].pixelformat; |
359 | return 0; |
360 | } |
361 | |
362 | static int visl_g_fmt_vid_cap(struct file *file, void *priv, |
363 | struct v4l2_format *f) |
364 | { |
365 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
366 | *f = ctx->decoded_fmt; |
367 | |
368 | return 0; |
369 | } |
370 | |
371 | static int visl_g_fmt_vid_out(struct file *file, void *priv, |
372 | struct v4l2_format *f) |
373 | { |
374 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
375 | |
376 | *f = ctx->coded_fmt; |
377 | return 0; |
378 | } |
379 | |
380 | static int visl_try_fmt_vid_cap(struct file *file, void *priv, |
381 | struct v4l2_format *f) |
382 | { |
383 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; |
384 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
385 | const struct visl_coded_format_desc *coded_desc; |
386 | unsigned int i; |
387 | |
388 | coded_desc = ctx->coded_format_desc; |
389 | |
390 | for (i = 0; i < coded_desc->num_decoded_fmts; i++) { |
391 | if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) |
392 | break; |
393 | } |
394 | |
395 | if (i == coded_desc->num_decoded_fmts) |
396 | pix_mp->pixelformat = coded_desc->decoded_fmts[0]; |
397 | |
398 | v4l2_apply_frmsize_constraints(width: &pix_mp->width, |
399 | height: &pix_mp->height, |
400 | frmsize: &coded_desc->frmsize); |
401 | |
402 | v4l2_fill_pixfmt_mp(pixfmt: pix_mp, pixelformat: pix_mp->pixelformat, |
403 | width: pix_mp->width, height: pix_mp->height); |
404 | |
405 | pix_mp->field = V4L2_FIELD_NONE; |
406 | |
407 | return 0; |
408 | } |
409 | |
410 | static int visl_try_fmt_vid_out(struct file *file, void *priv, |
411 | struct v4l2_format *f) |
412 | { |
413 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; |
414 | const struct visl_coded_format_desc *coded_desc; |
415 | |
416 | coded_desc = visl_find_coded_fmt_desc(fourcc: pix_mp->pixelformat); |
417 | if (!coded_desc) { |
418 | pix_mp->pixelformat = visl_coded_fmts[0].pixelformat; |
419 | coded_desc = &visl_coded_fmts[0]; |
420 | } |
421 | |
422 | v4l2_apply_frmsize_constraints(width: &pix_mp->width, |
423 | height: &pix_mp->height, |
424 | frmsize: &coded_desc->frmsize); |
425 | |
426 | pix_mp->field = V4L2_FIELD_NONE; |
427 | pix_mp->num_planes = 1; |
428 | |
429 | if (pix_mp->plane_fmt[0].sizeimage == 0) |
430 | pix_mp->plane_fmt[0].sizeimage = max(MIN_CODED_SZ, |
431 | pix_mp->width * pix_mp->height * 3); |
432 | |
433 | return 0; |
434 | } |
435 | |
436 | static int visl_s_fmt_vid_out(struct file *file, void *priv, |
437 | struct v4l2_format *f) |
438 | { |
439 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
440 | struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; |
441 | const struct visl_coded_format_desc *desc; |
442 | struct vb2_queue *peer_vq; |
443 | int ret; |
444 | |
445 | peer_vq = v4l2_m2m_get_vq(m2m_ctx, type: V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); |
446 | if (vb2_is_busy(q: peer_vq)) |
447 | return -EBUSY; |
448 | |
449 | dprintk(ctx->dev, "Trying to set the OUTPUT format to:\n" ); |
450 | visl_print_fmt(ctx, f); |
451 | |
452 | ret = visl_try_fmt_vid_out(file, priv, f); |
453 | if (ret) |
454 | return ret; |
455 | |
456 | desc = visl_find_coded_fmt_desc(fourcc: f->fmt.pix_mp.pixelformat); |
457 | ctx->coded_format_desc = desc; |
458 | ctx->coded_fmt = *f; |
459 | |
460 | ret = visl_reset_decoded_fmt(ctx); |
461 | if (ret) |
462 | return ret; |
463 | |
464 | ctx->decoded_fmt.fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; |
465 | ctx->decoded_fmt.fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; |
466 | ctx->decoded_fmt.fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; |
467 | ctx->decoded_fmt.fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; |
468 | |
469 | dprintk(ctx->dev, "OUTPUT format was set to:\n" ); |
470 | visl_print_fmt(ctx, f: &ctx->coded_fmt); |
471 | |
472 | visl_set_current_codec(ctx); |
473 | return 0; |
474 | } |
475 | |
476 | static int visl_s_fmt_vid_cap(struct file *file, void *priv, |
477 | struct v4l2_format *f) |
478 | { |
479 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
480 | int ret; |
481 | |
482 | dprintk(ctx->dev, "Trying to set the CAPTURE format to:\n" ); |
483 | visl_print_fmt(ctx, f); |
484 | |
485 | ret = visl_try_fmt_vid_cap(file, priv, f); |
486 | if (ret) |
487 | return ret; |
488 | |
489 | ctx->decoded_fmt = *f; |
490 | |
491 | dprintk(ctx->dev, "CAPTURE format was set to:\n" ); |
492 | visl_print_fmt(ctx, f: &ctx->decoded_fmt); |
493 | |
494 | visl_tpg_init(ctx); |
495 | return 0; |
496 | } |
497 | |
498 | static int visl_enum_framesizes(struct file *file, void *priv, |
499 | struct v4l2_frmsizeenum *fsize) |
500 | { |
501 | const struct visl_coded_format_desc *fmt; |
502 | struct visl_ctx *ctx = visl_file_to_ctx(file); |
503 | |
504 | if (fsize->index != 0) |
505 | return -EINVAL; |
506 | |
507 | fmt = visl_find_coded_fmt_desc(fourcc: fsize->pixel_format); |
508 | if (!fmt) { |
509 | dprintk(ctx->dev, |
510 | "Unsupported format for the OUTPUT queue: %d\n" , |
511 | fsize->pixel_format); |
512 | |
513 | return -EINVAL; |
514 | } |
515 | |
516 | fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; |
517 | fsize->stepwise = fmt->frmsize; |
518 | return 0; |
519 | } |
520 | |
521 | const struct v4l2_ioctl_ops visl_ioctl_ops = { |
522 | .vidioc_querycap = visl_querycap, |
523 | .vidioc_enum_framesizes = visl_enum_framesizes, |
524 | |
525 | .vidioc_enum_fmt_vid_cap = visl_enum_fmt_vid_cap, |
526 | .vidioc_g_fmt_vid_cap_mplane = visl_g_fmt_vid_cap, |
527 | .vidioc_try_fmt_vid_cap_mplane = visl_try_fmt_vid_cap, |
528 | .vidioc_s_fmt_vid_cap_mplane = visl_s_fmt_vid_cap, |
529 | |
530 | .vidioc_enum_fmt_vid_out = visl_enum_fmt_vid_out, |
531 | .vidioc_g_fmt_vid_out_mplane = visl_g_fmt_vid_out, |
532 | .vidioc_try_fmt_vid_out_mplane = visl_try_fmt_vid_out, |
533 | .vidioc_s_fmt_vid_out_mplane = visl_s_fmt_vid_out, |
534 | |
535 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
536 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
537 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, |
538 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
539 | .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, |
540 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, |
541 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
542 | |
543 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
544 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
545 | |
546 | .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, |
547 | .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, |
548 | |
549 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
550 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
551 | }; |
552 | |
553 | static int visl_queue_setup(struct vb2_queue *vq, |
554 | unsigned int *nbuffers, |
555 | unsigned int *num_planes, |
556 | unsigned int sizes[], |
557 | struct device *alloc_devs[]) |
558 | { |
559 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vq); |
560 | struct v4l2_format *f; |
561 | u32 i; |
562 | char *qname; |
563 | |
564 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) { |
565 | f = &ctx->coded_fmt; |
566 | qname = "Output" ; |
567 | } else { |
568 | f = &ctx->decoded_fmt; |
569 | qname = "Capture" ; |
570 | } |
571 | |
572 | if (*num_planes) { |
573 | if (*num_planes != f->fmt.pix_mp.num_planes) |
574 | return -EINVAL; |
575 | |
576 | for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { |
577 | if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage) |
578 | return -EINVAL; |
579 | } |
580 | } else { |
581 | *num_planes = f->fmt.pix_mp.num_planes; |
582 | for (i = 0; i < f->fmt.pix_mp.num_planes; i++) |
583 | sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; |
584 | } |
585 | |
586 | dprintk(ctx->dev, "%s: %d buffer(s) requested, num_planes=%d.\n" , |
587 | qname, *nbuffers, *num_planes); |
588 | |
589 | for (i = 0; i < f->fmt.pix_mp.num_planes; i++) |
590 | dprintk(ctx->dev, "plane[%d].sizeimage=%d\n" , |
591 | i, f->fmt.pix_mp.plane_fmt[i].sizeimage); |
592 | |
593 | return 0; |
594 | } |
595 | |
596 | static void visl_queue_cleanup(struct vb2_queue *vq, u32 state) |
597 | { |
598 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vq); |
599 | struct vb2_v4l2_buffer *vbuf; |
600 | |
601 | dprintk(ctx->dev, "Cleaning up queues\n" ); |
602 | for (;;) { |
603 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) |
604 | vbuf = v4l2_m2m_src_buf_remove(m2m_ctx: ctx->fh.m2m_ctx); |
605 | else |
606 | vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx: ctx->fh.m2m_ctx); |
607 | |
608 | if (!vbuf) |
609 | break; |
610 | |
611 | v4l2_ctrl_request_complete(req: vbuf->vb2_buf.req_obj.req, |
612 | parent: &ctx->hdl); |
613 | dprintk(ctx->dev, "Marked request %p as complete\n" , |
614 | vbuf->vb2_buf.req_obj.req); |
615 | |
616 | v4l2_m2m_buf_done(buf: vbuf, state); |
617 | dprintk(ctx->dev, |
618 | "Marked buffer %llu as done, state is %d\n" , |
619 | vbuf->vb2_buf.timestamp, |
620 | state); |
621 | } |
622 | } |
623 | |
624 | static int visl_buf_out_validate(struct vb2_buffer *vb) |
625 | { |
626 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
627 | |
628 | vbuf->field = V4L2_FIELD_NONE; |
629 | return 0; |
630 | } |
631 | |
632 | static int visl_buf_prepare(struct vb2_buffer *vb) |
633 | { |
634 | struct vb2_queue *vq = vb->vb2_queue; |
635 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vq); |
636 | u32 plane_sz = vb2_plane_size(vb, plane_no: 0); |
637 | struct v4l2_pix_format *pix_fmt; |
638 | |
639 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) { |
640 | pix_fmt = &ctx->coded_fmt.fmt.pix; |
641 | } else { |
642 | pix_fmt = &ctx->decoded_fmt.fmt.pix; |
643 | vb2_set_plane_payload(vb, plane_no: 0, size: pix_fmt->sizeimage); |
644 | } |
645 | |
646 | if (plane_sz < pix_fmt->sizeimage) { |
647 | v4l2_err(&ctx->dev->v4l2_dev, "plane[0] size is %d, sizeimage is %d\n" , |
648 | plane_sz, pix_fmt->sizeimage); |
649 | return -EINVAL; |
650 | } |
651 | |
652 | return 0; |
653 | } |
654 | |
655 | static int visl_start_streaming(struct vb2_queue *vq, unsigned int count) |
656 | { |
657 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vq); |
658 | struct visl_q_data *q_data = get_q_data(ctx, type: vq->type); |
659 | int rc = 0; |
660 | |
661 | if (!q_data) { |
662 | rc = -EINVAL; |
663 | goto err; |
664 | } |
665 | |
666 | q_data->sequence = 0; |
667 | |
668 | if (V4L2_TYPE_IS_CAPTURE(vq->type)) { |
669 | ctx->capture_streamon_jiffies = get_jiffies_64(); |
670 | return 0; |
671 | } |
672 | |
673 | if (WARN_ON(!ctx->coded_format_desc)) { |
674 | rc = -EINVAL; |
675 | goto err; |
676 | } |
677 | |
678 | return 0; |
679 | |
680 | err: |
681 | visl_queue_cleanup(vq, state: VB2_BUF_STATE_QUEUED); |
682 | return rc; |
683 | } |
684 | |
685 | static void visl_stop_streaming(struct vb2_queue *vq) |
686 | { |
687 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vq); |
688 | |
689 | dprintk(ctx->dev, "Stop streaming\n" ); |
690 | visl_queue_cleanup(vq, state: VB2_BUF_STATE_ERROR); |
691 | |
692 | if (!keep_bitstream_buffers) |
693 | visl_debugfs_clear_bitstream(dev: ctx->dev); |
694 | } |
695 | |
696 | static void visl_buf_queue(struct vb2_buffer *vb) |
697 | { |
698 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
699 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vb->vb2_queue); |
700 | |
701 | v4l2_m2m_buf_queue(m2m_ctx: ctx->fh.m2m_ctx, vbuf); |
702 | } |
703 | |
704 | static void visl_buf_request_complete(struct vb2_buffer *vb) |
705 | { |
706 | struct visl_ctx *ctx = vb2_get_drv_priv(q: vb->vb2_queue); |
707 | |
708 | v4l2_ctrl_request_complete(req: vb->req_obj.req, parent: &ctx->hdl); |
709 | } |
710 | |
711 | static const struct vb2_ops visl_qops = { |
712 | .queue_setup = visl_queue_setup, |
713 | .buf_out_validate = visl_buf_out_validate, |
714 | .buf_prepare = visl_buf_prepare, |
715 | .buf_queue = visl_buf_queue, |
716 | .start_streaming = visl_start_streaming, |
717 | .stop_streaming = visl_stop_streaming, |
718 | .wait_prepare = vb2_ops_wait_prepare, |
719 | .wait_finish = vb2_ops_wait_finish, |
720 | .buf_request_complete = visl_buf_request_complete, |
721 | }; |
722 | |
723 | int visl_queue_init(void *priv, struct vb2_queue *src_vq, |
724 | struct vb2_queue *dst_vq) |
725 | { |
726 | struct visl_ctx *ctx = priv; |
727 | int ret; |
728 | |
729 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
730 | src_vq->io_modes = VB2_MMAP | VB2_DMABUF; |
731 | src_vq->drv_priv = ctx; |
732 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
733 | src_vq->ops = &visl_qops; |
734 | src_vq->mem_ops = &vb2_vmalloc_memops; |
735 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
736 | src_vq->lock = &ctx->vb_mutex; |
737 | src_vq->supports_requests = true; |
738 | src_vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; |
739 | |
740 | ret = vb2_queue_init(q: src_vq); |
741 | if (ret) |
742 | return ret; |
743 | |
744 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
745 | dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; |
746 | dst_vq->drv_priv = ctx; |
747 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
748 | dst_vq->ops = &visl_qops; |
749 | dst_vq->mem_ops = &vb2_vmalloc_memops; |
750 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
751 | dst_vq->lock = &ctx->vb_mutex; |
752 | |
753 | return vb2_queue_init(q: dst_vq); |
754 | } |
755 | |
756 | int visl_request_validate(struct media_request *req) |
757 | { |
758 | struct media_request_object *obj; |
759 | struct visl_ctx *ctx = NULL; |
760 | unsigned int count; |
761 | |
762 | list_for_each_entry(obj, &req->objects, list) { |
763 | struct vb2_buffer *vb; |
764 | |
765 | if (vb2_request_object_is_buffer(obj)) { |
766 | vb = container_of(obj, struct vb2_buffer, req_obj); |
767 | ctx = vb2_get_drv_priv(q: vb->vb2_queue); |
768 | |
769 | break; |
770 | } |
771 | } |
772 | |
773 | if (!ctx) |
774 | return -ENOENT; |
775 | |
776 | count = vb2_request_buffer_cnt(req); |
777 | if (!count) { |
778 | v4l2_err(&ctx->dev->v4l2_dev, |
779 | "No buffer was provided with the request\n" ); |
780 | return -ENOENT; |
781 | } else if (count > 1) { |
782 | v4l2_err(&ctx->dev->v4l2_dev, |
783 | "More than one buffer was provided with the request\n" ); |
784 | return -EINVAL; |
785 | } |
786 | |
787 | return vb2_request_validate(req); |
788 | } |
789 | |