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
26 #include "codec-v4l2-fwht.h"
27
28 MODULE_DESCRIPTION("Virtual codec device");
29 MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
30 MODULE_LICENSE("GPL v2");
31
32 static bool multiplanar;
33 module_param(multiplanar, bool, 0444);
34 MODULE_PARM_DESC(multiplanar,
35 " use multi-planar API instead of single-planar API");
36
37 static unsigned int debug;
38 module_param(debug, uint, 0644);
39 MODULE_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
45 #define MIN_HEIGHT 360U
46 /* Recommended number of buffers for the stateful codecs */
47 #define VICODEC_REC_BUFS 2
48
49 #define dprintk(dev, fmt, arg...) \
50 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
51
52
53 struct pixfmt_info {
54 u32 id;
55 unsigned int bytesperline_mult;
56 unsigned int sizeimage_mult;
57 unsigned int sizeimage_div;
58 unsigned int luma_step;
59 unsigned int chroma_step;
60 /* Chroma plane subsampling */
61 unsigned int width_div;
62 unsigned int height_div;
63 };
64
65 static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
66 V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1
67 };
68
69 static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = {
70 V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1
71 };
72
vicodec_dev_release(struct device * dev)73 static void vicodec_dev_release(struct device *dev)
74 {
75 }
76
77 static struct platform_device vicodec_pdev = {
78 .name = VICODEC_NAME,
79 .dev.release = vicodec_dev_release,
80 };
81
82 /* Per-queue, driver-specific private data */
83 struct vicodec_q_data {
84 unsigned int coded_width;
85 unsigned int coded_height;
86 unsigned int visible_width;
87 unsigned int visible_height;
88 unsigned int sizeimage;
89 unsigned int vb2_sizeimage;
90 unsigned int sequence;
91 const struct v4l2_fwht_pixfmt_info *info;
92 };
93
94 enum {
95 V4L2_M2M_SRC = 0,
96 V4L2_M2M_DST = 1,
97 };
98
99 struct vicodec_dev_instance {
100 struct video_device vfd;
101 struct mutex mutex;
102 spinlock_t lock;
103 struct v4l2_m2m_dev *m2m_dev;
104 };
105
106 struct vicodec_dev {
107 struct v4l2_device v4l2_dev;
108 struct vicodec_dev_instance stateful_enc;
109 struct vicodec_dev_instance stateful_dec;
110 struct vicodec_dev_instance stateless_dec;
111 #ifdef CONFIG_MEDIA_CONTROLLER
112 struct media_device mdev;
113 #endif
114
115 };
116
117 struct vicodec_ctx {
118 struct v4l2_fh fh;
119 struct vicodec_dev *dev;
120 bool is_enc;
121 bool is_stateless;
122 spinlock_t *lock;
123
124 struct v4l2_ctrl_handler hdl;
125
126 /* Source and destination queue data */
127 struct vicodec_q_data q_data[2];
128 struct v4l2_fwht_state state;
129
130 u32 cur_buf_offset;
131 u32 comp_max_size;
132 u32 comp_size;
133 u32 header_size;
134 u32 comp_magic_cnt;
135 bool comp_has_frame;
136 bool comp_has_next_frame;
137 bool first_source_change_sent;
138 bool source_changed;
139 };
140
141 static const struct v4l2_event vicodec_eos_event = {
142 .type = V4L2_EVENT_EOS
143 };
144
file2ctx(struct file * file)145 static inline struct vicodec_ctx *file2ctx(struct file *file)
146 {
147 return container_of(file->private_data, struct vicodec_ctx, fh);
148 }
149
get_q_data(struct vicodec_ctx * ctx,enum v4l2_buf_type type)150 static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
151 enum v4l2_buf_type type)
152 {
153 switch (type) {
154 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
155 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
156 return &ctx->q_data[V4L2_M2M_SRC];
157 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
158 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
159 return &ctx->q_data[V4L2_M2M_DST];
160 default:
161 break;
162 }
163 return NULL;
164 }
165
copy_cap_to_ref(const u8 * cap,const struct v4l2_fwht_pixfmt_info * info,struct v4l2_fwht_state * state)166 static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info,
167 struct v4l2_fwht_state *state)
168 {
169 int plane_idx;
170 u8 *p_ref = state->ref_frame.buf;
171 unsigned int cap_stride = state->stride;
172 unsigned int ref_stride = state->ref_stride;
173
174 for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) {
175 int i;
176 unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ?
177 info->height_div : 1;
178 const u8 *row_cap = cap;
179 u8 *row_ref = p_ref;
180
181 if (info->planes_num == 3 && plane_idx == 1) {
182 cap_stride /= 2;
183 ref_stride /= 2;
184 }
185
186 if (plane_idx == 1 &&
187 (info->id == V4L2_PIX_FMT_NV24 ||
188 info->id == V4L2_PIX_FMT_NV42)) {
189 cap_stride *= 2;
190 ref_stride *= 2;
191 }
192
193 for (i = 0; i < state->visible_height / h_div; i++) {
194 memcpy(row_ref, row_cap, ref_stride);
195 row_ref += ref_stride;
196 row_cap += cap_stride;
197 }
198 cap += cap_stride * (state->coded_height / h_div);
199 p_ref += ref_stride * (state->coded_height / h_div);
200 }
201 }
202
validate_by_version(unsigned int flags,unsigned int version)203 static bool validate_by_version(unsigned int flags, unsigned int version)
204 {
205 if (!version || version > V4L2_FWHT_VERSION)
206 return false;
207
208 if (version >= 2) {
209 unsigned int components_num = 1 +
210 ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
211 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
212 unsigned int pixenc = flags & V4L2_FWHT_FL_PIXENC_MSK;
213
214 if (components_num == 0 || components_num > 4 || !pixenc)
215 return false;
216 }
217 return true;
218 }
219
validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params * params,const struct v4l2_fwht_pixfmt_info * cur_info)220 static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params,
221 const struct v4l2_fwht_pixfmt_info *cur_info)
222 {
223 unsigned int width_div =
224 (params->flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
225 unsigned int height_div =
226 (params->flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
227 unsigned int components_num = 3;
228 unsigned int pixenc = 0;
229
230 if (params->version < 3)
231 return false;
232
233 components_num = 1 + ((params->flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
234 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
235 pixenc = (params->flags & V4L2_FWHT_FL_PIXENC_MSK);
236 if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div,
237 components_num, pixenc))
238 return true;
239 return false;
240 }
241
242
update_state_from_header(struct vicodec_ctx * ctx)243 static void update_state_from_header(struct vicodec_ctx *ctx)
244 {
245 const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
246
247 ctx->state.visible_width = ntohl(p_hdr->width);
248 ctx->state.visible_height = ntohl(p_hdr->height);
249 ctx->state.colorspace = ntohl(p_hdr->colorspace);
250 ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
251 ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
252 ctx->state.quantization = ntohl(p_hdr->quantization);
253 }
254
device_process(struct vicodec_ctx * ctx,struct vb2_v4l2_buffer * src_vb,struct vb2_v4l2_buffer * dst_vb)255 static int device_process(struct vicodec_ctx *ctx,
256 struct vb2_v4l2_buffer *src_vb,
257 struct vb2_v4l2_buffer *dst_vb)
258 {
259 struct vicodec_dev *dev = ctx->dev;
260 struct v4l2_fwht_state *state = &ctx->state;
261 u8 *p_src, *p_dst;
262 int ret = 0;
263
264 if (ctx->is_enc || ctx->is_stateless)
265 p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
266 else
267 p_src = state->compressed_frame;
268
269 if (ctx->is_stateless) {
270 struct media_request *src_req = src_vb->vb2_buf.req_obj.req;
271
272 ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl);
273 if (ret)
274 return ret;
275 update_state_from_header(ctx);
276
277 ctx->state.header.size =
278 htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0));
279 /*
280 * set the reference buffer from the reference timestamp
281 * only if this is a P-frame
282 */
283 if (!(ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)) {
284 struct vb2_buffer *ref_vb2_buf;
285 struct vb2_queue *vq_cap =
286 v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
287 V4L2_BUF_TYPE_VIDEO_CAPTURE);
288
289 ref_vb2_buf = vb2_find_buffer(vq_cap, ctx->state.ref_frame_ts);
290 if (!ref_vb2_buf)
291 return -EINVAL;
292 if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR)
293 ret = -EINVAL;
294 ctx->state.ref_frame.buf =
295 vb2_plane_vaddr(ref_vb2_buf, 0);
296 } else {
297 ctx->state.ref_frame.buf = NULL;
298 }
299 }
300 p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
301 if (!p_src || !p_dst) {
302 v4l2_err(&dev->v4l2_dev,
303 "Acquiring kernel pointers to buffers failed\n");
304 return -EFAULT;
305 }
306
307 if (ctx->is_enc) {
308 struct vicodec_q_data *q_src;
309 int comp_sz_or_errcode;
310
311 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
312 state->info = q_src->info;
313 comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst);
314 if (comp_sz_or_errcode < 0)
315 return comp_sz_or_errcode;
316 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode);
317 } else {
318 struct vicodec_q_data *q_dst;
319 unsigned int comp_frame_size = ntohl(ctx->state.header.size);
320
321 q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
322 if (comp_frame_size > ctx->comp_max_size)
323 return -EINVAL;
324 state->info = q_dst->info;
325 ret = v4l2_fwht_decode(state, p_src, p_dst);
326 if (ret < 0)
327 return ret;
328 if (!ctx->is_stateless)
329 copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state);
330
331 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
332 if (ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)
333 dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME;
334 else
335 dst_vb->flags |= V4L2_BUF_FLAG_PFRAME;
336 }
337 return ret;
338 }
339
340 /*
341 * mem2mem callbacks
342 */
get_next_header(struct vicodec_ctx * ctx,u8 ** pp,u32 sz)343 static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx,
344 u8 **pp, u32 sz)
345 {
346 static const u8 magic[] = {
347 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
348 };
349 u8 *p = *pp;
350 u32 state;
351 u8 *header = (u8 *)&ctx->state.header;
352
353 state = VB2_BUF_STATE_DONE;
354
355 if (!ctx->header_size) {
356 state = VB2_BUF_STATE_ERROR;
357 for (; p < *pp + sz; p++) {
358 u32 copy;
359
360 p = memchr(p, magic[ctx->comp_magic_cnt],
361 *pp + sz - p);
362 if (!p) {
363 ctx->comp_magic_cnt = 0;
364 p = *pp + sz;
365 break;
366 }
367 copy = sizeof(magic) - ctx->comp_magic_cnt;
368 if (*pp + sz - p < copy)
369 copy = *pp + sz - p;
370
371 memcpy(header + ctx->comp_magic_cnt, p, copy);
372 ctx->comp_magic_cnt += copy;
373 if (!memcmp(header, magic, ctx->comp_magic_cnt)) {
374 p += copy;
375 state = VB2_BUF_STATE_DONE;
376 break;
377 }
378 ctx->comp_magic_cnt = 0;
379 }
380 if (ctx->comp_magic_cnt < sizeof(magic)) {
381 *pp = p;
382 return state;
383 }
384 ctx->header_size = sizeof(magic);
385 }
386
387 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
388 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size;
389
390 if (*pp + sz - p < copy)
391 copy = *pp + sz - p;
392
393 memcpy(header + ctx->header_size, p, copy);
394 p += copy;
395 ctx->header_size += copy;
396 }
397 *pp = p;
398 return state;
399 }
400
401 /* device_run() - prepares and starts the device */
device_run(void * priv)402 static void device_run(void *priv)
403 {
404 struct vicodec_ctx *ctx = priv;
405 struct vicodec_dev *dev = ctx->dev;
406 struct vb2_v4l2_buffer *src_buf, *dst_buf;
407 struct vicodec_q_data *q_src, *q_dst;
408 u32 state;
409 struct media_request *src_req;
410
411 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
412 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
413 src_req = src_buf->vb2_buf.req_obj.req;
414
415 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
416 q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
417
418 state = VB2_BUF_STATE_DONE;
419 if (device_process(ctx, src_buf, dst_buf))
420 state = VB2_BUF_STATE_ERROR;
421 else
422 dst_buf->sequence = q_dst->sequence++;
423 dst_buf->flags &= ~V4L2_BUF_FLAG_LAST;
424 v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
425
426 spin_lock(ctx->lock);
427 if (!ctx->comp_has_next_frame &&
428 v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {
429 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
430 v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
431 v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
432 }
433 if (ctx->is_enc || ctx->is_stateless) {
434 src_buf->sequence = q_src->sequence++;
435 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
436 v4l2_m2m_buf_done(src_buf, state);
437 } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
438 src_buf->sequence = q_src->sequence++;
439 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
440 v4l2_m2m_buf_done(src_buf, state);
441 ctx->cur_buf_offset = 0;
442 ctx->comp_has_next_frame = false;
443 }
444 v4l2_m2m_buf_done(dst_buf, state);
445
446 ctx->comp_size = 0;
447 ctx->header_size = 0;
448 ctx->comp_magic_cnt = 0;
449 ctx->comp_has_frame = false;
450 spin_unlock(ctx->lock);
451 if (ctx->is_stateless && src_req)
452 v4l2_ctrl_request_complete(src_req, &ctx->hdl);
453
454 if (ctx->is_enc)
455 v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx);
456 else if (ctx->is_stateless)
457 v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev,
458 ctx->fh.m2m_ctx);
459 else
460 v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx);
461 }
462
job_remove_src_buf(struct vicodec_ctx * ctx,u32 state)463 static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
464 {
465 struct vb2_v4l2_buffer *src_buf;
466 struct vicodec_q_data *q_src;
467
468 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
469 spin_lock(ctx->lock);
470 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
471 src_buf->sequence = q_src->sequence++;
472 v4l2_m2m_buf_done(src_buf, state);
473 ctx->cur_buf_offset = 0;
474 spin_unlock(ctx->lock);
475 }
476
477 static const struct v4l2_fwht_pixfmt_info *
info_from_header(const struct fwht_cframe_hdr * p_hdr)478 info_from_header(const struct fwht_cframe_hdr *p_hdr)
479 {
480 unsigned int flags = ntohl(p_hdr->flags);
481 unsigned int width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
482 unsigned int height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
483 unsigned int components_num = 3;
484 unsigned int pixenc = 0;
485 unsigned int version = ntohl(p_hdr->version);
486
487 if (version >= 2) {
488 components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
489 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
490 pixenc = (flags & V4L2_FWHT_FL_PIXENC_MSK);
491 }
492 return v4l2_fwht_find_nth_fmt(width_div, height_div,
493 components_num, pixenc, 0);
494 }
495
is_header_valid(const struct fwht_cframe_hdr * p_hdr)496 static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr)
497 {
498 const struct v4l2_fwht_pixfmt_info *info;
499 unsigned int w = ntohl(p_hdr->width);
500 unsigned int h = ntohl(p_hdr->height);
501 unsigned int version = ntohl(p_hdr->version);
502 unsigned int flags = ntohl(p_hdr->flags);
503
504 if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT)
505 return false;
506
507 if (!validate_by_version(flags, version))
508 return false;
509
510 info = info_from_header(p_hdr);
511 if (!info)
512 return false;
513 return true;
514 }
515
update_capture_data_from_header(struct vicodec_ctx * ctx)516 static void update_capture_data_from_header(struct vicodec_ctx *ctx)
517 {
518 struct vicodec_q_data *q_dst = get_q_data(ctx,
519 V4L2_BUF_TYPE_VIDEO_CAPTURE);
520 const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
521 const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr);
522 unsigned int flags = ntohl(p_hdr->flags);
523 unsigned int hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
524 unsigned int hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
525
526 /*
527 * This function should not be used by a stateless codec since
528 * it changes values in q_data that are not request specific
529 */
530 WARN_ON(ctx->is_stateless);
531
532 q_dst->info = info;
533 q_dst->visible_width = ntohl(p_hdr->width);
534 q_dst->visible_height = ntohl(p_hdr->height);
535 q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div);
536 q_dst->coded_height = vic_round_dim(q_dst->visible_height,
537 hdr_height_div);
538
539 q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height *
540 q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div;
541 ctx->state.colorspace = ntohl(p_hdr->colorspace);
542
543 ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
544 ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
545 ctx->state.quantization = ntohl(p_hdr->quantization);
546 }
547
set_last_buffer(struct vb2_v4l2_buffer * dst_buf,const struct vb2_v4l2_buffer * src_buf,struct vicodec_ctx * ctx)548 static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf,
549 const struct vb2_v4l2_buffer *src_buf,
550 struct vicodec_ctx *ctx)
551 {
552 struct vicodec_q_data *q_dst = get_q_data(ctx,
553 V4L2_BUF_TYPE_VIDEO_CAPTURE);
554
555 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
556 dst_buf->sequence = q_dst->sequence++;
557
558 v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc);
559 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
560 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
561 }
562
job_ready(void * priv)563 static int job_ready(void *priv)
564 {
565 static const u8 magic[] = {
566 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
567 };
568 struct vicodec_ctx *ctx = priv;
569 struct vb2_v4l2_buffer *src_buf;
570 u8 *p_src;
571 u8 *p;
572 u32 sz;
573 u32 state;
574 struct vicodec_q_data *q_dst = get_q_data(ctx,
575 V4L2_BUF_TYPE_VIDEO_CAPTURE);
576 unsigned int flags;
577 unsigned int hdr_width_div;
578 unsigned int hdr_height_div;
579 unsigned int max_to_copy;
580 unsigned int comp_frame_size;
581
582 if (ctx->source_changed)
583 return 0;
584 if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
585 return 1;
586
587 restart:
588 ctx->comp_has_next_frame = false;
589 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
590 if (!src_buf)
591 return 0;
592 p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
593 sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
594 p = p_src + ctx->cur_buf_offset;
595
596 state = VB2_BUF_STATE_DONE;
597
598 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
599 state = get_next_header(ctx, &p, p_src + sz - p);
600 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
601 if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
602 src_buf))
603 return 1;
604 job_remove_src_buf(ctx, state);
605 goto restart;
606 }
607 }
608
609 comp_frame_size = ntohl(ctx->state.header.size);
610
611 /*
612 * The current scanned frame might be the first frame of a new
613 * resolution so its size might be larger than ctx->comp_max_size.
614 * In that case it is copied up to the current buffer capacity and
615 * the copy will continue after allocating new large enough buffer
616 * when restreaming
617 */
618 max_to_copy = min(comp_frame_size, ctx->comp_max_size);
619
620 if (ctx->comp_size < max_to_copy) {
621 u32 copy = max_to_copy - ctx->comp_size;
622
623 if (copy > p_src + sz - p)
624 copy = p_src + sz - p;
625
626 memcpy(ctx->state.compressed_frame + ctx->comp_size,
627 p, copy);
628 p += copy;
629 ctx->comp_size += copy;
630 if (ctx->comp_size < max_to_copy) {
631 if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
632 src_buf))
633 return 1;
634 job_remove_src_buf(ctx, state);
635 goto restart;
636 }
637 }
638 ctx->cur_buf_offset = p - p_src;
639 if (ctx->comp_size == comp_frame_size)
640 ctx->comp_has_frame = true;
641 ctx->comp_has_next_frame = false;
642 if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >=
643 sizeof(struct fwht_cframe_hdr)) {
644 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
645 u32 frame_size = ntohl(p_hdr->size);
646 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
647
648 if (!memcmp(p, magic, sizeof(magic)))
649 ctx->comp_has_next_frame = remaining >= frame_size;
650 }
651 /*
652 * if the header is invalid the device_run will just drop the frame
653 * with an error
654 */
655 if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame)
656 return 1;
657 flags = ntohl(ctx->state.header.flags);
658 hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
659 hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
660
661 if (ntohl(ctx->state.header.width) != q_dst->visible_width ||
662 ntohl(ctx->state.header.height) != q_dst->visible_height ||
663 !q_dst->info ||
664 hdr_width_div != q_dst->info->width_div ||
665 hdr_height_div != q_dst->info->height_div) {
666 static const struct v4l2_event rs_event = {
667 .type = V4L2_EVENT_SOURCE_CHANGE,
668 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
669 };
670
671 struct vb2_v4l2_buffer *dst_buf =
672 v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
673
674 update_capture_data_from_header(ctx);
675 v4l2_event_queue_fh(&ctx->fh, &rs_event);
676 set_last_buffer(dst_buf, src_buf, ctx);
677 ctx->source_changed = true;
678 return 0;
679 }
680 return 1;
681 }
682
683 /*
684 * video ioctls
685 */
686
find_fmt(u32 fmt)687 static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
688 {
689 const struct v4l2_fwht_pixfmt_info *info =
690 v4l2_fwht_find_pixfmt(fmt);
691
692 if (!info)
693 info = v4l2_fwht_get_pixfmt(0);
694 return info;
695 }
696
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)697 static int vidioc_querycap(struct file *file, void *priv,
698 struct v4l2_capability *cap)
699 {
700 strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver));
701 strscpy(cap->card, VICODEC_NAME, sizeof(cap->card));
702 snprintf(cap->bus_info, sizeof(cap->bus_info),
703 "platform:%s", VICODEC_NAME);
704 return 0;
705 }
706
enum_fmt(struct v4l2_fmtdesc * f,struct vicodec_ctx * ctx,bool is_out)707 static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
708 bool is_out)
709 {
710 bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out);
711
712 if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
713 return -EINVAL;
714 if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
715 return -EINVAL;
716
717 if (is_uncomp) {
718 const struct v4l2_fwht_pixfmt_info *info =
719 get_q_data(ctx, f->type)->info;
720
721 if (ctx->is_enc ||
722 !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q))
723 info = v4l2_fwht_get_pixfmt(f->index);
724 else
725 info = v4l2_fwht_find_nth_fmt(info->width_div,
726 info->height_div,
727 info->components_num,
728 info->pixenc,
729 f->index);
730 if (!info)
731 return -EINVAL;
732 f->pixelformat = info->id;
733 } else {
734 if (f->index)
735 return -EINVAL;
736 f->pixelformat = ctx->is_stateless ?
737 V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT;
738 if (!ctx->is_enc && !ctx->is_stateless)
739 f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION |
740 V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM;
741 }
742 return 0;
743 }
744
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)745 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
746 struct v4l2_fmtdesc *f)
747 {
748 struct vicodec_ctx *ctx = file2ctx(file);
749
750 return enum_fmt(f, ctx, false);
751 }
752
vidioc_enum_fmt_vid_out(struct file * file,void * priv,struct v4l2_fmtdesc * f)753 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
754 struct v4l2_fmtdesc *f)
755 {
756 struct vicodec_ctx *ctx = file2ctx(file);
757
758 return enum_fmt(f, ctx, true);
759 }
760
vidioc_g_fmt(struct vicodec_ctx * ctx,struct v4l2_format * f)761 static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
762 {
763 struct vb2_queue *vq;
764 struct vicodec_q_data *q_data;
765 struct v4l2_pix_format_mplane *pix_mp;
766 struct v4l2_pix_format *pix;
767 const struct v4l2_fwht_pixfmt_info *info;
768
769 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
770 if (!vq)
771 return -EINVAL;
772
773 q_data = get_q_data(ctx, f->type);
774 info = q_data->info;
775
776 switch (f->type) {
777 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
778 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
779 if (multiplanar)
780 return -EINVAL;
781 pix = &f->fmt.pix;
782 pix->width = q_data->coded_width;
783 pix->height = q_data->coded_height;
784 pix->field = V4L2_FIELD_NONE;
785 pix->pixelformat = info->id;
786 pix->bytesperline = q_data->coded_width *
787 info->bytesperline_mult;
788 pix->sizeimage = q_data->sizeimage;
789 pix->colorspace = ctx->state.colorspace;
790 pix->xfer_func = ctx->state.xfer_func;
791 pix->ycbcr_enc = ctx->state.ycbcr_enc;
792 pix->quantization = ctx->state.quantization;
793 break;
794
795 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
796 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
797 if (!multiplanar)
798 return -EINVAL;
799 pix_mp = &f->fmt.pix_mp;
800 pix_mp->width = q_data->coded_width;
801 pix_mp->height = q_data->coded_height;
802 pix_mp->field = V4L2_FIELD_NONE;
803 pix_mp->pixelformat = info->id;
804 pix_mp->num_planes = 1;
805 pix_mp->plane_fmt[0].bytesperline =
806 q_data->coded_width * info->bytesperline_mult;
807 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
808 pix_mp->colorspace = ctx->state.colorspace;
809 pix_mp->xfer_func = ctx->state.xfer_func;
810 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
811 pix_mp->quantization = ctx->state.quantization;
812 break;
813 default:
814 return -EINVAL;
815 }
816 return 0;
817 }
818
vidioc_g_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)819 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
820 struct v4l2_format *f)
821 {
822 return vidioc_g_fmt(file2ctx(file), f);
823 }
824
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)825 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
826 struct v4l2_format *f)
827 {
828 return vidioc_g_fmt(file2ctx(file), f);
829 }
830
vidioc_try_fmt(struct vicodec_ctx * ctx,struct v4l2_format * f)831 static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
832 {
833 struct v4l2_pix_format_mplane *pix_mp;
834 struct v4l2_pix_format *pix;
835 struct v4l2_plane_pix_format *plane;
836 const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ?
837 &pixfmt_stateless_fwht : &pixfmt_fwht;
838
839 switch (f->type) {
840 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
841 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
842 pix = &f->fmt.pix;
843 if (pix->pixelformat != V4L2_PIX_FMT_FWHT &&
844 pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS)
845 info = find_fmt(pix->pixelformat);
846
847 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
848 pix->width = vic_round_dim(pix->width, info->width_div);
849
850 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
851 pix->height = vic_round_dim(pix->height, info->height_div);
852
853 pix->field = V4L2_FIELD_NONE;
854 pix->bytesperline =
855 pix->width * info->bytesperline_mult;
856 pix->sizeimage = pix->width * pix->height *
857 info->sizeimage_mult / info->sizeimage_div;
858 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
859 pix->sizeimage += sizeof(struct fwht_cframe_hdr);
860 break;
861 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
862 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
863 pix_mp = &f->fmt.pix_mp;
864 plane = pix_mp->plane_fmt;
865 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT &&
866 pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS)
867 info = find_fmt(pix_mp->pixelformat);
868 pix_mp->num_planes = 1;
869
870 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH);
871 pix_mp->width = vic_round_dim(pix_mp->width, info->width_div);
872
873 pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT);
874 pix_mp->height = vic_round_dim(pix_mp->height,
875 info->height_div);
876
877 pix_mp->field = V4L2_FIELD_NONE;
878 plane->bytesperline =
879 pix_mp->width * info->bytesperline_mult;
880 plane->sizeimage = pix_mp->width * pix_mp->height *
881 info->sizeimage_mult / info->sizeimage_div;
882 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
883 plane->sizeimage += sizeof(struct fwht_cframe_hdr);
884 break;
885 default:
886 return -EINVAL;
887 }
888
889 return 0;
890 }
891
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)892 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
893 struct v4l2_format *f)
894 {
895 struct vicodec_ctx *ctx = file2ctx(file);
896 struct v4l2_pix_format_mplane *pix_mp;
897 struct v4l2_pix_format *pix;
898
899 switch (f->type) {
900 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
901 if (multiplanar)
902 return -EINVAL;
903 pix = &f->fmt.pix;
904 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
905 find_fmt(f->fmt.pix.pixelformat)->id;
906 pix->colorspace = ctx->state.colorspace;
907 pix->xfer_func = ctx->state.xfer_func;
908 pix->ycbcr_enc = ctx->state.ycbcr_enc;
909 pix->quantization = ctx->state.quantization;
910 break;
911 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
912 if (!multiplanar)
913 return -EINVAL;
914 pix_mp = &f->fmt.pix_mp;
915 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
916 find_fmt(pix_mp->pixelformat)->id;
917 pix_mp->colorspace = ctx->state.colorspace;
918 pix_mp->xfer_func = ctx->state.xfer_func;
919 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
920 pix_mp->quantization = ctx->state.quantization;
921 break;
922 default:
923 return -EINVAL;
924 }
925
926 return vidioc_try_fmt(ctx, f);
927 }
928
vidioc_try_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)929 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
930 struct v4l2_format *f)
931 {
932 struct vicodec_ctx *ctx = file2ctx(file);
933 struct v4l2_pix_format_mplane *pix_mp;
934 struct v4l2_pix_format *pix;
935
936 switch (f->type) {
937 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
938 if (multiplanar)
939 return -EINVAL;
940 pix = &f->fmt.pix;
941 if (ctx->is_enc)
942 pix->pixelformat = find_fmt(pix->pixelformat)->id;
943 else if (ctx->is_stateless)
944 pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS;
945 else
946 pix->pixelformat = V4L2_PIX_FMT_FWHT;
947 if (!pix->colorspace)
948 pix->colorspace = V4L2_COLORSPACE_REC709;
949 break;
950 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
951 if (!multiplanar)
952 return -EINVAL;
953 pix_mp = &f->fmt.pix_mp;
954 if (ctx->is_enc)
955 pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id;
956 else if (ctx->is_stateless)
957 pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS;
958 else
959 pix_mp->pixelformat = V4L2_PIX_FMT_FWHT;
960 if (!pix_mp->colorspace)
961 pix_mp->colorspace = V4L2_COLORSPACE_REC709;
962 break;
963 default:
964 return -EINVAL;
965 }
966
967 return vidioc_try_fmt(ctx, f);
968 }
969
vidioc_s_fmt(struct vicodec_ctx * ctx,struct v4l2_format * f)970 static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
971 {
972 struct vicodec_q_data *q_data;
973 struct vb2_queue *vq;
974 bool fmt_changed = true;
975 struct v4l2_pix_format_mplane *pix_mp;
976 struct v4l2_pix_format *pix;
977
978 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
979 if (!vq)
980 return -EINVAL;
981
982 q_data = get_q_data(ctx, f->type);
983 if (!q_data)
984 return -EINVAL;
985
986 switch (f->type) {
987 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
988 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
989 pix = &f->fmt.pix;
990 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
991 fmt_changed =
992 !q_data->info ||
993 q_data->info->id != pix->pixelformat ||
994 q_data->coded_width != pix->width ||
995 q_data->coded_height != pix->height;
996
997 if (vb2_is_busy(vq) && fmt_changed)
998 return -EBUSY;
999
1000 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
1001 q_data->info = &pixfmt_fwht;
1002 else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS)
1003 q_data->info = &pixfmt_stateless_fwht;
1004 else
1005 q_data->info = find_fmt(pix->pixelformat);
1006 q_data->coded_width = pix->width;
1007 q_data->coded_height = pix->height;
1008 q_data->sizeimage = pix->sizeimage;
1009 break;
1010 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1011 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1012 pix_mp = &f->fmt.pix_mp;
1013 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
1014 fmt_changed =
1015 !q_data->info ||
1016 q_data->info->id != pix_mp->pixelformat ||
1017 q_data->coded_width != pix_mp->width ||
1018 q_data->coded_height != pix_mp->height;
1019
1020 if (vb2_is_busy(vq) && fmt_changed)
1021 return -EBUSY;
1022
1023 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
1024 q_data->info = &pixfmt_fwht;
1025 else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS)
1026 q_data->info = &pixfmt_stateless_fwht;
1027 else
1028 q_data->info = find_fmt(pix_mp->pixelformat);
1029 q_data->coded_width = pix_mp->width;
1030 q_data->coded_height = pix_mp->height;
1031 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
1032 break;
1033 default:
1034 return -EINVAL;
1035 }
1036
1037 dprintk(ctx->dev,
1038 "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n",
1039 f->type, q_data->coded_width, q_data->coded_height,
1040 q_data->info->id);
1041
1042 return 0;
1043 }
1044
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1045 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
1046 struct v4l2_format *f)
1047 {
1048 int ret;
1049
1050 ret = vidioc_try_fmt_vid_cap(file, priv, f);
1051 if (ret)
1052 return ret;
1053
1054 return vidioc_s_fmt(file2ctx(file), f);
1055 }
1056
vidioc_s_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)1057 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
1058 struct v4l2_format *f)
1059 {
1060 struct vicodec_ctx *ctx = file2ctx(file);
1061 struct vicodec_q_data *q_data;
1062 struct vicodec_q_data *q_data_cap;
1063 struct v4l2_pix_format *pix;
1064 struct v4l2_pix_format_mplane *pix_mp;
1065 u32 coded_w = 0, coded_h = 0;
1066 unsigned int size = 0;
1067 int ret;
1068
1069 q_data = get_q_data(ctx, f->type);
1070 q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
1071
1072 ret = vidioc_try_fmt_vid_out(file, priv, f);
1073 if (ret)
1074 return ret;
1075
1076 if (ctx->is_enc) {
1077 struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
1078 struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1079 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1080 const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ?
1081 &pixfmt_stateless_fwht : &pixfmt_fwht;
1082
1083 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1084 coded_w = f->fmt.pix.width;
1085 coded_h = f->fmt.pix.height;
1086 } else {
1087 coded_w = f->fmt.pix_mp.width;
1088 coded_h = f->fmt.pix_mp.height;
1089 }
1090 if (vb2_is_busy(vq) && (coded_w != q_data->coded_width ||
1091 coded_h != q_data->coded_height))
1092 return -EBUSY;
1093 size = coded_w * coded_h *
1094 info->sizeimage_mult / info->sizeimage_div;
1095 if (!ctx->is_stateless)
1096 size += sizeof(struct fwht_cframe_hdr);
1097
1098 if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage)
1099 return -EBUSY;
1100 }
1101
1102 ret = vidioc_s_fmt(file2ctx(file), f);
1103 if (!ret) {
1104 if (ctx->is_enc) {
1105 q_data->visible_width = coded_w;
1106 q_data->visible_height = coded_h;
1107 q_data_cap->coded_width = coded_w;
1108 q_data_cap->coded_height = coded_h;
1109 q_data_cap->sizeimage = size;
1110 }
1111
1112 switch (f->type) {
1113 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1114 pix = &f->fmt.pix;
1115 ctx->state.colorspace = pix->colorspace;
1116 ctx->state.xfer_func = pix->xfer_func;
1117 ctx->state.ycbcr_enc = pix->ycbcr_enc;
1118 ctx->state.quantization = pix->quantization;
1119 break;
1120 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1121 pix_mp = &f->fmt.pix_mp;
1122 ctx->state.colorspace = pix_mp->colorspace;
1123 ctx->state.xfer_func = pix_mp->xfer_func;
1124 ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
1125 ctx->state.quantization = pix_mp->quantization;
1126 break;
1127 default:
1128 break;
1129 }
1130 }
1131 return ret;
1132 }
1133
vidioc_g_selection(struct file * file,void * priv,struct v4l2_selection * s)1134 static int vidioc_g_selection(struct file *file, void *priv,
1135 struct v4l2_selection *s)
1136 {
1137 struct vicodec_ctx *ctx = file2ctx(file);
1138 struct vicodec_q_data *q_data;
1139
1140 q_data = get_q_data(ctx, s->type);
1141 if (!q_data)
1142 return -EINVAL;
1143 /*
1144 * encoder supports only cropping on the OUTPUT buffer
1145 * decoder supports only composing on the CAPTURE buffer
1146 */
1147 if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1148 switch (s->target) {
1149 case V4L2_SEL_TGT_CROP:
1150 s->r.left = 0;
1151 s->r.top = 0;
1152 s->r.width = q_data->visible_width;
1153 s->r.height = q_data->visible_height;
1154 return 0;
1155 case V4L2_SEL_TGT_CROP_DEFAULT:
1156 case V4L2_SEL_TGT_CROP_BOUNDS:
1157 s->r.left = 0;
1158 s->r.top = 0;
1159 s->r.width = q_data->coded_width;
1160 s->r.height = q_data->coded_height;
1161 return 0;
1162 }
1163 } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1164 switch (s->target) {
1165 case V4L2_SEL_TGT_COMPOSE:
1166 s->r.left = 0;
1167 s->r.top = 0;
1168 s->r.width = q_data->visible_width;
1169 s->r.height = q_data->visible_height;
1170 return 0;
1171 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1172 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1173 s->r.left = 0;
1174 s->r.top = 0;
1175 s->r.width = q_data->coded_width;
1176 s->r.height = q_data->coded_height;
1177 return 0;
1178 }
1179 }
1180 return -EINVAL;
1181 }
1182
vidioc_s_selection(struct file * file,void * priv,struct v4l2_selection * s)1183 static int vidioc_s_selection(struct file *file, void *priv,
1184 struct v4l2_selection *s)
1185 {
1186 struct vicodec_ctx *ctx = file2ctx(file);
1187 struct vicodec_q_data *q_data;
1188
1189 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1190 return -EINVAL;
1191
1192 q_data = get_q_data(ctx, s->type);
1193 if (!q_data)
1194 return -EINVAL;
1195
1196 if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP)
1197 return -EINVAL;
1198
1199 s->r.left = 0;
1200 s->r.top = 0;
1201 q_data->visible_width = clamp(s->r.width, MIN_WIDTH,
1202 q_data->coded_width);
1203 s->r.width = q_data->visible_width;
1204 q_data->visible_height = clamp(s->r.height, MIN_HEIGHT,
1205 q_data->coded_height);
1206 s->r.height = q_data->visible_height;
1207 return 0;
1208 }
1209
vicodec_encoder_cmd(struct file * file,void * fh,struct v4l2_encoder_cmd * ec)1210 static int vicodec_encoder_cmd(struct file *file, void *fh,
1211 struct v4l2_encoder_cmd *ec)
1212 {
1213 struct vicodec_ctx *ctx = file2ctx(file);
1214 int ret;
1215
1216 ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
1217 if (ret < 0)
1218 return ret;
1219
1220 if (!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
1221 return 0;
1222
1223 ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec);
1224 if (ret < 0)
1225 return ret;
1226
1227 if (ec->cmd == V4L2_ENC_CMD_STOP &&
1228 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1229 v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1230
1231 if (ec->cmd == V4L2_ENC_CMD_START &&
1232 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1233 vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
1234
1235 return 0;
1236 }
1237
vicodec_decoder_cmd(struct file * file,void * fh,struct v4l2_decoder_cmd * dc)1238 static int vicodec_decoder_cmd(struct file *file, void *fh,
1239 struct v4l2_decoder_cmd *dc)
1240 {
1241 struct vicodec_ctx *ctx = file2ctx(file);
1242 int ret;
1243
1244 /*
1245 * This ioctl should not be used with a stateless codec that doesn't
1246 * support holding buffers and the associated flush command.
1247 */
1248 WARN_ON(ctx->is_stateless);
1249
1250 ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
1251 if (ret < 0)
1252 return ret;
1253
1254 if (!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
1255 return 0;
1256
1257 ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc);
1258 if (ret < 0)
1259 return ret;
1260
1261 if (dc->cmd == V4L2_DEC_CMD_STOP &&
1262 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1263 v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1264
1265 if (dc->cmd == V4L2_DEC_CMD_START &&
1266 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1267 vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
1268
1269 return 0;
1270 }
1271
vicodec_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)1272 static int vicodec_enum_framesizes(struct file *file, void *fh,
1273 struct v4l2_frmsizeenum *fsize)
1274 {
1275 switch (fsize->pixel_format) {
1276 case V4L2_PIX_FMT_FWHT_STATELESS:
1277 break;
1278 case V4L2_PIX_FMT_FWHT:
1279 break;
1280 default:
1281 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
1282 break;
1283 return -EINVAL;
1284 }
1285
1286 if (fsize->index)
1287 return -EINVAL;
1288
1289 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1290
1291 fsize->stepwise.min_width = MIN_WIDTH;
1292 fsize->stepwise.max_width = MAX_WIDTH;
1293 fsize->stepwise.step_width = 8;
1294 fsize->stepwise.min_height = MIN_HEIGHT;
1295 fsize->stepwise.max_height = MAX_HEIGHT;
1296 fsize->stepwise.step_height = 8;
1297
1298 return 0;
1299 }
1300
vicodec_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)1301 static int vicodec_subscribe_event(struct v4l2_fh *fh,
1302 const struct v4l2_event_subscription *sub)
1303 {
1304 struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh);
1305
1306 switch (sub->type) {
1307 case V4L2_EVENT_SOURCE_CHANGE:
1308 if (ctx->is_enc)
1309 return -EINVAL;
1310 fallthrough;
1311 case V4L2_EVENT_EOS:
1312 if (ctx->is_stateless)
1313 return -EINVAL;
1314 return v4l2_event_subscribe(fh, sub, 0, NULL);
1315 default:
1316 return v4l2_ctrl_subscribe_event(fh, sub);
1317 }
1318 }
1319
1320 static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
1321 .vidioc_querycap = vidioc_querycap,
1322
1323 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1324 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1325 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1326 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1327
1328 .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
1329 .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
1330 .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
1331
1332 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1333 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1334 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1335 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1336
1337 .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
1338 .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
1339 .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
1340
1341 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1342 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1343 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1344 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
1345 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
1346 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
1347 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
1348 .vidioc_remove_bufs = v4l2_m2m_ioctl_remove_bufs,
1349
1350 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1351 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
1352
1353 .vidioc_g_selection = vidioc_g_selection,
1354 .vidioc_s_selection = vidioc_s_selection,
1355
1356 .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
1357 .vidioc_encoder_cmd = vicodec_encoder_cmd,
1358 .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
1359 .vidioc_decoder_cmd = vicodec_decoder_cmd,
1360 .vidioc_enum_framesizes = vicodec_enum_framesizes,
1361
1362 .vidioc_subscribe_event = vicodec_subscribe_event,
1363 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1364 };
1365
1366
1367 /*
1368 * Queue operations
1369 */
1370
vicodec_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])1371 static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1372 unsigned int *nplanes, unsigned int sizes[],
1373 struct device *alloc_devs[])
1374 {
1375 struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
1376 struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
1377 unsigned int size = q_data->sizeimage;
1378
1379 if (*nplanes)
1380 return sizes[0] < size ? -EINVAL : 0;
1381
1382 *nplanes = 1;
1383 sizes[0] = size;
1384 q_data->vb2_sizeimage = size;
1385 return 0;
1386 }
1387
vicodec_buf_out_validate(struct vb2_buffer * vb)1388 static int vicodec_buf_out_validate(struct vb2_buffer *vb)
1389 {
1390 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1391
1392 vbuf->field = V4L2_FIELD_NONE;
1393 return 0;
1394 }
1395
vicodec_buf_prepare(struct vb2_buffer * vb)1396 static int vicodec_buf_prepare(struct vb2_buffer *vb)
1397 {
1398 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1399 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1400 struct vicodec_q_data *q_data;
1401
1402 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1403
1404 q_data = get_q_data(ctx, vb->vb2_queue->type);
1405 if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1406 if (vbuf->field == V4L2_FIELD_ANY)
1407 vbuf->field = V4L2_FIELD_NONE;
1408 if (vbuf->field != V4L2_FIELD_NONE) {
1409 dprintk(ctx->dev, "%s field isn't supported\n",
1410 __func__);
1411 return -EINVAL;
1412 }
1413 }
1414
1415 if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) {
1416 dprintk(ctx->dev,
1417 "%s data will not fit into plane (%lu < %lu)\n",
1418 __func__, vb2_plane_size(vb, 0),
1419 (long)q_data->vb2_sizeimage);
1420 return -EINVAL;
1421 }
1422
1423 return 0;
1424 }
1425
vicodec_buf_queue(struct vb2_buffer * vb)1426 static void vicodec_buf_queue(struct vb2_buffer *vb)
1427 {
1428 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1429 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1430 unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
1431 u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
1432 u8 *p = p_src;
1433 struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1434 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1435 struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1436 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1437 bool header_valid = false;
1438 static const struct v4l2_event rs_event = {
1439 .type = V4L2_EVENT_SOURCE_CHANGE,
1440 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
1441 };
1442
1443 if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&
1444 vb2_is_streaming(vb->vb2_queue) &&
1445 v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
1446 unsigned int i;
1447
1448 for (i = 0; i < vb->num_planes; i++)
1449 vb2_set_plane_payload(vb, i, 0);
1450
1451 vbuf->field = V4L2_FIELD_NONE;
1452 vbuf->sequence =
1453 get_q_data(ctx, vb->vb2_queue->type)->sequence++;
1454
1455 v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
1456 v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1457 return;
1458 }
1459
1460 /* buf_queue handles only the first source change event */
1461 if (ctx->first_source_change_sent) {
1462 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1463 return;
1464 }
1465
1466 /*
1467 * if both queues are streaming, the source change event is
1468 * handled in job_ready
1469 */
1470 if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) {
1471 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1472 return;
1473 }
1474
1475 /*
1476 * source change event is relevant only for the stateful decoder
1477 * in the compressed stream
1478 */
1479 if (ctx->is_stateless || ctx->is_enc ||
1480 V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) {
1481 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1482 return;
1483 }
1484
1485 do {
1486 enum vb2_buffer_state state =
1487 get_next_header(ctx, &p, p_src + sz - p);
1488
1489 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
1490 v4l2_m2m_buf_done(vbuf, state);
1491 return;
1492 }
1493 header_valid = is_header_valid(&ctx->state.header);
1494 /*
1495 * p points right after the end of the header in the
1496 * buffer. If the header is invalid we set p to point
1497 * to the next byte after the start of the header
1498 */
1499 if (!header_valid) {
1500 p = p - sizeof(struct fwht_cframe_hdr) + 1;
1501 if (p < p_src)
1502 p = p_src;
1503 ctx->header_size = 0;
1504 ctx->comp_magic_cnt = 0;
1505 }
1506
1507 } while (!header_valid);
1508
1509 ctx->cur_buf_offset = p - p_src;
1510 update_capture_data_from_header(ctx);
1511 ctx->first_source_change_sent = true;
1512 v4l2_event_queue_fh(&ctx->fh, &rs_event);
1513 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1514 }
1515
vicodec_return_bufs(struct vb2_queue * q,u32 state)1516 static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
1517 {
1518 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1519 struct vb2_v4l2_buffer *vbuf;
1520
1521 for (;;) {
1522 if (V4L2_TYPE_IS_OUTPUT(q->type))
1523 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1524 else
1525 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1526 if (vbuf == NULL)
1527 return;
1528 v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
1529 &ctx->hdl);
1530 spin_lock(ctx->lock);
1531 v4l2_m2m_buf_done(vbuf, state);
1532 spin_unlock(ctx->lock);
1533 }
1534 }
1535
total_frame_size(struct vicodec_q_data * q_data)1536 static unsigned int total_frame_size(struct vicodec_q_data *q_data)
1537 {
1538 unsigned int size;
1539 unsigned int chroma_div;
1540
1541 if (!q_data->info) {
1542 WARN_ON(1);
1543 return 0;
1544 }
1545 size = q_data->coded_width * q_data->coded_height;
1546 chroma_div = q_data->info->width_div * q_data->info->height_div;
1547
1548 if (q_data->info->components_num == 4)
1549 return 2 * size + 2 * (size / chroma_div);
1550 else if (q_data->info->components_num == 3)
1551 return size + 2 * (size / chroma_div);
1552 return size;
1553 }
1554
vicodec_start_streaming(struct vb2_queue * q,unsigned int count)1555 static int vicodec_start_streaming(struct vb2_queue *q,
1556 unsigned int count)
1557 {
1558 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1559 struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
1560 struct v4l2_fwht_state *state = &ctx->state;
1561 const struct v4l2_fwht_pixfmt_info *info = q_data->info;
1562 unsigned int size = q_data->coded_width * q_data->coded_height;
1563 unsigned int chroma_div;
1564 unsigned int total_planes_size;
1565 u8 *new_comp_frame = NULL;
1566
1567 chroma_div = info->width_div * info->height_div;
1568 q_data->sequence = 0;
1569
1570 v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
1571
1572 state->gop_cnt = 0;
1573
1574 if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1575 (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->is_enc))
1576 return 0;
1577
1578 if (info->id == V4L2_PIX_FMT_FWHT ||
1579 info->id == V4L2_PIX_FMT_FWHT_STATELESS) {
1580 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1581 return -EINVAL;
1582 }
1583 total_planes_size = total_frame_size(q_data);
1584 ctx->comp_max_size = total_planes_size;
1585
1586 state->visible_width = q_data->visible_width;
1587 state->visible_height = q_data->visible_height;
1588 state->coded_width = q_data->coded_width;
1589 state->coded_height = q_data->coded_height;
1590 state->stride = q_data->coded_width *
1591 info->bytesperline_mult;
1592
1593 if (ctx->is_stateless) {
1594 state->ref_stride = state->stride;
1595 return 0;
1596 }
1597 state->ref_stride = q_data->coded_width * info->luma_alpha_step;
1598
1599 state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL);
1600 state->ref_frame.luma = state->ref_frame.buf;
1601 new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1602
1603 if (!state->ref_frame.luma || !new_comp_frame) {
1604 kvfree(state->ref_frame.luma);
1605 kvfree(new_comp_frame);
1606 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1607 return -ENOMEM;
1608 }
1609 /*
1610 * if state->compressed_frame was already allocated then
1611 * it contain data of the first frame of the new resolution
1612 */
1613 if (state->compressed_frame) {
1614 if (ctx->comp_size > ctx->comp_max_size)
1615 ctx->comp_size = ctx->comp_max_size;
1616
1617 memcpy(new_comp_frame,
1618 state->compressed_frame, ctx->comp_size);
1619 }
1620
1621 kvfree(state->compressed_frame);
1622 state->compressed_frame = new_comp_frame;
1623
1624 if (info->components_num < 3) {
1625 state->ref_frame.cb = NULL;
1626 state->ref_frame.cr = NULL;
1627 state->ref_frame.alpha = NULL;
1628 return 0;
1629 }
1630
1631 state->ref_frame.cb = state->ref_frame.luma + size;
1632 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1633
1634 if (info->components_num == 4)
1635 state->ref_frame.alpha =
1636 state->ref_frame.cr + size / chroma_div;
1637 else
1638 state->ref_frame.alpha = NULL;
1639
1640 return 0;
1641 }
1642
vicodec_stop_streaming(struct vb2_queue * q)1643 static void vicodec_stop_streaming(struct vb2_queue *q)
1644 {
1645 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1646
1647 vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1648
1649 v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
1650
1651 if (V4L2_TYPE_IS_OUTPUT(q->type) &&
1652 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1653 v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1654
1655 if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
1656 ctx->first_source_change_sent = false;
1657
1658 if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1659 (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
1660 if (!ctx->is_stateless)
1661 kvfree(ctx->state.ref_frame.buf);
1662 ctx->state.ref_frame.buf = NULL;
1663 ctx->state.ref_frame.luma = NULL;
1664 ctx->comp_max_size = 0;
1665 ctx->source_changed = false;
1666 }
1667 if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) {
1668 ctx->cur_buf_offset = 0;
1669 ctx->comp_size = 0;
1670 ctx->header_size = 0;
1671 ctx->comp_magic_cnt = 0;
1672 ctx->comp_has_frame = false;
1673 ctx->comp_has_next_frame = false;
1674 }
1675 }
1676
vicodec_buf_request_complete(struct vb2_buffer * vb)1677 static void vicodec_buf_request_complete(struct vb2_buffer *vb)
1678 {
1679 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1680
1681 v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
1682 }
1683
1684
1685 static const struct vb2_ops vicodec_qops = {
1686 .queue_setup = vicodec_queue_setup,
1687 .buf_out_validate = vicodec_buf_out_validate,
1688 .buf_prepare = vicodec_buf_prepare,
1689 .buf_queue = vicodec_buf_queue,
1690 .buf_request_complete = vicodec_buf_request_complete,
1691 .start_streaming = vicodec_start_streaming,
1692 .stop_streaming = vicodec_stop_streaming,
1693 };
1694
queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)1695 static int queue_init(void *priv, struct vb2_queue *src_vq,
1696 struct vb2_queue *dst_vq)
1697 {
1698 struct vicodec_ctx *ctx = priv;
1699 int ret;
1700
1701 src_vq->type = (multiplanar ?
1702 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1703 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1704 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1705 src_vq->drv_priv = ctx;
1706 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1707 src_vq->ops = &vicodec_qops;
1708 src_vq->mem_ops = &vb2_vmalloc_memops;
1709 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1710 if (ctx->is_enc) {
1711 src_vq->lock = &ctx->dev->stateful_enc.mutex;
1712 src_vq->min_reqbufs_allocation = VICODEC_REC_BUFS;
1713 } else if (ctx->is_stateless) {
1714 src_vq->lock = &ctx->dev->stateless_dec.mutex;
1715 } else {
1716 src_vq->lock = &ctx->dev->stateful_dec.mutex;
1717 }
1718 src_vq->supports_requests = ctx->is_stateless;
1719 src_vq->requires_requests = ctx->is_stateless;
1720 ret = vb2_queue_init(src_vq);
1721 if (ret)
1722 return ret;
1723
1724 dst_vq->type = (multiplanar ?
1725 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1726 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1727 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1728 dst_vq->max_num_buffers = 64;
1729 dst_vq->drv_priv = ctx;
1730 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1731 dst_vq->ops = &vicodec_qops;
1732 dst_vq->mem_ops = &vb2_vmalloc_memops;
1733 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1734 dst_vq->lock = src_vq->lock;
1735 if (!ctx->is_stateless && !ctx->is_enc)
1736 dst_vq->min_reqbufs_allocation = VICODEC_REC_BUFS;
1737
1738 return vb2_queue_init(dst_vq);
1739 }
1740
vicodec_try_ctrl(struct v4l2_ctrl * ctrl)1741 static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl)
1742 {
1743 struct vicodec_ctx *ctx = container_of(ctrl->handler,
1744 struct vicodec_ctx, hdl);
1745 const struct v4l2_ctrl_fwht_params *params;
1746 struct vicodec_q_data *q_dst = get_q_data(ctx,
1747 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1748
1749 switch (ctrl->id) {
1750 case V4L2_CID_STATELESS_FWHT_PARAMS:
1751 if (!q_dst->info)
1752 return -EINVAL;
1753 params = ctrl->p_new.p_fwht_params;
1754 if (params->width > q_dst->coded_width ||
1755 params->width < MIN_WIDTH ||
1756 params->height > q_dst->coded_height ||
1757 params->height < MIN_HEIGHT)
1758 return -EINVAL;
1759 if (!validate_by_version(params->flags, params->version))
1760 return -EINVAL;
1761 if (!validate_stateless_params_flags(params, q_dst->info))
1762 return -EINVAL;
1763 return 0;
1764 default:
1765 return 0;
1766 }
1767 return 0;
1768 }
1769
update_header_from_stateless_params(struct vicodec_ctx * ctx,const struct v4l2_ctrl_fwht_params * params)1770 static void update_header_from_stateless_params(struct vicodec_ctx *ctx,
1771 const struct v4l2_ctrl_fwht_params *params)
1772 {
1773 struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
1774
1775 p_hdr->magic1 = FWHT_MAGIC1;
1776 p_hdr->magic2 = FWHT_MAGIC2;
1777 p_hdr->version = htonl(params->version);
1778 p_hdr->width = htonl(params->width);
1779 p_hdr->height = htonl(params->height);
1780 p_hdr->flags = htonl(params->flags);
1781 p_hdr->colorspace = htonl(params->colorspace);
1782 p_hdr->xfer_func = htonl(params->xfer_func);
1783 p_hdr->ycbcr_enc = htonl(params->ycbcr_enc);
1784 p_hdr->quantization = htonl(params->quantization);
1785 }
1786
vicodec_s_ctrl(struct v4l2_ctrl * ctrl)1787 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1788 {
1789 struct vicodec_ctx *ctx = container_of(ctrl->handler,
1790 struct vicodec_ctx, hdl);
1791 const struct v4l2_ctrl_fwht_params *params;
1792
1793 switch (ctrl->id) {
1794 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1795 ctx->state.gop_size = ctrl->val;
1796 return 0;
1797 case V4L2_CID_FWHT_I_FRAME_QP:
1798 ctx->state.i_frame_qp = ctrl->val;
1799 return 0;
1800 case V4L2_CID_FWHT_P_FRAME_QP:
1801 ctx->state.p_frame_qp = ctrl->val;
1802 return 0;
1803 case V4L2_CID_STATELESS_FWHT_PARAMS:
1804 params = ctrl->p_new.p_fwht_params;
1805 update_header_from_stateless_params(ctx, params);
1806 ctx->state.ref_frame_ts = params->backward_ref_ts;
1807 return 0;
1808 }
1809 return -EINVAL;
1810 }
1811
1812 static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
1813 .s_ctrl = vicodec_s_ctrl,
1814 .try_ctrl = vicodec_try_ctrl,
1815 };
1816
1817 static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = {
1818 .ops = &vicodec_ctrl_ops,
1819 .id = V4L2_CID_STATELESS_FWHT_PARAMS,
1820 .elem_size = sizeof(struct v4l2_ctrl_fwht_params),
1821 };
1822
1823 /*
1824 * File operations
1825 */
vicodec_open(struct file * file)1826 static int vicodec_open(struct file *file)
1827 {
1828 const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0);
1829 struct video_device *vfd = video_devdata(file);
1830 struct vicodec_dev *dev = video_drvdata(file);
1831 struct vicodec_ctx *ctx = NULL;
1832 struct v4l2_ctrl_handler *hdl;
1833 unsigned int raw_size;
1834 unsigned int comp_size;
1835 int rc = 0;
1836
1837 if (mutex_lock_interruptible(vfd->lock))
1838 return -ERESTARTSYS;
1839 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1840 if (!ctx) {
1841 rc = -ENOMEM;
1842 goto open_unlock;
1843 }
1844
1845 if (vfd == &dev->stateful_enc.vfd)
1846 ctx->is_enc = true;
1847 else if (vfd == &dev->stateless_dec.vfd)
1848 ctx->is_stateless = true;
1849
1850 v4l2_fh_init(&ctx->fh, video_devdata(file));
1851 file->private_data = &ctx->fh;
1852 ctx->dev = dev;
1853 hdl = &ctx->hdl;
1854 v4l2_ctrl_handler_init(hdl, 5);
1855 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1856 1, 16, 1, 10);
1857 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP,
1858 1, 31, 1, 20);
1859 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP,
1860 1, 31, 1, 20);
1861
1862 if (ctx->is_stateless)
1863 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL);
1864 else
1865 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, ctx->is_enc ?
1866 V4L2_CID_MIN_BUFFERS_FOR_OUTPUT :
1867 V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
1868 VICODEC_REC_BUFS, VICODEC_REC_BUFS, 1,
1869 VICODEC_REC_BUFS);
1870
1871 if (hdl->error) {
1872 rc = hdl->error;
1873 v4l2_ctrl_handler_free(hdl);
1874 kfree(ctx);
1875 goto open_unlock;
1876 }
1877 ctx->fh.ctrl_handler = hdl;
1878 v4l2_ctrl_handler_setup(hdl);
1879
1880 if (ctx->is_enc)
1881 ctx->q_data[V4L2_M2M_SRC].info = info;
1882 else if (ctx->is_stateless)
1883 ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht;
1884 else
1885 ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht;
1886 ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
1887 ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
1888 ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
1889 ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
1890 raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div;
1891 comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult /
1892 pixfmt_fwht.sizeimage_div;
1893 if (ctx->is_enc)
1894 ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size;
1895 else if (ctx->is_stateless)
1896 ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size;
1897 else
1898 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1899 comp_size + sizeof(struct fwht_cframe_hdr);
1900 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1901 if (ctx->is_enc) {
1902 ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
1903 ctx->q_data[V4L2_M2M_DST].sizeimage =
1904 comp_size + sizeof(struct fwht_cframe_hdr);
1905 } else {
1906 ctx->q_data[V4L2_M2M_DST].info = info;
1907 ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size;
1908 }
1909
1910 ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1911
1912 if (ctx->is_enc) {
1913 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev,
1914 ctx, &queue_init);
1915 ctx->lock = &dev->stateful_enc.lock;
1916 } else if (ctx->is_stateless) {
1917 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev,
1918 ctx, &queue_init);
1919 ctx->lock = &dev->stateless_dec.lock;
1920 } else {
1921 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev,
1922 ctx, &queue_init);
1923 ctx->lock = &dev->stateful_dec.lock;
1924 }
1925
1926 if (IS_ERR(ctx->fh.m2m_ctx)) {
1927 rc = PTR_ERR(ctx->fh.m2m_ctx);
1928
1929 v4l2_ctrl_handler_free(hdl);
1930 v4l2_fh_exit(&ctx->fh);
1931 kfree(ctx);
1932 goto open_unlock;
1933 }
1934
1935 v4l2_fh_add(&ctx->fh);
1936
1937 open_unlock:
1938 mutex_unlock(vfd->lock);
1939 return rc;
1940 }
1941
vicodec_release(struct file * file)1942 static int vicodec_release(struct file *file)
1943 {
1944 struct video_device *vfd = video_devdata(file);
1945 struct vicodec_ctx *ctx = file2ctx(file);
1946
1947 mutex_lock(vfd->lock);
1948 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1949 mutex_unlock(vfd->lock);
1950 v4l2_fh_del(&ctx->fh);
1951 v4l2_fh_exit(&ctx->fh);
1952 v4l2_ctrl_handler_free(&ctx->hdl);
1953 kvfree(ctx->state.compressed_frame);
1954 kfree(ctx);
1955
1956 return 0;
1957 }
1958
vicodec_request_validate(struct media_request * req)1959 static int vicodec_request_validate(struct media_request *req)
1960 {
1961 struct media_request_object *obj;
1962 struct v4l2_ctrl_handler *parent_hdl, *hdl;
1963 struct vicodec_ctx *ctx = NULL;
1964 struct v4l2_ctrl *ctrl;
1965 unsigned int count;
1966
1967 list_for_each_entry(obj, &req->objects, list) {
1968 struct vb2_buffer *vb;
1969
1970 if (vb2_request_object_is_buffer(obj)) {
1971 vb = container_of(obj, struct vb2_buffer, req_obj);
1972 ctx = vb2_get_drv_priv(vb->vb2_queue);
1973
1974 break;
1975 }
1976 }
1977
1978 if (!ctx) {
1979 pr_err("No buffer was provided with the request\n");
1980 return -ENOENT;
1981 }
1982
1983 count = vb2_request_buffer_cnt(req);
1984 if (!count) {
1985 v4l2_info(&ctx->dev->v4l2_dev,
1986 "No buffer was provided with the request\n");
1987 return -ENOENT;
1988 } else if (count > 1) {
1989 v4l2_info(&ctx->dev->v4l2_dev,
1990 "More than one buffer was provided with the request\n");
1991 return -EINVAL;
1992 }
1993
1994 parent_hdl = &ctx->hdl;
1995
1996 hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
1997 if (!hdl) {
1998 v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n");
1999 return -ENOENT;
2000 }
2001 ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl,
2002 vicodec_ctrl_stateless_state.id);
2003 v4l2_ctrl_request_hdl_put(hdl);
2004 if (!ctrl) {
2005 v4l2_info(&ctx->dev->v4l2_dev,
2006 "Missing required codec control\n");
2007 return -ENOENT;
2008 }
2009
2010 return vb2_request_validate(req);
2011 }
2012
2013 static const struct v4l2_file_operations vicodec_fops = {
2014 .owner = THIS_MODULE,
2015 .open = vicodec_open,
2016 .release = vicodec_release,
2017 .poll = v4l2_m2m_fop_poll,
2018 .unlocked_ioctl = video_ioctl2,
2019 .mmap = v4l2_m2m_fop_mmap,
2020 };
2021
2022 static const struct video_device vicodec_videodev = {
2023 .name = VICODEC_NAME,
2024 .vfl_dir = VFL_DIR_M2M,
2025 .fops = &vicodec_fops,
2026 .ioctl_ops = &vicodec_ioctl_ops,
2027 .minor = -1,
2028 .release = video_device_release_empty,
2029 };
2030
2031 static const struct media_device_ops vicodec_m2m_media_ops = {
2032 .req_validate = vicodec_request_validate,
2033 .req_queue = v4l2_m2m_request_queue,
2034 };
2035
2036 static const struct v4l2_m2m_ops m2m_ops = {
2037 .device_run = device_run,
2038 .job_ready = job_ready,
2039 };
2040
register_instance(struct vicodec_dev * dev,struct vicodec_dev_instance * dev_instance,const char * name,bool is_enc,bool is_stateless)2041 static int register_instance(struct vicodec_dev *dev,
2042 struct vicodec_dev_instance *dev_instance,
2043 const char *name, bool is_enc, bool is_stateless)
2044 {
2045 struct video_device *vfd;
2046 int ret;
2047
2048 spin_lock_init(&dev_instance->lock);
2049 mutex_init(&dev_instance->mutex);
2050 dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops);
2051 if (IS_ERR(dev_instance->m2m_dev)) {
2052 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n");
2053 return PTR_ERR(dev_instance->m2m_dev);
2054 }
2055
2056 dev_instance->vfd = vicodec_videodev;
2057 vfd = &dev_instance->vfd;
2058 vfd->lock = &dev_instance->mutex;
2059 vfd->v4l2_dev = &dev->v4l2_dev;
2060 strscpy(vfd->name, name, sizeof(vfd->name));
2061 vfd->device_caps = V4L2_CAP_STREAMING |
2062 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
2063 if (is_enc || is_stateless) {
2064 v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
2065 v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
2066 }
2067 if (!is_enc) {
2068 v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
2069 v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
2070 }
2071 video_set_drvdata(vfd, dev);
2072
2073 ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
2074 if (ret) {
2075 v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name);
2076 v4l2_m2m_release(dev_instance->m2m_dev);
2077 return ret;
2078 }
2079 v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n",
2080 name, vfd->num);
2081 return 0;
2082 }
2083
vicodec_v4l2_dev_release(struct v4l2_device * v4l2_dev)2084 static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev)
2085 {
2086 struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev);
2087
2088 v4l2_device_unregister(&dev->v4l2_dev);
2089 v4l2_m2m_release(dev->stateful_enc.m2m_dev);
2090 v4l2_m2m_release(dev->stateful_dec.m2m_dev);
2091 v4l2_m2m_release(dev->stateless_dec.m2m_dev);
2092 #ifdef CONFIG_MEDIA_CONTROLLER
2093 media_device_cleanup(&dev->mdev);
2094 #endif
2095 kfree(dev);
2096 }
2097
vicodec_probe(struct platform_device * pdev)2098 static int vicodec_probe(struct platform_device *pdev)
2099 {
2100 struct vicodec_dev *dev;
2101 int ret;
2102
2103 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2104 if (!dev)
2105 return -ENOMEM;
2106
2107 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
2108 if (ret)
2109 goto free_dev;
2110
2111 dev->v4l2_dev.release = vicodec_v4l2_dev_release;
2112
2113 #ifdef CONFIG_MEDIA_CONTROLLER
2114 dev->mdev.dev = &pdev->dev;
2115 strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
2116 strscpy(dev->mdev.bus_info, "platform:vicodec",
2117 sizeof(dev->mdev.bus_info));
2118 media_device_init(&dev->mdev);
2119 dev->mdev.ops = &vicodec_m2m_media_ops;
2120 dev->v4l2_dev.mdev = &dev->mdev;
2121 #endif
2122
2123 platform_set_drvdata(pdev, dev);
2124
2125 ret = register_instance(dev, &dev->stateful_enc, "stateful-encoder",
2126 true, false);
2127 if (ret)
2128 goto unreg_dev;
2129
2130 ret = register_instance(dev, &dev->stateful_dec, "stateful-decoder",
2131 false, false);
2132 if (ret)
2133 goto unreg_sf_enc;
2134
2135 ret = register_instance(dev, &dev->stateless_dec, "stateless-decoder",
2136 false, true);
2137 if (ret)
2138 goto unreg_sf_dec;
2139
2140 #ifdef CONFIG_MEDIA_CONTROLLER
2141 ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev,
2142 &dev->stateful_enc.vfd,
2143 MEDIA_ENT_F_PROC_VIDEO_ENCODER);
2144 if (ret) {
2145 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n");
2146 goto unreg_m2m;
2147 }
2148
2149 ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev,
2150 &dev->stateful_dec.vfd,
2151 MEDIA_ENT_F_PROC_VIDEO_DECODER);
2152 if (ret) {
2153 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n");
2154 goto unreg_m2m_sf_enc_mc;
2155 }
2156
2157 ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev,
2158 &dev->stateless_dec.vfd,
2159 MEDIA_ENT_F_PROC_VIDEO_DECODER);
2160 if (ret) {
2161 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n");
2162 goto unreg_m2m_sf_dec_mc;
2163 }
2164
2165 ret = media_device_register(&dev->mdev);
2166 if (ret) {
2167 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
2168 goto unreg_m2m_sl_dec_mc;
2169 }
2170 #endif
2171 return 0;
2172
2173 #ifdef CONFIG_MEDIA_CONTROLLER
2174 unreg_m2m_sl_dec_mc:
2175 v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
2176 unreg_m2m_sf_dec_mc:
2177 v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
2178 unreg_m2m_sf_enc_mc:
2179 v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
2180 unreg_m2m:
2181 video_unregister_device(&dev->stateless_dec.vfd);
2182 v4l2_m2m_release(dev->stateless_dec.m2m_dev);
2183 #endif
2184 unreg_sf_dec:
2185 video_unregister_device(&dev->stateful_dec.vfd);
2186 v4l2_m2m_release(dev->stateful_dec.m2m_dev);
2187 unreg_sf_enc:
2188 video_unregister_device(&dev->stateful_enc.vfd);
2189 v4l2_m2m_release(dev->stateful_enc.m2m_dev);
2190 unreg_dev:
2191 v4l2_device_unregister(&dev->v4l2_dev);
2192 free_dev:
2193 kfree(dev);
2194
2195 return ret;
2196 }
2197
vicodec_remove(struct platform_device * pdev)2198 static void vicodec_remove(struct platform_device *pdev)
2199 {
2200 struct vicodec_dev *dev = platform_get_drvdata(pdev);
2201
2202 v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
2203
2204 #ifdef CONFIG_MEDIA_CONTROLLER
2205 media_device_unregister(&dev->mdev);
2206 v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
2207 v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
2208 v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
2209 #endif
2210
2211 video_unregister_device(&dev->stateful_enc.vfd);
2212 video_unregister_device(&dev->stateful_dec.vfd);
2213 video_unregister_device(&dev->stateless_dec.vfd);
2214 v4l2_device_put(&dev->v4l2_dev);
2215 }
2216
2217 static struct platform_driver vicodec_pdrv = {
2218 .probe = vicodec_probe,
2219 .remove = vicodec_remove,
2220 .driver = {
2221 .name = VICODEC_NAME,
2222 },
2223 };
2224
vicodec_exit(void)2225 static void __exit vicodec_exit(void)
2226 {
2227 platform_driver_unregister(&vicodec_pdrv);
2228 platform_device_unregister(&vicodec_pdev);
2229 }
2230
vicodec_init(void)2231 static int __init vicodec_init(void)
2232 {
2233 int ret;
2234
2235 ret = platform_device_register(&vicodec_pdev);
2236 if (ret)
2237 return ret;
2238
2239 ret = platform_driver_register(&vicodec_pdrv);
2240 if (ret)
2241 platform_device_unregister(&vicodec_pdev);
2242
2243 return ret;
2244 }
2245
2246 module_init(vicodec_init);
2247 module_exit(vicodec_exit);
2248