media: vicodec: ensure comp frame pointer kept in range
[linux-block.git] / drivers / media / platform / vicodec / vicodec-core.c
CommitLineData
256bf813
HV
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * A virtual codec example device.
4 *
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 *
7 * This is a virtual codec device driver for testing the codec framework.
8 * It simulates a device that uses memory buffers for both source and
9 * destination and encodes or decodes the data.
10 */
11
12#include <linux/module.h>
13#include <linux/delay.h>
14#include <linux/fs.h>
15#include <linux/sched.h>
16#include <linux/slab.h>
17
18#include <linux/platform_device.h>
19#include <media/v4l2-mem2mem.h>
20#include <media/v4l2-device.h>
21#include <media/v4l2-ioctl.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-event.h>
24#include <media/videobuf2-vmalloc.h>
25
cd12b401 26#include "codec-v4l2-fwht.h"
256bf813
HV
27
28MODULE_DESCRIPTION("Virtual codec device");
29MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
30MODULE_LICENSE("GPL v2");
31
32static bool multiplanar;
33module_param(multiplanar, bool, 0444);
34MODULE_PARM_DESC(multiplanar,
35 " use multi-planar API instead of single-planar API");
36
37static unsigned int debug;
38module_param(debug, uint, 0644);
39MODULE_PARM_DESC(debug, " activates debug info");
40
41#define VICODEC_NAME "vicodec"
42#define MAX_WIDTH 4096U
43#define MIN_WIDTH 640U
44#define MAX_HEIGHT 2160U
7cf7b2e9 45#define MIN_HEIGHT 360U
256bf813
HV
46
47#define dprintk(dev, fmt, arg...) \
48 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
49
50
29a7a5e9
HV
51struct pixfmt_info {
52 u32 id;
53 unsigned int bytesperline_mult;
54 unsigned int sizeimage_mult;
55 unsigned int sizeimage_div;
56 unsigned int luma_step;
57 unsigned int chroma_step;
58 /* Chroma plane subsampling */
59 unsigned int width_div;
60 unsigned int height_div;
61};
62
cd12b401 63static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
8c1d02f1 64 V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1
29a7a5e9
HV
65};
66
256bf813
HV
67static void vicodec_dev_release(struct device *dev)
68{
69}
70
71static struct platform_device vicodec_pdev = {
72 .name = VICODEC_NAME,
73 .dev.release = vicodec_dev_release,
74};
75
76/* Per-queue, driver-specific private data */
77struct vicodec_q_data {
9e812549
DH
78 unsigned int coded_width;
79 unsigned int coded_height;
80 unsigned int visible_width;
81 unsigned int visible_height;
256bf813
HV
82 unsigned int sizeimage;
83 unsigned int sequence;
cd12b401 84 const struct v4l2_fwht_pixfmt_info *info;
256bf813
HV
85};
86
87enum {
88 V4L2_M2M_SRC = 0,
89 V4L2_M2M_DST = 1,
90};
91
92struct vicodec_dev {
93 struct v4l2_device v4l2_dev;
94 struct video_device enc_vfd;
95 struct video_device dec_vfd;
96#ifdef CONFIG_MEDIA_CONTROLLER
97 struct media_device mdev;
98#endif
99
100 struct mutex enc_mutex;
101 struct mutex dec_mutex;
102 spinlock_t enc_lock;
103 spinlock_t dec_lock;
104
105 struct v4l2_m2m_dev *enc_dev;
106 struct v4l2_m2m_dev *dec_dev;
107};
108
109struct vicodec_ctx {
110 struct v4l2_fh fh;
111 struct vicodec_dev *dev;
112 bool is_enc;
113 spinlock_t *lock;
114
115 struct v4l2_ctrl_handler hdl;
256bf813 116
256bf813
HV
117 struct vb2_v4l2_buffer *last_src_buf;
118 struct vb2_v4l2_buffer *last_dst_buf;
119
256bf813
HV
120 /* Source and destination queue data */
121 struct vicodec_q_data q_data[2];
cd12b401
HV
122 struct v4l2_fwht_state state;
123
256bf813
HV
124 u32 cur_buf_offset;
125 u32 comp_max_size;
126 u32 comp_size;
ddc1b085 127 u32 header_size;
256bf813 128 u32 comp_magic_cnt;
256bf813
HV
129 bool comp_has_frame;
130 bool comp_has_next_frame;
3b15f68e
DH
131 bool first_source_change_sent;
132 bool source_changed;
256bf813
HV
133};
134
256bf813
HV
135static inline struct vicodec_ctx *file2ctx(struct file *file)
136{
137 return container_of(file->private_data, struct vicodec_ctx, fh);
138}
139
140static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
141 enum v4l2_buf_type type)
142{
143 switch (type) {
144 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
145 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
146 return &ctx->q_data[V4L2_M2M_SRC];
147 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
148 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
149 return &ctx->q_data[V4L2_M2M_DST];
150 default:
151 WARN_ON(1);
152 break;
153 }
154 return NULL;
155}
156
256bf813 157static int device_process(struct vicodec_ctx *ctx,
b9bbbbfe
DH
158 struct vb2_v4l2_buffer *src_vb,
159 struct vb2_v4l2_buffer *dst_vb)
256bf813
HV
160{
161 struct vicodec_dev *dev = ctx->dev;
b9bbbbfe 162 struct vicodec_q_data *q_dst;
cd12b401 163 struct v4l2_fwht_state *state = &ctx->state;
b9bbbbfe 164 u8 *p_src, *p_dst;
256bf813
HV
165 int ret;
166
b9bbbbfe 167 q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
256bf813 168 if (ctx->is_enc)
b9bbbbfe 169 p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
256bf813 170 else
b9bbbbfe
DH
171 p_src = state->compressed_frame;
172 p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
173 if (!p_src || !p_dst) {
256bf813
HV
174 v4l2_err(&dev->v4l2_dev,
175 "Acquiring kernel pointers to buffers failed\n");
176 return -EFAULT;
177 }
178
179 if (ctx->is_enc) {
b9bbbbfe 180 struct vicodec_q_data *q_src;
256bf813 181
b9bbbbfe
DH
182 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
183 state->info = q_src->info;
184 ret = v4l2_fwht_encode(state, p_src, p_dst);
b09d8b25
HV
185 if (ret < 0)
186 return ret;
b9bbbbfe 187 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret);
256bf813 188 } else {
f863f222
DH
189 unsigned int comp_frame_size = ntohl(ctx->state.header.size);
190
191 if (comp_frame_size > ctx->comp_max_size)
192 return -EINVAL;
b9bbbbfe
DH
193 state->info = q_dst->info;
194 ret = v4l2_fwht_decode(state, p_src, p_dst);
b09d8b25 195 if (ret < 0)
256bf813 196 return ret;
b9bbbbfe 197 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
256bf813
HV
198 }
199
b9bbbbfe 200 dst_vb->sequence = q_dst->sequence++;
b9bbbbfe 201 dst_vb->flags &= ~V4L2_BUF_FLAG_LAST;
96bddd5f 202 v4l2_m2m_buf_copy_data(src_vb, dst_vb, !ctx->is_enc);
256bf813
HV
203
204 return 0;
205}
206
207/*
208 * mem2mem callbacks
209 */
ddc1b085
DH
210enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, u8 **pp, u32 sz)
211{
212 static const u8 magic[] = {
213 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
214 };
215 u8 *p = *pp;
216 u32 state;
217 u8 *header = (u8 *)&ctx->state.header;
218
219 state = VB2_BUF_STATE_DONE;
220
221 if (!ctx->header_size) {
222 state = VB2_BUF_STATE_ERROR;
223 for (; p < *pp + sz; p++) {
224 u32 copy;
225
226 p = memchr(p, magic[ctx->comp_magic_cnt],
227 *pp + sz - p);
228 if (!p) {
229 ctx->comp_magic_cnt = 0;
230 p = *pp + sz;
231 break;
232 }
233 copy = sizeof(magic) - ctx->comp_magic_cnt;
234 if (*pp + sz - p < copy)
235 copy = *pp + sz - p;
236
237 memcpy(header + ctx->comp_magic_cnt, p, copy);
238 ctx->comp_magic_cnt += copy;
239 if (!memcmp(header, magic, ctx->comp_magic_cnt)) {
240 p += copy;
241 state = VB2_BUF_STATE_DONE;
242 break;
243 }
244 ctx->comp_magic_cnt = 0;
245 }
246 if (ctx->comp_magic_cnt < sizeof(magic)) {
247 *pp = p;
248 return state;
249 }
250 ctx->header_size = sizeof(magic);
251 }
252
253 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
254 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size;
255
256 if (*pp + sz - p < copy)
257 copy = *pp + sz - p;
258
259 memcpy(header + ctx->header_size, p, copy);
260 p += copy;
261 ctx->header_size += copy;
262 }
263 *pp = p;
264 return state;
265}
256bf813
HV
266
267/* device_run() - prepares and starts the device */
268static void device_run(void *priv)
269{
270 static const struct v4l2_event eos_event = {
271 .type = V4L2_EVENT_EOS
272 };
273 struct vicodec_ctx *ctx = priv;
274 struct vicodec_dev *dev = ctx->dev;
275 struct vb2_v4l2_buffer *src_buf, *dst_buf;
b9bbbbfe 276 struct vicodec_q_data *q_src;
256bf813
HV
277 u32 state;
278
279 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
280 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
b9bbbbfe 281 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
256bf813
HV
282
283 state = VB2_BUF_STATE_DONE;
284 if (device_process(ctx, src_buf, dst_buf))
285 state = VB2_BUF_STATE_ERROR;
286 ctx->last_dst_buf = dst_buf;
287
288 spin_lock(ctx->lock);
289 if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
290 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
291 v4l2_event_queue_fh(&ctx->fh, &eos_event);
292 }
293 if (ctx->is_enc) {
b9bbbbfe 294 src_buf->sequence = q_src->sequence++;
256bf813
HV
295 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
296 v4l2_m2m_buf_done(src_buf, state);
297 } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
b9bbbbfe 298 src_buf->sequence = q_src->sequence++;
256bf813
HV
299 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
300 v4l2_m2m_buf_done(src_buf, state);
301 ctx->cur_buf_offset = 0;
302 ctx->comp_has_next_frame = false;
303 }
304 v4l2_m2m_buf_done(dst_buf, state);
305 ctx->comp_size = 0;
ddc1b085 306 ctx->header_size = 0;
256bf813
HV
307 ctx->comp_magic_cnt = 0;
308 ctx->comp_has_frame = false;
309 spin_unlock(ctx->lock);
310
311 if (ctx->is_enc)
312 v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
313 else
314 v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
315}
316
b9bbbbfe 317static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
256bf813
HV
318{
319 struct vb2_v4l2_buffer *src_buf;
b9bbbbfe 320 struct vicodec_q_data *q_src;
256bf813 321
b9bbbbfe 322 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
256bf813
HV
323 spin_lock(ctx->lock);
324 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
b9bbbbfe 325 src_buf->sequence = q_src->sequence++;
256bf813
HV
326 v4l2_m2m_buf_done(src_buf, state);
327 ctx->cur_buf_offset = 0;
328 spin_unlock(ctx->lock);
329}
330
3b15f68e
DH
331static const struct v4l2_fwht_pixfmt_info *
332info_from_header(const struct fwht_cframe_hdr *p_hdr)
333{
334 unsigned int flags = ntohl(p_hdr->flags);
335 unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
336 unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
337 unsigned int components_num = 3;
338 unsigned int pixenc = 0;
339 unsigned int version = ntohl(p_hdr->version);
340
341 if (version == FWHT_VERSION) {
342 components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
343 FWHT_FL_COMPONENTS_NUM_OFFSET);
344 pixenc = (flags & FWHT_FL_PIXENC_MSK);
345 }
346 return v4l2_fwht_default_fmt(width_div, height_div,
347 components_num, pixenc, 0);
348}
349
350static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr)
351{
352 const struct v4l2_fwht_pixfmt_info *info;
353 unsigned int w = ntohl(p_hdr->width);
354 unsigned int h = ntohl(p_hdr->height);
355 unsigned int version = ntohl(p_hdr->version);
356 unsigned int flags = ntohl(p_hdr->flags);
357
358 if (!version || version > FWHT_VERSION)
359 return false;
360
361 if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT)
362 return false;
363
364 if (version == FWHT_VERSION) {
365 unsigned int components_num = 1 +
366 ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
367 FWHT_FL_COMPONENTS_NUM_OFFSET);
368 unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK;
369
370 if (components_num == 0 || components_num > 4 || !pixenc)
371 return false;
372 }
373
374 info = info_from_header(p_hdr);
375 if (!info)
376 return false;
377 return true;
378}
379
380static void update_capture_data_from_header(struct vicodec_ctx *ctx)
381{
382 struct vicodec_q_data *q_dst = get_q_data(ctx,
383 V4L2_BUF_TYPE_VIDEO_CAPTURE);
384 const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
385 const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr);
386 unsigned int flags = ntohl(p_hdr->flags);
387 unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
388 unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
389
390 q_dst->info = info;
391 q_dst->visible_width = ntohl(p_hdr->width);
392 q_dst->visible_height = ntohl(p_hdr->height);
393 q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div);
394 q_dst->coded_height = vic_round_dim(q_dst->visible_height,
395 hdr_height_div);
396
397 q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height *
398 q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div;
399 ctx->state.colorspace = ntohl(p_hdr->colorspace);
400
401 ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
402 ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
403 ctx->state.quantization = ntohl(p_hdr->quantization);
404}
405
406static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf,
407 const struct vb2_v4l2_buffer *src_buf,
408 struct vicodec_ctx *ctx)
409{
410 struct vicodec_q_data *q_dst = get_q_data(ctx,
411 V4L2_BUF_TYPE_VIDEO_CAPTURE);
412
413 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
414 dst_buf->sequence = q_dst->sequence++;
415
416 v4l2_m2m_buf_copy_data(src_buf, dst_buf, !ctx->is_enc);
417 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
418 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
419}
420
256bf813
HV
421static int job_ready(void *priv)
422{
423 static const u8 magic[] = {
424 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
425 };
426 struct vicodec_ctx *ctx = priv;
427 struct vb2_v4l2_buffer *src_buf;
b9bbbbfe 428 u8 *p_src;
256bf813
HV
429 u8 *p;
430 u32 sz;
431 u32 state;
3b15f68e
DH
432 struct vicodec_q_data *q_dst = get_q_data(ctx,
433 V4L2_BUF_TYPE_VIDEO_CAPTURE);
434 unsigned int flags;
435 unsigned int hdr_width_div;
436 unsigned int hdr_height_div;
437 unsigned int max_to_copy;
438 unsigned int comp_frame_size;
439
440 if (ctx->source_changed)
441 return 0;
256bf813
HV
442 if (ctx->is_enc || ctx->comp_has_frame)
443 return 1;
444
445restart:
446 ctx->comp_has_next_frame = false;
447 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
448 if (!src_buf)
449 return 0;
b9bbbbfe 450 p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
256bf813 451 sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
b9bbbbfe 452 p = p_src + ctx->cur_buf_offset;
256bf813
HV
453
454 state = VB2_BUF_STATE_DONE;
455
ddc1b085
DH
456 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
457 state = get_next_header(ctx, &p, p_src + sz - p);
458 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
b9bbbbfe 459 job_remove_src_buf(ctx, state);
256bf813
HV
460 goto restart;
461 }
3b15f68e 462 }
256bf813 463
3b15f68e 464 comp_frame_size = ntohl(ctx->state.header.size);
ddc1b085 465
3b15f68e
DH
466 /*
467 * The current scanned frame might be the first frame of a new
468 * resolution so its size might be larger than ctx->comp_max_size.
469 * In that case it is copied up to the current buffer capacity and
470 * the copy will continue after allocating new large enough buffer
471 * when restreaming
472 */
473 max_to_copy = min(comp_frame_size, ctx->comp_max_size);
474
475 if (ctx->comp_size < max_to_copy) {
476 u32 copy = max_to_copy - ctx->comp_size;
256bf813 477
b9bbbbfe
DH
478 if (copy > p_src + sz - p)
479 copy = p_src + sz - p;
480
cd12b401 481 memcpy(ctx->state.compressed_frame + ctx->comp_size,
256bf813
HV
482 p, copy);
483 p += copy;
484 ctx->comp_size += copy;
3b15f68e 485 if (ctx->comp_size < max_to_copy) {
b9bbbbfe 486 job_remove_src_buf(ctx, state);
256bf813
HV
487 goto restart;
488 }
489 }
b9bbbbfe 490 ctx->cur_buf_offset = p - p_src;
3b15f68e
DH
491 if (ctx->comp_size == comp_frame_size)
492 ctx->comp_has_frame = true;
256bf813 493 ctx->comp_has_next_frame = false;
3b15f68e
DH
494 if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >=
495 sizeof(struct fwht_cframe_hdr)) {
21abebf0 496 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
256bf813
HV
497 u32 frame_size = ntohl(p_hdr->size);
498 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
499
500 if (!memcmp(p, magic, sizeof(magic)))
501 ctx->comp_has_next_frame = remaining >= frame_size;
502 }
3b15f68e
DH
503 /*
504 * if the header is invalid the device_run will just drop the frame
505 * with an error
506 */
507 if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame)
508 return 1;
509 flags = ntohl(ctx->state.header.flags);
510 hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
511 hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
512
513 if (ntohl(ctx->state.header.width) != q_dst->visible_width ||
514 ntohl(ctx->state.header.height) != q_dst->visible_height ||
515 !q_dst->info ||
516 hdr_width_div != q_dst->info->width_div ||
517 hdr_height_div != q_dst->info->height_div) {
518 static const struct v4l2_event rs_event = {
519 .type = V4L2_EVENT_SOURCE_CHANGE,
520 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
521 };
522
523 struct vb2_v4l2_buffer *dst_buf =
524 v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
525
526 update_capture_data_from_header(ctx);
527 ctx->first_source_change_sent = true;
528 v4l2_event_queue_fh(&ctx->fh, &rs_event);
529 set_last_buffer(dst_buf, src_buf, ctx);
530 ctx->source_changed = true;
531 return 0;
532 }
256bf813
HV
533 return 1;
534}
535
256bf813
HV
536/*
537 * video ioctls
538 */
539
cd12b401 540static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
256bf813 541{
cd12b401
HV
542 const struct v4l2_fwht_pixfmt_info *info =
543 v4l2_fwht_find_pixfmt(fmt);
256bf813 544
cd12b401
HV
545 if (!info)
546 info = v4l2_fwht_get_pixfmt(0);
547 return info;
256bf813
HV
548}
549
550static int vidioc_querycap(struct file *file, void *priv,
551 struct v4l2_capability *cap)
552{
553 strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1);
554 strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
555 snprintf(cap->bus_info, sizeof(cap->bus_info),
556 "platform:%s", VICODEC_NAME);
256bf813
HV
557 return 0;
558}
559
5fbd0729
DH
560static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
561 bool is_out)
256bf813 562{
5fbd0729 563 bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out);
256bf813
HV
564
565 if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
566 return -EINVAL;
567 if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
568 return -EINVAL;
256bf813 569
cd12b401
HV
570 if (is_uncomp) {
571 const struct v4l2_fwht_pixfmt_info *info =
5fbd0729
DH
572 get_q_data(ctx, f->type)->info;
573
3b15f68e 574 if (!info || ctx->is_enc)
5fbd0729
DH
575 info = v4l2_fwht_get_pixfmt(f->index);
576 else
577 info = v4l2_fwht_default_fmt(info->width_div,
578 info->height_div,
579 info->components_num,
580 info->pixenc,
581 f->index);
cd12b401
HV
582 if (!info)
583 return -EINVAL;
584 f->pixelformat = info->id;
585 } else {
586 if (f->index)
587 return -EINVAL;
256bf813 588 f->pixelformat = V4L2_PIX_FMT_FWHT;
cd12b401 589 }
256bf813
HV
590 return 0;
591}
592
593static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
594 struct v4l2_fmtdesc *f)
595{
596 struct vicodec_ctx *ctx = file2ctx(file);
597
5fbd0729 598 return enum_fmt(f, ctx, false);
256bf813
HV
599}
600
601static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
602 struct v4l2_fmtdesc *f)
603{
604 struct vicodec_ctx *ctx = file2ctx(file);
605
5fbd0729 606 return enum_fmt(f, ctx, true);
256bf813
HV
607}
608
609static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
610{
611 struct vb2_queue *vq;
612 struct vicodec_q_data *q_data;
613 struct v4l2_pix_format_mplane *pix_mp;
614 struct v4l2_pix_format *pix;
cd12b401 615 const struct v4l2_fwht_pixfmt_info *info;
256bf813
HV
616
617 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
618 if (!vq)
619 return -EINVAL;
620
621 q_data = get_q_data(ctx, f->type);
29a7a5e9 622 info = q_data->info;
256bf813 623
3b15f68e
DH
624 if (!info)
625 info = v4l2_fwht_get_pixfmt(0);
626
256bf813
HV
627 switch (f->type) {
628 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
629 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
630 if (multiplanar)
631 return -EINVAL;
632 pix = &f->fmt.pix;
9e812549
DH
633 pix->width = q_data->coded_width;
634 pix->height = q_data->coded_height;
256bf813 635 pix->field = V4L2_FIELD_NONE;
29a7a5e9 636 pix->pixelformat = info->id;
9e812549
DH
637 pix->bytesperline = q_data->coded_width *
638 info->bytesperline_mult;
256bf813 639 pix->sizeimage = q_data->sizeimage;
cd12b401
HV
640 pix->colorspace = ctx->state.colorspace;
641 pix->xfer_func = ctx->state.xfer_func;
642 pix->ycbcr_enc = ctx->state.ycbcr_enc;
643 pix->quantization = ctx->state.quantization;
256bf813
HV
644 break;
645
646 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
647 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
648 if (!multiplanar)
649 return -EINVAL;
650 pix_mp = &f->fmt.pix_mp;
9e812549
DH
651 pix_mp->width = q_data->coded_width;
652 pix_mp->height = q_data->coded_height;
256bf813 653 pix_mp->field = V4L2_FIELD_NONE;
29a7a5e9 654 pix_mp->pixelformat = info->id;
256bf813 655 pix_mp->num_planes = 1;
29a7a5e9 656 pix_mp->plane_fmt[0].bytesperline =
9e812549 657 q_data->coded_width * info->bytesperline_mult;
256bf813 658 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
cd12b401
HV
659 pix_mp->colorspace = ctx->state.colorspace;
660 pix_mp->xfer_func = ctx->state.xfer_func;
661 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
662 pix_mp->quantization = ctx->state.quantization;
256bf813
HV
663 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
664 memset(pix_mp->plane_fmt[0].reserved, 0,
665 sizeof(pix_mp->plane_fmt[0].reserved));
666 break;
667 default:
668 return -EINVAL;
669 }
670 return 0;
671}
672
673static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
674 struct v4l2_format *f)
675{
676 return vidioc_g_fmt(file2ctx(file), f);
677}
678
679static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
680 struct v4l2_format *f)
681{
682 return vidioc_g_fmt(file2ctx(file), f);
683}
684
685static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
686{
687 struct v4l2_pix_format_mplane *pix_mp;
688 struct v4l2_pix_format *pix;
29a7a5e9 689 struct v4l2_plane_pix_format *plane;
cd12b401 690 const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
256bf813
HV
691
692 switch (f->type) {
693 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
694 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
695 pix = &f->fmt.pix;
29a7a5e9
HV
696 if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
697 info = find_fmt(pix->pixelformat);
9e812549
DH
698
699 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
700 pix->width = vic_round_dim(pix->width, info->width_div);
701
702 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
703 pix->height = vic_round_dim(pix->height, info->height_div);
704
256bf813 705 pix->field = V4L2_FIELD_NONE;
29a7a5e9
HV
706 pix->bytesperline =
707 pix->width * info->bytesperline_mult;
708 pix->sizeimage = pix->width * pix->height *
709 info->sizeimage_mult / info->sizeimage_div;
710 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
21abebf0 711 pix->sizeimage += sizeof(struct fwht_cframe_hdr);
256bf813
HV
712 break;
713 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
714 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
715 pix_mp = &f->fmt.pix_mp;
29a7a5e9
HV
716 plane = pix_mp->plane_fmt;
717 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
718 info = find_fmt(pix_mp->pixelformat);
719 pix_mp->num_planes = 1;
9e812549
DH
720
721 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH);
722 pix_mp->width = vic_round_dim(pix_mp->width, info->width_div);
723
724 pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT);
725 pix_mp->height = vic_round_dim(pix_mp->height,
726 info->height_div);
727
256bf813 728 pix_mp->field = V4L2_FIELD_NONE;
29a7a5e9
HV
729 plane->bytesperline =
730 pix_mp->width * info->bytesperline_mult;
731 plane->sizeimage = pix_mp->width * pix_mp->height *
732 info->sizeimage_mult / info->sizeimage_div;
733 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
21abebf0 734 plane->sizeimage += sizeof(struct fwht_cframe_hdr);
256bf813 735 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
29a7a5e9 736 memset(plane->reserved, 0, sizeof(plane->reserved));
256bf813
HV
737 break;
738 default:
739 return -EINVAL;
740 }
741
742 return 0;
743}
744
745static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
746 struct v4l2_format *f)
747{
748 struct vicodec_ctx *ctx = file2ctx(file);
749 struct v4l2_pix_format_mplane *pix_mp;
750 struct v4l2_pix_format *pix;
751
752 switch (f->type) {
753 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
754 if (multiplanar)
755 return -EINVAL;
756 pix = &f->fmt.pix;
757 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 758 find_fmt(f->fmt.pix.pixelformat)->id;
cd12b401
HV
759 pix->colorspace = ctx->state.colorspace;
760 pix->xfer_func = ctx->state.xfer_func;
761 pix->ycbcr_enc = ctx->state.ycbcr_enc;
762 pix->quantization = ctx->state.quantization;
256bf813
HV
763 break;
764 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
765 if (!multiplanar)
766 return -EINVAL;
767 pix_mp = &f->fmt.pix_mp;
768 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 769 find_fmt(pix_mp->pixelformat)->id;
cd12b401
HV
770 pix_mp->colorspace = ctx->state.colorspace;
771 pix_mp->xfer_func = ctx->state.xfer_func;
772 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
773 pix_mp->quantization = ctx->state.quantization;
256bf813
HV
774 break;
775 default:
776 return -EINVAL;
777 }
778
779 return vidioc_try_fmt(ctx, f);
780}
781
782static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
783 struct v4l2_format *f)
784{
785 struct vicodec_ctx *ctx = file2ctx(file);
786 struct v4l2_pix_format_mplane *pix_mp;
787 struct v4l2_pix_format *pix;
788
789 switch (f->type) {
790 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
791 if (multiplanar)
792 return -EINVAL;
793 pix = &f->fmt.pix;
794 pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 795 find_fmt(pix->pixelformat)->id;
256bf813
HV
796 if (!pix->colorspace)
797 pix->colorspace = V4L2_COLORSPACE_REC709;
798 break;
799 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
800 if (!multiplanar)
801 return -EINVAL;
802 pix_mp = &f->fmt.pix_mp;
803 pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 804 find_fmt(pix_mp->pixelformat)->id;
256bf813
HV
805 if (!pix_mp->colorspace)
806 pix_mp->colorspace = V4L2_COLORSPACE_REC709;
807 break;
808 default:
809 return -EINVAL;
810 }
811
812 return vidioc_try_fmt(ctx, f);
813}
814
815static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
816{
817 struct vicodec_q_data *q_data;
818 struct vb2_queue *vq;
819 bool fmt_changed = true;
820 struct v4l2_pix_format_mplane *pix_mp;
821 struct v4l2_pix_format *pix;
822
823 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
824 if (!vq)
825 return -EINVAL;
826
827 q_data = get_q_data(ctx, f->type);
828 if (!q_data)
829 return -EINVAL;
830
831 switch (f->type) {
832 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
833 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
834 pix = &f->fmt.pix;
835 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
836 fmt_changed =
3b15f68e 837 !q_data->info ||
29a7a5e9 838 q_data->info->id != pix->pixelformat ||
9e812549
DH
839 q_data->coded_width != pix->width ||
840 q_data->coded_height != pix->height;
256bf813
HV
841
842 if (vb2_is_busy(vq) && fmt_changed)
843 return -EBUSY;
844
29a7a5e9
HV
845 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
846 q_data->info = &pixfmt_fwht;
847 else
848 q_data->info = find_fmt(pix->pixelformat);
9e812549
DH
849 q_data->coded_width = pix->width;
850 q_data->coded_height = pix->height;
256bf813
HV
851 q_data->sizeimage = pix->sizeimage;
852 break;
853 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
854 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
855 pix_mp = &f->fmt.pix_mp;
856 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
857 fmt_changed =
3b15f68e 858 !q_data->info ||
29a7a5e9 859 q_data->info->id != pix_mp->pixelformat ||
9e812549
DH
860 q_data->coded_width != pix_mp->width ||
861 q_data->coded_height != pix_mp->height;
256bf813
HV
862
863 if (vb2_is_busy(vq) && fmt_changed)
864 return -EBUSY;
865
29a7a5e9
HV
866 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
867 q_data->info = &pixfmt_fwht;
868 else
869 q_data->info = find_fmt(pix_mp->pixelformat);
9e812549
DH
870 q_data->coded_width = pix_mp->width;
871 q_data->coded_height = pix_mp->height;
256bf813
HV
872 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
873 break;
874 default:
875 return -EINVAL;
876 }
9e812549
DH
877 if (q_data->visible_width > q_data->coded_width)
878 q_data->visible_width = q_data->coded_width;
879 if (q_data->visible_height > q_data->coded_height)
880 q_data->visible_height = q_data->coded_height;
881
256bf813
HV
882
883 dprintk(ctx->dev,
9e812549
DH
884 "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n",
885 f->type, q_data->coded_width, q_data->coded_height,
886 q_data->visible_width, q_data->visible_height,
887 q_data->info->id);
256bf813
HV
888
889 return 0;
890}
891
892static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
893 struct v4l2_format *f)
894{
895 int ret;
896
897 ret = vidioc_try_fmt_vid_cap(file, priv, f);
898 if (ret)
899 return ret;
900
901 return vidioc_s_fmt(file2ctx(file), f);
902}
903
904static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
905 struct v4l2_format *f)
906{
907 struct vicodec_ctx *ctx = file2ctx(file);
908 struct v4l2_pix_format_mplane *pix_mp;
909 struct v4l2_pix_format *pix;
910 int ret;
911
912 ret = vidioc_try_fmt_vid_out(file, priv, f);
913 if (ret)
914 return ret;
915
916 ret = vidioc_s_fmt(file2ctx(file), f);
917 if (!ret) {
918 switch (f->type) {
919 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
920 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
921 pix = &f->fmt.pix;
cd12b401
HV
922 ctx->state.colorspace = pix->colorspace;
923 ctx->state.xfer_func = pix->xfer_func;
924 ctx->state.ycbcr_enc = pix->ycbcr_enc;
925 ctx->state.quantization = pix->quantization;
256bf813
HV
926 break;
927 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
928 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
929 pix_mp = &f->fmt.pix_mp;
cd12b401
HV
930 ctx->state.colorspace = pix_mp->colorspace;
931 ctx->state.xfer_func = pix_mp->xfer_func;
932 ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
933 ctx->state.quantization = pix_mp->quantization;
256bf813
HV
934 break;
935 default:
936 break;
937 }
938 }
939 return ret;
940}
941
9e812549
DH
942static int vidioc_g_selection(struct file *file, void *priv,
943 struct v4l2_selection *s)
944{
945 struct vicodec_ctx *ctx = file2ctx(file);
946 struct vicodec_q_data *q_data;
947 enum v4l2_buf_type valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
948 enum v4l2_buf_type valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
949
950 if (multiplanar) {
951 valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
952 valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
953 }
954
955 q_data = get_q_data(ctx, s->type);
956 if (!q_data)
957 return -EINVAL;
958 /*
959 * encoder supports only cropping on the OUTPUT buffer
960 * decoder supports only composing on the CAPTURE buffer
961 */
962 if ((ctx->is_enc && s->type == valid_out_type) ||
963 (!ctx->is_enc && s->type == valid_cap_type)) {
964 switch (s->target) {
965 case V4L2_SEL_TGT_COMPOSE:
966 case V4L2_SEL_TGT_CROP:
967 s->r.left = 0;
968 s->r.top = 0;
969 s->r.width = q_data->visible_width;
970 s->r.height = q_data->visible_height;
971 return 0;
972 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
973 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
974 case V4L2_SEL_TGT_CROP_DEFAULT:
975 case V4L2_SEL_TGT_CROP_BOUNDS:
976 s->r.left = 0;
977 s->r.top = 0;
978 s->r.width = q_data->coded_width;
979 s->r.height = q_data->coded_height;
980 return 0;
981 }
982 }
983 return -EINVAL;
984}
985
986static int vidioc_s_selection(struct file *file, void *priv,
987 struct v4l2_selection *s)
988{
989 struct vicodec_ctx *ctx = file2ctx(file);
990 struct vicodec_q_data *q_data;
991 enum v4l2_buf_type out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
992
993 if (multiplanar)
994 out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
995
996 q_data = get_q_data(ctx, s->type);
997 if (!q_data)
998 return -EINVAL;
999
1000 if (!ctx->is_enc || s->type != out_type ||
1001 s->target != V4L2_SEL_TGT_CROP)
1002 return -EINVAL;
1003
1004 s->r.left = 0;
1005 s->r.top = 0;
1006 q_data->visible_width = clamp(s->r.width, MIN_WIDTH,
1007 q_data->coded_width);
1008 s->r.width = q_data->visible_width;
1009 q_data->visible_height = clamp(s->r.height, MIN_HEIGHT,
1010 q_data->coded_height);
1011 s->r.height = q_data->visible_height;
1012 return 0;
1013}
1014
256bf813
HV
1015static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
1016{
1017 static const struct v4l2_event eos_event = {
1018 .type = V4L2_EVENT_EOS
1019 };
1020
1021 spin_lock(ctx->lock);
1022 ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
1023 if (!ctx->last_src_buf && ctx->last_dst_buf) {
1024 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
1025 v4l2_event_queue_fh(&ctx->fh, &eos_event);
1026 }
1027 spin_unlock(ctx->lock);
1028}
1029
1030static int vicodec_try_encoder_cmd(struct file *file, void *fh,
1031 struct v4l2_encoder_cmd *ec)
1032{
1033 if (ec->cmd != V4L2_ENC_CMD_STOP)
1034 return -EINVAL;
1035
1036 if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
1037 return -EINVAL;
1038
1039 return 0;
1040}
1041
1042static int vicodec_encoder_cmd(struct file *file, void *fh,
1043 struct v4l2_encoder_cmd *ec)
1044{
1045 struct vicodec_ctx *ctx = file2ctx(file);
1046 int ret;
1047
1048 ret = vicodec_try_encoder_cmd(file, fh, ec);
1049 if (ret < 0)
1050 return ret;
1051
1052 vicodec_mark_last_buf(ctx);
1053 return 0;
1054}
1055
1056static int vicodec_try_decoder_cmd(struct file *file, void *fh,
1057 struct v4l2_decoder_cmd *dc)
1058{
1059 if (dc->cmd != V4L2_DEC_CMD_STOP)
1060 return -EINVAL;
1061
1062 if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
1063 return -EINVAL;
1064
1065 if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
1066 return -EINVAL;
1067
1068 return 0;
1069}
1070
1071static int vicodec_decoder_cmd(struct file *file, void *fh,
1072 struct v4l2_decoder_cmd *dc)
1073{
1074 struct vicodec_ctx *ctx = file2ctx(file);
1075 int ret;
1076
1077 ret = vicodec_try_decoder_cmd(file, fh, dc);
1078 if (ret < 0)
1079 return ret;
1080
1081 vicodec_mark_last_buf(ctx);
1082 return 0;
1083}
1084
1085static int vicodec_enum_framesizes(struct file *file, void *fh,
1086 struct v4l2_frmsizeenum *fsize)
1087{
1088 switch (fsize->pixel_format) {
1089 case V4L2_PIX_FMT_FWHT:
1090 break;
1091 default:
29a7a5e9 1092 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
256bf813
HV
1093 break;
1094 return -EINVAL;
1095 }
1096
1097 if (fsize->index)
1098 return -EINVAL;
1099
1100 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1101
1102 fsize->stepwise.min_width = MIN_WIDTH;
1103 fsize->stepwise.max_width = MAX_WIDTH;
1104 fsize->stepwise.step_width = 8;
1105 fsize->stepwise.min_height = MIN_HEIGHT;
1106 fsize->stepwise.max_height = MAX_HEIGHT;
1107 fsize->stepwise.step_height = 8;
1108
1109 return 0;
1110}
1111
1112static int vicodec_subscribe_event(struct v4l2_fh *fh,
1113 const struct v4l2_event_subscription *sub)
1114{
1115 switch (sub->type) {
1116 case V4L2_EVENT_EOS:
3b15f68e 1117 case V4L2_EVENT_SOURCE_CHANGE:
256bf813
HV
1118 return v4l2_event_subscribe(fh, sub, 0, NULL);
1119 default:
1120 return v4l2_ctrl_subscribe_event(fh, sub);
1121 }
1122}
1123
1124static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
1125 .vidioc_querycap = vidioc_querycap,
1126
1127 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1128 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1129 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1130 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1131
1132 .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
1133 .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
1134 .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
1135 .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
1136
1137 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1138 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1139 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1140 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1141
1142 .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
1143 .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
1144 .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
1145 .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
1146
1147 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1148 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1149 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1150 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
1151 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
1152 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
1153 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
1154
1155 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1156 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
1157
9e812549
DH
1158 .vidioc_g_selection = vidioc_g_selection,
1159 .vidioc_s_selection = vidioc_s_selection,
1160
256bf813
HV
1161 .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
1162 .vidioc_encoder_cmd = vicodec_encoder_cmd,
1163 .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
1164 .vidioc_decoder_cmd = vicodec_decoder_cmd,
1165 .vidioc_enum_framesizes = vicodec_enum_framesizes,
1166
1167 .vidioc_subscribe_event = vicodec_subscribe_event,
1168 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1169};
1170
1171
1172/*
1173 * Queue operations
1174 */
1175
1176static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1177 unsigned int *nplanes, unsigned int sizes[],
1178 struct device *alloc_devs[])
1179{
1180 struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
1181 struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
1182 unsigned int size = q_data->sizeimage;
1183
1184 if (*nplanes)
1185 return sizes[0] < size ? -EINVAL : 0;
1186
1187 *nplanes = 1;
1188 sizes[0] = size;
1189 return 0;
1190}
1191
1192static int vicodec_buf_prepare(struct vb2_buffer *vb)
1193{
1194 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1195 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1196 struct vicodec_q_data *q_data;
1197
1198 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1199
1200 q_data = get_q_data(ctx, vb->vb2_queue->type);
1201 if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1202 if (vbuf->field == V4L2_FIELD_ANY)
1203 vbuf->field = V4L2_FIELD_NONE;
1204 if (vbuf->field != V4L2_FIELD_NONE) {
1205 dprintk(ctx->dev, "%s field isn't supported\n",
1206 __func__);
1207 return -EINVAL;
1208 }
1209 }
1210
1211 if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1212 dprintk(ctx->dev,
1213 "%s data will not fit into plane (%lu < %lu)\n",
1214 __func__, vb2_plane_size(vb, 0),
1215 (long)q_data->sizeimage);
1216 return -EINVAL;
1217 }
1218
1219 return 0;
1220}
1221
1222static void vicodec_buf_queue(struct vb2_buffer *vb)
1223{
1224 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1225 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
3b15f68e
DH
1226 unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
1227 u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
1228 u8 *p = p_src;
1229 struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1230 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1231 struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1232 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1233 bool header_valid = false;
1234 static const struct v4l2_event rs_event = {
1235 .type = V4L2_EVENT_SOURCE_CHANGE,
1236 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
1237 };
1238
1239 /* buf_queue handles only the first source change event */
1240 if (ctx->first_source_change_sent) {
1241 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1242 return;
1243 }
1244
1245 /*
1246 * if both queues are streaming, the source change event is
1247 * handled in job_ready
1248 */
1249 if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) {
1250 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1251 return;
1252 }
1253
1254 /*
1255 * source change event is relevant only for the decoder
1256 * in the compressed stream
1257 */
1258 if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1259 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1260 return;
1261 }
1262
1263 do {
1264 enum vb2_buffer_state state =
1265 get_next_header(ctx, &p, p_src + sz - p);
1266
1267 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
1268 v4l2_m2m_buf_done(vbuf, state);
1269 return;
1270 }
1271 header_valid = is_header_valid(&ctx->state.header);
1272 /*
1273 * p points right after the end of the header in the
1274 * buffer. If the header is invalid we set p to point
1275 * to the next byte after the start of the header
1276 */
1277 if (!header_valid) {
1278 p = p - sizeof(struct fwht_cframe_hdr) + 1;
1279 if (p < p_src)
1280 p = p_src;
1281 ctx->header_size = 0;
1282 ctx->comp_magic_cnt = 0;
1283 }
256bf813 1284
3b15f68e
DH
1285 } while (!header_valid);
1286
1287 ctx->cur_buf_offset = p - p_src;
1288 update_capture_data_from_header(ctx);
1289 ctx->first_source_change_sent = true;
1290 v4l2_event_queue_fh(&ctx->fh, &rs_event);
256bf813
HV
1291 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1292}
1293
1294static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
1295{
1296 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1297 struct vb2_v4l2_buffer *vbuf;
1298
1299 for (;;) {
1300 if (V4L2_TYPE_IS_OUTPUT(q->type))
1301 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1302 else
1303 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1304 if (vbuf == NULL)
1305 return;
1306 spin_lock(ctx->lock);
1307 v4l2_m2m_buf_done(vbuf, state);
1308 spin_unlock(ctx->lock);
1309 }
1310}
1311
1312static int vicodec_start_streaming(struct vb2_queue *q,
1313 unsigned int count)
1314{
1315 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1316 struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
cd12b401 1317 struct v4l2_fwht_state *state = &ctx->state;
cd12b401 1318 const struct v4l2_fwht_pixfmt_info *info = q_data->info;
9e812549 1319 unsigned int size = q_data->coded_width * q_data->coded_height;
3b15f68e 1320 unsigned int chroma_div;
19505719 1321 unsigned int total_planes_size;
3b15f68e 1322 u8 *new_comp_frame;
19505719 1323
3b15f68e
DH
1324 if (!info)
1325 return -EINVAL;
1326
1327 chroma_div = info->width_div * info->height_div;
1328 q_data->sequence = 0;
1329
1330 ctx->last_src_buf = NULL;
1331 ctx->last_dst_buf = NULL;
1332 state->gop_cnt = 0;
1333
1334 if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1335 (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc))
1336 return 0;
1337
1338 if (info->id == V4L2_PIX_FMT_FWHT) {
1339 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1340 return -EINVAL;
1341 }
1342 if (info->components_num == 4)
16ecf6df
DH
1343 total_planes_size = 2 * size + 2 * (size / chroma_div);
1344 else if (info->components_num == 3)
19505719
DH
1345 total_planes_size = size + 2 * (size / chroma_div);
1346 else
1347 total_planes_size = size;
256bf813 1348
3b15f68e
DH
1349 state->visible_width = q_data->visible_width;
1350 state->visible_height = q_data->visible_height;
1351 state->coded_width = q_data->coded_width;
1352 state->coded_height = q_data->coded_height;
1353 state->stride = q_data->coded_width *
1354 info->bytesperline_mult;
256bf813 1355
19505719 1356 state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
ddc1b085 1357 ctx->comp_max_size = total_planes_size;
3b15f68e
DH
1358 new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1359
1360 if (!state->ref_frame.luma || !new_comp_frame) {
cd12b401 1361 kvfree(state->ref_frame.luma);
3b15f68e 1362 kvfree(new_comp_frame);
256bf813
HV
1363 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1364 return -ENOMEM;
1365 }
3b15f68e
DH
1366 /*
1367 * if state->compressed_frame was already allocated then
1368 * it contain data of the first frame of the new resolution
1369 */
1370 if (state->compressed_frame) {
1371 if (ctx->comp_size > ctx->comp_max_size)
1372 ctx->comp_size = ctx->comp_max_size;
1373
1374 memcpy(new_comp_frame,
1375 state->compressed_frame, ctx->comp_size);
1376 }
1377
1378 kvfree(state->compressed_frame);
1379 state->compressed_frame = new_comp_frame;
1380
1381 if (info->components_num >= 3) {
19505719
DH
1382 state->ref_frame.cb = state->ref_frame.luma + size;
1383 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1384 } else {
1385 state->ref_frame.cb = NULL;
1386 state->ref_frame.cr = NULL;
1387 }
16ecf6df 1388
3b15f68e 1389 if (info->components_num == 4)
16ecf6df
DH
1390 state->ref_frame.alpha =
1391 state->ref_frame.cr + size / chroma_div;
1392 else
1393 state->ref_frame.alpha = NULL;
256bf813
HV
1394 return 0;
1395}
1396
1397static void vicodec_stop_streaming(struct vb2_queue *q)
1398{
1399 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1400
1401 vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1402
3b15f68e
DH
1403 if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1404 (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
1405 kvfree(ctx->state.ref_frame.luma);
1406 ctx->comp_max_size = 0;
1407 ctx->source_changed = false;
1408 }
1409 if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) {
1410 ctx->cur_buf_offset = 0;
1411 ctx->comp_size = 0;
1412 ctx->header_size = 0;
1413 ctx->comp_magic_cnt = 0;
1414 ctx->comp_has_frame = 0;
1415 ctx->comp_has_next_frame = 0;
1416 }
256bf813
HV
1417}
1418
1419static const struct vb2_ops vicodec_qops = {
1420 .queue_setup = vicodec_queue_setup,
1421 .buf_prepare = vicodec_buf_prepare,
1422 .buf_queue = vicodec_buf_queue,
1423 .start_streaming = vicodec_start_streaming,
1424 .stop_streaming = vicodec_stop_streaming,
1425 .wait_prepare = vb2_ops_wait_prepare,
1426 .wait_finish = vb2_ops_wait_finish,
1427};
1428
1429static int queue_init(void *priv, struct vb2_queue *src_vq,
1430 struct vb2_queue *dst_vq)
1431{
1432 struct vicodec_ctx *ctx = priv;
1433 int ret;
1434
1435 src_vq->type = (multiplanar ?
1436 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1437 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1438 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1439 src_vq->drv_priv = ctx;
1440 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1441 src_vq->ops = &vicodec_qops;
1442 src_vq->mem_ops = &vb2_vmalloc_memops;
1443 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1444 src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1445 &ctx->dev->dec_mutex;
1446
1447 ret = vb2_queue_init(src_vq);
1448 if (ret)
1449 return ret;
1450
1451 dst_vq->type = (multiplanar ?
1452 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1453 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1454 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1455 dst_vq->drv_priv = ctx;
1456 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1457 dst_vq->ops = &vicodec_qops;
1458 dst_vq->mem_ops = &vb2_vmalloc_memops;
1459 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1460 dst_vq->lock = src_vq->lock;
1461
1462 return vb2_queue_init(dst_vq);
1463}
1464
48568b0c
HV
1465#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
1466#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
1467#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
1468
1469static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1470{
1471 struct vicodec_ctx *ctx = container_of(ctrl->handler,
1472 struct vicodec_ctx, hdl);
1473
1474 switch (ctrl->id) {
1475 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
cd12b401 1476 ctx->state.gop_size = ctrl->val;
48568b0c
HV
1477 return 0;
1478 case VICODEC_CID_I_FRAME_QP:
cd12b401 1479 ctx->state.i_frame_qp = ctrl->val;
48568b0c
HV
1480 return 0;
1481 case VICODEC_CID_P_FRAME_QP:
cd12b401 1482 ctx->state.p_frame_qp = ctrl->val;
48568b0c
HV
1483 return 0;
1484 }
1485 return -EINVAL;
1486}
1487
299553d8 1488static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
48568b0c
HV
1489 .s_ctrl = vicodec_s_ctrl,
1490};
1491
1492static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1493 .ops = &vicodec_ctrl_ops,
1494 .id = VICODEC_CID_I_FRAME_QP,
1495 .name = "FWHT I-Frame QP Value",
1496 .type = V4L2_CTRL_TYPE_INTEGER,
1497 .min = 1,
1498 .max = 31,
1499 .def = 20,
1500 .step = 1,
1501};
1502
1503static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1504 .ops = &vicodec_ctrl_ops,
1505 .id = VICODEC_CID_P_FRAME_QP,
1506 .name = "FWHT P-Frame QP Value",
1507 .type = V4L2_CTRL_TYPE_INTEGER,
1508 .min = 1,
1509 .max = 31,
1510 .def = 20,
1511 .step = 1,
1512};
1513
256bf813
HV
1514/*
1515 * File operations
1516 */
1517static int vicodec_open(struct file *file)
1518{
1519 struct video_device *vfd = video_devdata(file);
1520 struct vicodec_dev *dev = video_drvdata(file);
1521 struct vicodec_ctx *ctx = NULL;
1522 struct v4l2_ctrl_handler *hdl;
1523 unsigned int size;
1524 int rc = 0;
1525
1526 if (mutex_lock_interruptible(vfd->lock))
1527 return -ERESTARTSYS;
1528 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1529 if (!ctx) {
1530 rc = -ENOMEM;
1531 goto open_unlock;
1532 }
1533
1534 if (vfd == &dev->enc_vfd)
1535 ctx->is_enc = true;
1536
1537 v4l2_fh_init(&ctx->fh, video_devdata(file));
1538 file->private_data = &ctx->fh;
1539 ctx->dev = dev;
1540 hdl = &ctx->hdl;
1541 v4l2_ctrl_handler_init(hdl, 4);
48568b0c
HV
1542 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1543 1, 16, 1, 10);
1544 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1545 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
256bf813
HV
1546 if (hdl->error) {
1547 rc = hdl->error;
1548 v4l2_ctrl_handler_free(hdl);
1549 kfree(ctx);
1550 goto open_unlock;
1551 }
1552 ctx->fh.ctrl_handler = hdl;
1553 v4l2_ctrl_handler_setup(hdl);
1554
29a7a5e9 1555 ctx->q_data[V4L2_M2M_SRC].info =
cd12b401 1556 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
9e812549
DH
1557 ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
1558 ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
1559 ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
1560 ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
29a7a5e9
HV
1561 size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1562 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
55f6fe09
HV
1563 if (ctx->is_enc)
1564 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1565 else
1566 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1567 size + sizeof(struct fwht_cframe_hdr);
3b15f68e
DH
1568 if (ctx->is_enc) {
1569 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1570 ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
1571 ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 *
1572 ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1573 ctx->q_data[V4L2_M2M_DST].info->sizeimage_div +
1574 sizeof(struct fwht_cframe_hdr);
1575 } else {
1576 ctx->q_data[V4L2_M2M_DST].info = NULL;
1577 }
1578
cd12b401 1579 ctx->state.colorspace = V4L2_COLORSPACE_REC709;
256bf813 1580
256bf813 1581 if (ctx->is_enc) {
256bf813
HV
1582 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1583 &queue_init);
1584 ctx->lock = &dev->enc_lock;
1585 } else {
256bf813
HV
1586 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1587 &queue_init);
1588 ctx->lock = &dev->dec_lock;
1589 }
1590
1591 if (IS_ERR(ctx->fh.m2m_ctx)) {
1592 rc = PTR_ERR(ctx->fh.m2m_ctx);
1593
1594 v4l2_ctrl_handler_free(hdl);
1595 v4l2_fh_exit(&ctx->fh);
1596 kfree(ctx);
1597 goto open_unlock;
1598 }
1599
1600 v4l2_fh_add(&ctx->fh);
1601
1602open_unlock:
1603 mutex_unlock(vfd->lock);
1604 return rc;
1605}
1606
1607static int vicodec_release(struct file *file)
1608{
1609 struct video_device *vfd = video_devdata(file);
1610 struct vicodec_ctx *ctx = file2ctx(file);
1611
1612 v4l2_fh_del(&ctx->fh);
1613 v4l2_fh_exit(&ctx->fh);
1614 v4l2_ctrl_handler_free(&ctx->hdl);
1615 mutex_lock(vfd->lock);
1616 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1617 mutex_unlock(vfd->lock);
1618 kfree(ctx);
1619
1620 return 0;
1621}
1622
1623static const struct v4l2_file_operations vicodec_fops = {
1624 .owner = THIS_MODULE,
1625 .open = vicodec_open,
1626 .release = vicodec_release,
1627 .poll = v4l2_m2m_fop_poll,
1628 .unlocked_ioctl = video_ioctl2,
1629 .mmap = v4l2_m2m_fop_mmap,
1630};
1631
1632static const struct video_device vicodec_videodev = {
1633 .name = VICODEC_NAME,
1634 .vfl_dir = VFL_DIR_M2M,
1635 .fops = &vicodec_fops,
1636 .ioctl_ops = &vicodec_ioctl_ops,
1637 .minor = -1,
1638 .release = video_device_release_empty,
1639};
1640
1641static const struct v4l2_m2m_ops m2m_ops = {
1642 .device_run = device_run,
256bf813
HV
1643 .job_ready = job_ready,
1644};
1645
1646static int vicodec_probe(struct platform_device *pdev)
1647{
1648 struct vicodec_dev *dev;
1649 struct video_device *vfd;
1650 int ret;
1651
1652 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1653 if (!dev)
1654 return -ENOMEM;
1655
1656 spin_lock_init(&dev->enc_lock);
1657 spin_lock_init(&dev->dec_lock);
1658
1659 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1660 if (ret)
1661 return ret;
1662
1663#ifdef CONFIG_MEDIA_CONTROLLER
1664 dev->mdev.dev = &pdev->dev;
c0decac1 1665 strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
256bf813
HV
1666 media_device_init(&dev->mdev);
1667 dev->v4l2_dev.mdev = &dev->mdev;
1668#endif
1669
1670 mutex_init(&dev->enc_mutex);
1671 mutex_init(&dev->dec_mutex);
1672
1673 platform_set_drvdata(pdev, dev);
1674
1675 dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1676 if (IS_ERR(dev->enc_dev)) {
1677 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1678 ret = PTR_ERR(dev->enc_dev);
1679 goto unreg_dev;
1680 }
1681
1682 dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1683 if (IS_ERR(dev->dec_dev)) {
1684 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1685 ret = PTR_ERR(dev->dec_dev);
1686 goto err_enc_m2m;
1687 }
1688
1689 dev->enc_vfd = vicodec_videodev;
1690 vfd = &dev->enc_vfd;
1691 vfd->lock = &dev->enc_mutex;
1692 vfd->v4l2_dev = &dev->v4l2_dev;
c0decac1 1693 strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
47fc65fa
HV
1694 vfd->device_caps = V4L2_CAP_STREAMING |
1695 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
256bf813
HV
1696 v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1697 v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1698 video_set_drvdata(vfd, dev);
1699
1700 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1701 if (ret) {
1702 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1703 goto err_dec_m2m;
1704 }
1705 v4l2_info(&dev->v4l2_dev,
1706 "Device registered as /dev/video%d\n", vfd->num);
1707
1708 dev->dec_vfd = vicodec_videodev;
1709 vfd = &dev->dec_vfd;
1710 vfd->lock = &dev->dec_mutex;
1711 vfd->v4l2_dev = &dev->v4l2_dev;
47fc65fa
HV
1712 vfd->device_caps = V4L2_CAP_STREAMING |
1713 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
c0decac1 1714 strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
256bf813
HV
1715 v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1716 v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1717 video_set_drvdata(vfd, dev);
1718
1719 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1720 if (ret) {
1721 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1722 goto unreg_enc;
1723 }
1724 v4l2_info(&dev->v4l2_dev,
1725 "Device registered as /dev/video%d\n", vfd->num);
1726
1727#ifdef CONFIG_MEDIA_CONTROLLER
1728 ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1729 &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1730 if (ret) {
1731 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1732 goto unreg_m2m;
1733 }
1734
1735 ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1736 &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1737 if (ret) {
1738 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1739 goto unreg_m2m_enc_mc;
1740 }
1741
1742 ret = media_device_register(&dev->mdev);
1743 if (ret) {
1744 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1745 goto unreg_m2m_dec_mc;
1746 }
1747#endif
1748 return 0;
1749
1750#ifdef CONFIG_MEDIA_CONTROLLER
1751unreg_m2m_dec_mc:
1752 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1753unreg_m2m_enc_mc:
1754 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1755unreg_m2m:
1756 video_unregister_device(&dev->dec_vfd);
1757#endif
1758unreg_enc:
1759 video_unregister_device(&dev->enc_vfd);
1760err_dec_m2m:
1761 v4l2_m2m_release(dev->dec_dev);
1762err_enc_m2m:
1763 v4l2_m2m_release(dev->enc_dev);
1764unreg_dev:
1765 v4l2_device_unregister(&dev->v4l2_dev);
1766
1767 return ret;
1768}
1769
1770static int vicodec_remove(struct platform_device *pdev)
1771{
1772 struct vicodec_dev *dev = platform_get_drvdata(pdev);
1773
1774 v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1775
1776#ifdef CONFIG_MEDIA_CONTROLLER
1777 media_device_unregister(&dev->mdev);
1778 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1779 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1780 media_device_cleanup(&dev->mdev);
1781#endif
1782
1783 v4l2_m2m_release(dev->enc_dev);
1784 v4l2_m2m_release(dev->dec_dev);
1785 video_unregister_device(&dev->enc_vfd);
1786 video_unregister_device(&dev->dec_vfd);
1787 v4l2_device_unregister(&dev->v4l2_dev);
1788
1789 return 0;
1790}
1791
1792static struct platform_driver vicodec_pdrv = {
1793 .probe = vicodec_probe,
1794 .remove = vicodec_remove,
1795 .driver = {
1796 .name = VICODEC_NAME,
1797 },
1798};
1799
1800static void __exit vicodec_exit(void)
1801{
1802 platform_driver_unregister(&vicodec_pdrv);
1803 platform_device_unregister(&vicodec_pdev);
1804}
1805
1806static int __init vicodec_init(void)
1807{
1808 int ret;
1809
1810 ret = platform_device_register(&vicodec_pdev);
1811 if (ret)
1812 return ret;
1813
1814 ret = platform_driver_register(&vicodec_pdrv);
1815 if (ret)
1816 platform_device_unregister(&vicodec_pdev);
1817
1818 return ret;
1819}
1820
1821module_init(vicodec_init);
1822module_exit(vicodec_exit);