1 // SPDX-License-Identifier: GPL-2.0-only
3 * A virtual codec example device.
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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.
12 #include <linux/module.h>
13 #include <linux/delay.h>
15 #include <linux/sched.h>
16 #include <linux/slab.h>
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>
26 #include "codec-v4l2-fwht.h"
28 MODULE_DESCRIPTION("Virtual codec device");
29 MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
30 MODULE_LICENSE("GPL v2");
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");
37 static unsigned int debug;
38 module_param(debug, uint, 0644);
39 MODULE_PARM_DESC(debug, " activates debug info");
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
47 #define dprintk(dev, fmt, arg...) \
48 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
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;
63 static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
64 V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0
67 static void vicodec_dev_release(struct device *dev)
71 static struct platform_device vicodec_pdev = {
73 .dev.release = vicodec_dev_release,
76 /* Per-queue, driver-specific private data */
77 struct vicodec_q_data {
80 unsigned int sizeimage;
81 unsigned int sequence;
82 const struct v4l2_fwht_pixfmt_info *info;
91 struct v4l2_device v4l2_dev;
92 struct video_device enc_vfd;
93 struct video_device dec_vfd;
94 #ifdef CONFIG_MEDIA_CONTROLLER
95 struct media_device mdev;
98 struct mutex enc_mutex;
99 struct mutex dec_mutex;
103 struct v4l2_m2m_dev *enc_dev;
104 struct v4l2_m2m_dev *dec_dev;
109 struct vicodec_dev *dev;
113 struct v4l2_ctrl_handler hdl;
115 struct vb2_v4l2_buffer *last_src_buf;
116 struct vb2_v4l2_buffer *last_dst_buf;
118 /* Source and destination queue data */
119 struct vicodec_q_data q_data[2];
120 struct v4l2_fwht_state state;
128 bool comp_has_next_frame;
131 static inline struct vicodec_ctx *file2ctx(struct file *file)
133 return container_of(file->private_data, struct vicodec_ctx, fh);
136 static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
137 enum v4l2_buf_type type)
140 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
141 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
142 return &ctx->q_data[V4L2_M2M_SRC];
143 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
144 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
145 return &ctx->q_data[V4L2_M2M_DST];
153 static int device_process(struct vicodec_ctx *ctx,
154 struct vb2_v4l2_buffer *in_vb,
155 struct vb2_v4l2_buffer *out_vb)
157 struct vicodec_dev *dev = ctx->dev;
158 struct vicodec_q_data *q_cap;
159 struct v4l2_fwht_state *state = &ctx->state;
163 q_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
165 p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
167 p_in = state->compressed_frame;
168 p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
169 if (!p_in || !p_out) {
170 v4l2_err(&dev->v4l2_dev,
171 "Acquiring kernel pointers to buffers failed\n");
176 struct vicodec_q_data *q_out;
178 q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
179 state->info = q_out->info;
180 ret = v4l2_fwht_encode(state, p_in, p_out);
183 vb2_set_plane_payload(&out_vb->vb2_buf, 0, ret);
185 state->info = q_cap->info;
186 ret = v4l2_fwht_decode(state, p_in, p_out);
189 vb2_set_plane_payload(&out_vb->vb2_buf, 0, q_cap->sizeimage);
192 out_vb->sequence = q_cap->sequence++;
193 out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
195 if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
196 out_vb->timecode = in_vb->timecode;
197 out_vb->field = in_vb->field;
198 out_vb->flags &= ~V4L2_BUF_FLAG_LAST;
199 out_vb->flags |= in_vb->flags &
200 (V4L2_BUF_FLAG_TIMECODE |
201 V4L2_BUF_FLAG_KEYFRAME |
202 V4L2_BUF_FLAG_PFRAME |
203 V4L2_BUF_FLAG_BFRAME |
204 V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
213 /* device_run() - prepares and starts the device */
214 static void device_run(void *priv)
216 static const struct v4l2_event eos_event = {
217 .type = V4L2_EVENT_EOS
219 struct vicodec_ctx *ctx = priv;
220 struct vicodec_dev *dev = ctx->dev;
221 struct vb2_v4l2_buffer *src_buf, *dst_buf;
222 struct vicodec_q_data *q_out;
225 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
226 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
227 q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
229 state = VB2_BUF_STATE_DONE;
230 if (device_process(ctx, src_buf, dst_buf))
231 state = VB2_BUF_STATE_ERROR;
232 ctx->last_dst_buf = dst_buf;
234 spin_lock(ctx->lock);
235 if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
236 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
237 v4l2_event_queue_fh(&ctx->fh, &eos_event);
240 src_buf->sequence = q_out->sequence++;
241 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
242 v4l2_m2m_buf_done(src_buf, state);
243 } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
244 src_buf->sequence = q_out->sequence++;
245 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
246 v4l2_m2m_buf_done(src_buf, state);
247 ctx->cur_buf_offset = 0;
248 ctx->comp_has_next_frame = false;
250 v4l2_m2m_buf_done(dst_buf, state);
252 ctx->comp_magic_cnt = 0;
253 ctx->comp_has_frame = false;
254 spin_unlock(ctx->lock);
257 v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
259 v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
262 static void job_remove_out_buf(struct vicodec_ctx *ctx, u32 state)
264 struct vb2_v4l2_buffer *src_buf;
265 struct vicodec_q_data *q_out;
267 q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
268 spin_lock(ctx->lock);
269 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
270 src_buf->sequence = q_out->sequence++;
271 v4l2_m2m_buf_done(src_buf, state);
272 ctx->cur_buf_offset = 0;
273 spin_unlock(ctx->lock);
276 static int job_ready(void *priv)
278 static const u8 magic[] = {
279 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
281 struct vicodec_ctx *ctx = priv;
282 struct vb2_v4l2_buffer *src_buf;
288 if (ctx->is_enc || ctx->comp_has_frame)
292 ctx->comp_has_next_frame = false;
293 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
296 p_out = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
297 sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
298 p = p_out + ctx->cur_buf_offset;
300 state = VB2_BUF_STATE_DONE;
302 if (!ctx->comp_size) {
303 state = VB2_BUF_STATE_ERROR;
304 for (; p < p_out + sz; p++) {
307 p = memchr(p, magic[ctx->comp_magic_cnt], sz);
309 ctx->comp_magic_cnt = 0;
312 copy = sizeof(magic) - ctx->comp_magic_cnt;
313 if (p_out + sz - p < copy)
314 copy = p_out + sz - p;
315 memcpy(ctx->state.compressed_frame + ctx->comp_magic_cnt,
317 ctx->comp_magic_cnt += copy;
318 if (!memcmp(ctx->state.compressed_frame, magic,
319 ctx->comp_magic_cnt)) {
321 state = VB2_BUF_STATE_DONE;
324 ctx->comp_magic_cnt = 0;
326 if (ctx->comp_magic_cnt < sizeof(magic)) {
327 job_remove_out_buf(ctx, state);
330 ctx->comp_size = sizeof(magic);
332 if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
333 struct fwht_cframe_hdr *p_hdr =
334 (struct fwht_cframe_hdr *)ctx->state.compressed_frame;
335 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->comp_size;
337 if (copy > p_out + sz - p)
338 copy = p_out + sz - p;
339 memcpy(ctx->state.compressed_frame + ctx->comp_size,
342 ctx->comp_size += copy;
343 if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
344 job_remove_out_buf(ctx, state);
347 ctx->comp_frame_size = ntohl(p_hdr->size) + sizeof(*p_hdr);
348 if (ctx->comp_frame_size > ctx->comp_max_size)
349 ctx->comp_frame_size = ctx->comp_max_size;
351 if (ctx->comp_size < ctx->comp_frame_size) {
352 u32 copy = ctx->comp_frame_size - ctx->comp_size;
354 if (copy > p_out + sz - p)
355 copy = p_out + sz - p;
356 memcpy(ctx->state.compressed_frame + ctx->comp_size,
359 ctx->comp_size += copy;
360 if (ctx->comp_size < ctx->comp_frame_size) {
361 job_remove_out_buf(ctx, state);
365 ctx->cur_buf_offset = p - p_out;
366 ctx->comp_has_frame = true;
367 ctx->comp_has_next_frame = false;
368 if (sz - ctx->cur_buf_offset >= sizeof(struct fwht_cframe_hdr)) {
369 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
370 u32 frame_size = ntohl(p_hdr->size);
371 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
373 if (!memcmp(p, magic, sizeof(magic)))
374 ctx->comp_has_next_frame = remaining >= frame_size;
383 static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
385 const struct v4l2_fwht_pixfmt_info *info =
386 v4l2_fwht_find_pixfmt(fmt);
389 info = v4l2_fwht_get_pixfmt(0);
393 static int vidioc_querycap(struct file *file, void *priv,
394 struct v4l2_capability *cap)
396 strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1);
397 strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
398 snprintf(cap->bus_info, sizeof(cap->bus_info),
399 "platform:%s", VICODEC_NAME);
403 static int enum_fmt(struct v4l2_fmtdesc *f, bool is_enc, bool is_out)
405 bool is_uncomp = (is_enc && is_out) || (!is_enc && !is_out);
407 if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
409 if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
413 const struct v4l2_fwht_pixfmt_info *info =
414 v4l2_fwht_get_pixfmt(f->index);
418 f->pixelformat = info->id;
422 f->pixelformat = V4L2_PIX_FMT_FWHT;
427 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
428 struct v4l2_fmtdesc *f)
430 struct vicodec_ctx *ctx = file2ctx(file);
432 return enum_fmt(f, ctx->is_enc, false);
435 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
436 struct v4l2_fmtdesc *f)
438 struct vicodec_ctx *ctx = file2ctx(file);
440 return enum_fmt(f, ctx->is_enc, true);
443 static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
445 struct vb2_queue *vq;
446 struct vicodec_q_data *q_data;
447 struct v4l2_pix_format_mplane *pix_mp;
448 struct v4l2_pix_format *pix;
449 const struct v4l2_fwht_pixfmt_info *info;
451 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
455 q_data = get_q_data(ctx, f->type);
459 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
460 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
464 pix->width = q_data->width;
465 pix->height = q_data->height;
466 pix->field = V4L2_FIELD_NONE;
467 pix->pixelformat = info->id;
468 pix->bytesperline = q_data->width * info->bytesperline_mult;
469 pix->sizeimage = q_data->sizeimage;
470 pix->colorspace = ctx->state.colorspace;
471 pix->xfer_func = ctx->state.xfer_func;
472 pix->ycbcr_enc = ctx->state.ycbcr_enc;
473 pix->quantization = ctx->state.quantization;
476 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
477 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
480 pix_mp = &f->fmt.pix_mp;
481 pix_mp->width = q_data->width;
482 pix_mp->height = q_data->height;
483 pix_mp->field = V4L2_FIELD_NONE;
484 pix_mp->pixelformat = info->id;
485 pix_mp->num_planes = 1;
486 pix_mp->plane_fmt[0].bytesperline =
487 q_data->width * info->bytesperline_mult;
488 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
489 pix_mp->colorspace = ctx->state.colorspace;
490 pix_mp->xfer_func = ctx->state.xfer_func;
491 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
492 pix_mp->quantization = ctx->state.quantization;
493 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
494 memset(pix_mp->plane_fmt[0].reserved, 0,
495 sizeof(pix_mp->plane_fmt[0].reserved));
503 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
504 struct v4l2_format *f)
506 return vidioc_g_fmt(file2ctx(file), f);
509 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
510 struct v4l2_format *f)
512 return vidioc_g_fmt(file2ctx(file), f);
515 static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
517 struct v4l2_pix_format_mplane *pix_mp;
518 struct v4l2_pix_format *pix;
519 struct v4l2_plane_pix_format *plane;
520 const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
523 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
524 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
526 if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
527 info = find_fmt(pix->pixelformat);
528 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7;
529 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
530 pix->field = V4L2_FIELD_NONE;
532 pix->width * info->bytesperline_mult;
533 pix->sizeimage = pix->width * pix->height *
534 info->sizeimage_mult / info->sizeimage_div;
535 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
536 pix->sizeimage += sizeof(struct fwht_cframe_hdr);
538 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
539 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
540 pix_mp = &f->fmt.pix_mp;
541 plane = pix_mp->plane_fmt;
542 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
543 info = find_fmt(pix_mp->pixelformat);
544 pix_mp->num_planes = 1;
545 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7;
547 clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
548 pix_mp->field = V4L2_FIELD_NONE;
549 plane->bytesperline =
550 pix_mp->width * info->bytesperline_mult;
551 plane->sizeimage = pix_mp->width * pix_mp->height *
552 info->sizeimage_mult / info->sizeimage_div;
553 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
554 plane->sizeimage += sizeof(struct fwht_cframe_hdr);
555 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
556 memset(plane->reserved, 0, sizeof(plane->reserved));
565 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
566 struct v4l2_format *f)
568 struct vicodec_ctx *ctx = file2ctx(file);
569 struct v4l2_pix_format_mplane *pix_mp;
570 struct v4l2_pix_format *pix;
573 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
577 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
578 find_fmt(f->fmt.pix.pixelformat)->id;
579 pix->colorspace = ctx->state.colorspace;
580 pix->xfer_func = ctx->state.xfer_func;
581 pix->ycbcr_enc = ctx->state.ycbcr_enc;
582 pix->quantization = ctx->state.quantization;
584 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
587 pix_mp = &f->fmt.pix_mp;
588 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
589 find_fmt(pix_mp->pixelformat)->id;
590 pix_mp->colorspace = ctx->state.colorspace;
591 pix_mp->xfer_func = ctx->state.xfer_func;
592 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
593 pix_mp->quantization = ctx->state.quantization;
599 return vidioc_try_fmt(ctx, f);
602 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
603 struct v4l2_format *f)
605 struct vicodec_ctx *ctx = file2ctx(file);
606 struct v4l2_pix_format_mplane *pix_mp;
607 struct v4l2_pix_format *pix;
610 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
614 pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
615 find_fmt(pix->pixelformat)->id;
616 if (!pix->colorspace)
617 pix->colorspace = V4L2_COLORSPACE_REC709;
619 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
622 pix_mp = &f->fmt.pix_mp;
623 pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
624 find_fmt(pix_mp->pixelformat)->id;
625 if (!pix_mp->colorspace)
626 pix_mp->colorspace = V4L2_COLORSPACE_REC709;
632 return vidioc_try_fmt(ctx, f);
635 static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
637 struct vicodec_q_data *q_data;
638 struct vb2_queue *vq;
639 bool fmt_changed = true;
640 struct v4l2_pix_format_mplane *pix_mp;
641 struct v4l2_pix_format *pix;
643 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
647 q_data = get_q_data(ctx, f->type);
652 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
653 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
655 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
657 q_data->info->id != pix->pixelformat ||
658 q_data->width != pix->width ||
659 q_data->height != pix->height;
661 if (vb2_is_busy(vq) && fmt_changed)
664 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
665 q_data->info = &pixfmt_fwht;
667 q_data->info = find_fmt(pix->pixelformat);
668 q_data->width = pix->width;
669 q_data->height = pix->height;
670 q_data->sizeimage = pix->sizeimage;
672 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
673 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
674 pix_mp = &f->fmt.pix_mp;
675 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
677 q_data->info->id != pix_mp->pixelformat ||
678 q_data->width != pix_mp->width ||
679 q_data->height != pix_mp->height;
681 if (vb2_is_busy(vq) && fmt_changed)
684 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
685 q_data->info = &pixfmt_fwht;
687 q_data->info = find_fmt(pix_mp->pixelformat);
688 q_data->width = pix_mp->width;
689 q_data->height = pix_mp->height;
690 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
697 "Setting format for type %d, wxh: %dx%d, fourcc: %08x\n",
698 f->type, q_data->width, q_data->height, q_data->info->id);
703 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
704 struct v4l2_format *f)
708 ret = vidioc_try_fmt_vid_cap(file, priv, f);
712 return vidioc_s_fmt(file2ctx(file), f);
715 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
716 struct v4l2_format *f)
718 struct vicodec_ctx *ctx = file2ctx(file);
719 struct v4l2_pix_format_mplane *pix_mp;
720 struct v4l2_pix_format *pix;
723 ret = vidioc_try_fmt_vid_out(file, priv, f);
727 ret = vidioc_s_fmt(file2ctx(file), f);
730 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
731 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
733 ctx->state.colorspace = pix->colorspace;
734 ctx->state.xfer_func = pix->xfer_func;
735 ctx->state.ycbcr_enc = pix->ycbcr_enc;
736 ctx->state.quantization = pix->quantization;
738 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
739 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
740 pix_mp = &f->fmt.pix_mp;
741 ctx->state.colorspace = pix_mp->colorspace;
742 ctx->state.xfer_func = pix_mp->xfer_func;
743 ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
744 ctx->state.quantization = pix_mp->quantization;
753 static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
755 static const struct v4l2_event eos_event = {
756 .type = V4L2_EVENT_EOS
759 spin_lock(ctx->lock);
760 ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
761 if (!ctx->last_src_buf && ctx->last_dst_buf) {
762 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
763 v4l2_event_queue_fh(&ctx->fh, &eos_event);
765 spin_unlock(ctx->lock);
768 static int vicodec_try_encoder_cmd(struct file *file, void *fh,
769 struct v4l2_encoder_cmd *ec)
771 if (ec->cmd != V4L2_ENC_CMD_STOP)
774 if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
780 static int vicodec_encoder_cmd(struct file *file, void *fh,
781 struct v4l2_encoder_cmd *ec)
783 struct vicodec_ctx *ctx = file2ctx(file);
786 ret = vicodec_try_encoder_cmd(file, fh, ec);
790 vicodec_mark_last_buf(ctx);
794 static int vicodec_try_decoder_cmd(struct file *file, void *fh,
795 struct v4l2_decoder_cmd *dc)
797 if (dc->cmd != V4L2_DEC_CMD_STOP)
800 if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
803 if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
809 static int vicodec_decoder_cmd(struct file *file, void *fh,
810 struct v4l2_decoder_cmd *dc)
812 struct vicodec_ctx *ctx = file2ctx(file);
815 ret = vicodec_try_decoder_cmd(file, fh, dc);
819 vicodec_mark_last_buf(ctx);
823 static int vicodec_enum_framesizes(struct file *file, void *fh,
824 struct v4l2_frmsizeenum *fsize)
826 switch (fsize->pixel_format) {
827 case V4L2_PIX_FMT_FWHT:
830 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
838 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
840 fsize->stepwise.min_width = MIN_WIDTH;
841 fsize->stepwise.max_width = MAX_WIDTH;
842 fsize->stepwise.step_width = 8;
843 fsize->stepwise.min_height = MIN_HEIGHT;
844 fsize->stepwise.max_height = MAX_HEIGHT;
845 fsize->stepwise.step_height = 8;
850 static int vicodec_subscribe_event(struct v4l2_fh *fh,
851 const struct v4l2_event_subscription *sub)
855 return v4l2_event_subscribe(fh, sub, 0, NULL);
857 return v4l2_ctrl_subscribe_event(fh, sub);
861 static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
862 .vidioc_querycap = vidioc_querycap,
864 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
865 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
866 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
867 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
869 .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
870 .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
871 .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
872 .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
874 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
875 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
876 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
877 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
879 .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
880 .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
881 .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
882 .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
884 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
885 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
886 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
887 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
888 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
889 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
890 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
892 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
893 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
895 .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
896 .vidioc_encoder_cmd = vicodec_encoder_cmd,
897 .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
898 .vidioc_decoder_cmd = vicodec_decoder_cmd,
899 .vidioc_enum_framesizes = vicodec_enum_framesizes,
901 .vidioc_subscribe_event = vicodec_subscribe_event,
902 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
910 static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
911 unsigned int *nplanes, unsigned int sizes[],
912 struct device *alloc_devs[])
914 struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
915 struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
916 unsigned int size = q_data->sizeimage;
919 return sizes[0] < size ? -EINVAL : 0;
926 static int vicodec_buf_prepare(struct vb2_buffer *vb)
928 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
929 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
930 struct vicodec_q_data *q_data;
932 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
934 q_data = get_q_data(ctx, vb->vb2_queue->type);
935 if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
936 if (vbuf->field == V4L2_FIELD_ANY)
937 vbuf->field = V4L2_FIELD_NONE;
938 if (vbuf->field != V4L2_FIELD_NONE) {
939 dprintk(ctx->dev, "%s field isn't supported\n",
945 if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
947 "%s data will not fit into plane (%lu < %lu)\n",
948 __func__, vb2_plane_size(vb, 0),
949 (long)q_data->sizeimage);
956 static void vicodec_buf_queue(struct vb2_buffer *vb)
958 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
959 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
961 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
964 static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
966 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
967 struct vb2_v4l2_buffer *vbuf;
970 if (V4L2_TYPE_IS_OUTPUT(q->type))
971 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
973 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
976 spin_lock(ctx->lock);
977 v4l2_m2m_buf_done(vbuf, state);
978 spin_unlock(ctx->lock);
982 static int vicodec_start_streaming(struct vb2_queue *q,
985 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
986 struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
987 struct v4l2_fwht_state *state = &ctx->state;
988 unsigned int size = q_data->width * q_data->height;
989 const struct v4l2_fwht_pixfmt_info *info = q_data->info;
990 unsigned int chroma_div = info->width_div * info->height_div;
991 unsigned int total_planes_size;
994 * we don't know ahead how many components are in the encoding type
995 * V4L2_PIX_FMT_FWHT, so we will allocate space for 4 planes.
997 if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4)
998 total_planes_size = 2 * size + 2 * (size / chroma_div);
999 else if (info->components_num == 3)
1000 total_planes_size = size + 2 * (size / chroma_div);
1002 total_planes_size = size;
1004 q_data->sequence = 0;
1006 if (!V4L2_TYPE_IS_OUTPUT(q->type))
1009 state->width = q_data->width;
1010 state->height = q_data->height;
1011 state->ref_frame.width = state->ref_frame.height = 0;
1012 state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
1013 ctx->comp_max_size = total_planes_size + sizeof(struct fwht_cframe_hdr);
1014 state->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1015 if (!state->ref_frame.luma || !state->compressed_frame) {
1016 kvfree(state->ref_frame.luma);
1017 kvfree(state->compressed_frame);
1018 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1021 if (info->id == V4L2_PIX_FMT_FWHT || info->components_num >= 3) {
1022 state->ref_frame.cb = state->ref_frame.luma + size;
1023 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1025 state->ref_frame.cb = NULL;
1026 state->ref_frame.cr = NULL;
1029 if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4)
1030 state->ref_frame.alpha =
1031 state->ref_frame.cr + size / chroma_div;
1033 state->ref_frame.alpha = NULL;
1035 ctx->last_src_buf = NULL;
1036 ctx->last_dst_buf = NULL;
1038 ctx->cur_buf_offset = 0;
1040 ctx->comp_magic_cnt = 0;
1041 ctx->comp_has_frame = false;
1046 static void vicodec_stop_streaming(struct vb2_queue *q)
1048 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1050 vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1052 if (!V4L2_TYPE_IS_OUTPUT(q->type))
1055 kvfree(ctx->state.ref_frame.luma);
1056 kvfree(ctx->state.compressed_frame);
1059 static const struct vb2_ops vicodec_qops = {
1060 .queue_setup = vicodec_queue_setup,
1061 .buf_prepare = vicodec_buf_prepare,
1062 .buf_queue = vicodec_buf_queue,
1063 .start_streaming = vicodec_start_streaming,
1064 .stop_streaming = vicodec_stop_streaming,
1065 .wait_prepare = vb2_ops_wait_prepare,
1066 .wait_finish = vb2_ops_wait_finish,
1069 static int queue_init(void *priv, struct vb2_queue *src_vq,
1070 struct vb2_queue *dst_vq)
1072 struct vicodec_ctx *ctx = priv;
1075 src_vq->type = (multiplanar ?
1076 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1077 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1078 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1079 src_vq->drv_priv = ctx;
1080 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1081 src_vq->ops = &vicodec_qops;
1082 src_vq->mem_ops = &vb2_vmalloc_memops;
1083 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1084 src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1085 &ctx->dev->dec_mutex;
1087 ret = vb2_queue_init(src_vq);
1091 dst_vq->type = (multiplanar ?
1092 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1093 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1094 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1095 dst_vq->drv_priv = ctx;
1096 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1097 dst_vq->ops = &vicodec_qops;
1098 dst_vq->mem_ops = &vb2_vmalloc_memops;
1099 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1100 dst_vq->lock = src_vq->lock;
1102 return vb2_queue_init(dst_vq);
1105 #define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
1106 #define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
1107 #define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
1109 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1111 struct vicodec_ctx *ctx = container_of(ctrl->handler,
1112 struct vicodec_ctx, hdl);
1115 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1116 ctx->state.gop_size = ctrl->val;
1118 case VICODEC_CID_I_FRAME_QP:
1119 ctx->state.i_frame_qp = ctrl->val;
1121 case VICODEC_CID_P_FRAME_QP:
1122 ctx->state.p_frame_qp = ctrl->val;
1128 static struct v4l2_ctrl_ops vicodec_ctrl_ops = {
1129 .s_ctrl = vicodec_s_ctrl,
1132 static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1133 .ops = &vicodec_ctrl_ops,
1134 .id = VICODEC_CID_I_FRAME_QP,
1135 .name = "FWHT I-Frame QP Value",
1136 .type = V4L2_CTRL_TYPE_INTEGER,
1143 static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1144 .ops = &vicodec_ctrl_ops,
1145 .id = VICODEC_CID_P_FRAME_QP,
1146 .name = "FWHT P-Frame QP Value",
1147 .type = V4L2_CTRL_TYPE_INTEGER,
1157 static int vicodec_open(struct file *file)
1159 struct video_device *vfd = video_devdata(file);
1160 struct vicodec_dev *dev = video_drvdata(file);
1161 struct vicodec_ctx *ctx = NULL;
1162 struct v4l2_ctrl_handler *hdl;
1166 if (mutex_lock_interruptible(vfd->lock))
1167 return -ERESTARTSYS;
1168 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1174 if (vfd == &dev->enc_vfd)
1177 v4l2_fh_init(&ctx->fh, video_devdata(file));
1178 file->private_data = &ctx->fh;
1181 v4l2_ctrl_handler_init(hdl, 4);
1182 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1184 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1185 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
1188 v4l2_ctrl_handler_free(hdl);
1192 ctx->fh.ctrl_handler = hdl;
1193 v4l2_ctrl_handler_setup(hdl);
1195 ctx->q_data[V4L2_M2M_SRC].info =
1196 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
1197 ctx->q_data[V4L2_M2M_SRC].width = 1280;
1198 ctx->q_data[V4L2_M2M_SRC].height = 720;
1199 size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1200 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
1202 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1204 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1205 size + sizeof(struct fwht_cframe_hdr);
1206 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1207 ctx->q_data[V4L2_M2M_DST].info =
1208 ctx->is_enc ? &pixfmt_fwht : v4l2_fwht_get_pixfmt(0);
1209 size = 1280 * 720 * ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1210 ctx->q_data[V4L2_M2M_DST].info->sizeimage_div;
1212 ctx->q_data[V4L2_M2M_DST].sizeimage =
1213 size + sizeof(struct fwht_cframe_hdr);
1215 ctx->q_data[V4L2_M2M_DST].sizeimage = size;
1216 ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1219 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1221 ctx->lock = &dev->enc_lock;
1223 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1225 ctx->lock = &dev->dec_lock;
1228 if (IS_ERR(ctx->fh.m2m_ctx)) {
1229 rc = PTR_ERR(ctx->fh.m2m_ctx);
1231 v4l2_ctrl_handler_free(hdl);
1232 v4l2_fh_exit(&ctx->fh);
1237 v4l2_fh_add(&ctx->fh);
1240 mutex_unlock(vfd->lock);
1244 static int vicodec_release(struct file *file)
1246 struct video_device *vfd = video_devdata(file);
1247 struct vicodec_ctx *ctx = file2ctx(file);
1249 v4l2_fh_del(&ctx->fh);
1250 v4l2_fh_exit(&ctx->fh);
1251 v4l2_ctrl_handler_free(&ctx->hdl);
1252 mutex_lock(vfd->lock);
1253 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1254 mutex_unlock(vfd->lock);
1260 static const struct v4l2_file_operations vicodec_fops = {
1261 .owner = THIS_MODULE,
1262 .open = vicodec_open,
1263 .release = vicodec_release,
1264 .poll = v4l2_m2m_fop_poll,
1265 .unlocked_ioctl = video_ioctl2,
1266 .mmap = v4l2_m2m_fop_mmap,
1269 static const struct video_device vicodec_videodev = {
1270 .name = VICODEC_NAME,
1271 .vfl_dir = VFL_DIR_M2M,
1272 .fops = &vicodec_fops,
1273 .ioctl_ops = &vicodec_ioctl_ops,
1275 .release = video_device_release_empty,
1278 static const struct v4l2_m2m_ops m2m_ops = {
1279 .device_run = device_run,
1280 .job_ready = job_ready,
1283 static int vicodec_probe(struct platform_device *pdev)
1285 struct vicodec_dev *dev;
1286 struct video_device *vfd;
1289 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1293 spin_lock_init(&dev->enc_lock);
1294 spin_lock_init(&dev->dec_lock);
1296 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1300 #ifdef CONFIG_MEDIA_CONTROLLER
1301 dev->mdev.dev = &pdev->dev;
1302 strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
1303 media_device_init(&dev->mdev);
1304 dev->v4l2_dev.mdev = &dev->mdev;
1307 mutex_init(&dev->enc_mutex);
1308 mutex_init(&dev->dec_mutex);
1310 platform_set_drvdata(pdev, dev);
1312 dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1313 if (IS_ERR(dev->enc_dev)) {
1314 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1315 ret = PTR_ERR(dev->enc_dev);
1319 dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1320 if (IS_ERR(dev->dec_dev)) {
1321 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1322 ret = PTR_ERR(dev->dec_dev);
1326 dev->enc_vfd = vicodec_videodev;
1327 vfd = &dev->enc_vfd;
1328 vfd->lock = &dev->enc_mutex;
1329 vfd->v4l2_dev = &dev->v4l2_dev;
1330 strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
1331 vfd->device_caps = V4L2_CAP_STREAMING |
1332 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1333 v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1334 v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1335 video_set_drvdata(vfd, dev);
1337 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1339 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1342 v4l2_info(&dev->v4l2_dev,
1343 "Device registered as /dev/video%d\n", vfd->num);
1345 dev->dec_vfd = vicodec_videodev;
1346 vfd = &dev->dec_vfd;
1347 vfd->lock = &dev->dec_mutex;
1348 vfd->v4l2_dev = &dev->v4l2_dev;
1349 vfd->device_caps = V4L2_CAP_STREAMING |
1350 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1351 strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
1352 v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1353 v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1354 video_set_drvdata(vfd, dev);
1356 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1358 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1361 v4l2_info(&dev->v4l2_dev,
1362 "Device registered as /dev/video%d\n", vfd->num);
1364 #ifdef CONFIG_MEDIA_CONTROLLER
1365 ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1366 &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1368 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1372 ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1373 &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1375 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1376 goto unreg_m2m_enc_mc;
1379 ret = media_device_register(&dev->mdev);
1381 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1382 goto unreg_m2m_dec_mc;
1387 #ifdef CONFIG_MEDIA_CONTROLLER
1389 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1391 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1393 video_unregister_device(&dev->dec_vfd);
1396 video_unregister_device(&dev->enc_vfd);
1398 v4l2_m2m_release(dev->dec_dev);
1400 v4l2_m2m_release(dev->enc_dev);
1402 v4l2_device_unregister(&dev->v4l2_dev);
1407 static int vicodec_remove(struct platform_device *pdev)
1409 struct vicodec_dev *dev = platform_get_drvdata(pdev);
1411 v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1413 #ifdef CONFIG_MEDIA_CONTROLLER
1414 media_device_unregister(&dev->mdev);
1415 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1416 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1417 media_device_cleanup(&dev->mdev);
1420 v4l2_m2m_release(dev->enc_dev);
1421 v4l2_m2m_release(dev->dec_dev);
1422 video_unregister_device(&dev->enc_vfd);
1423 video_unregister_device(&dev->dec_vfd);
1424 v4l2_device_unregister(&dev->v4l2_dev);
1429 static struct platform_driver vicodec_pdrv = {
1430 .probe = vicodec_probe,
1431 .remove = vicodec_remove,
1433 .name = VICODEC_NAME,
1437 static void __exit vicodec_exit(void)
1439 platform_driver_unregister(&vicodec_pdrv);
1440 platform_device_unregister(&vicodec_pdev);
1443 static int __init vicodec_init(void)
1447 ret = platform_device_register(&vicodec_pdev);
1451 ret = platform_driver_register(&vicodec_pdrv);
1453 platform_device_unregister(&vicodec_pdev);
1458 module_init(vicodec_init);
1459 module_exit(vicodec_exit);