From ce8cc7a85839af588b753ce4af0832db9c467f45 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 13 Feb 2019 13:44:00 +0000 Subject: [PATCH] staging: bcm2835_codec: Query supported formats from the component The driver was previously working with hard coded tables of which video formats were supported by each component. The components advertise this information via a MMAL parameter, so retrieve the information from there during probe, and store in the state structure for that device. Signed-off-by: Dave Stevenson --- .../bcm2835-codec/bcm2835-v4l2-codec.c | 455 +++++++++++++----- 1 file changed, 327 insertions(+), 128 deletions(-) --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -88,17 +88,12 @@ struct bcm2835_codec_fmt { int bytesperline_align; u32 flags; u32 mmal_fmt; - bool decode_only; - bool encode_only; int size_multiplier_x2; }; -/* Supported raw pixel formats. Those supported for both encode and decode - * must come first, with those only supported for decode coming after (there - * are no formats supported for encode only). - */ -static struct bcm2835_codec_fmt raw_formats[] = { +static const struct bcm2835_codec_fmt supported_formats[] = { { + /* YUV formats */ .fourcc = V4L2_PIX_FMT_YUV420, .depth = 8, .bytesperline_align = 32, @@ -139,7 +134,6 @@ static struct bcm2835_codec_fmt raw_form .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_YUYV, - .encode_only = true, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_UYVY, @@ -147,7 +141,6 @@ static struct bcm2835_codec_fmt raw_form .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_UYVY, - .encode_only = true, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_YVYU, @@ -155,7 +148,6 @@ static struct bcm2835_codec_fmt raw_form .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_YVYU, - .encode_only = true, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_VYUY, @@ -163,15 +155,14 @@ static struct bcm2835_codec_fmt raw_form .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_VYUY, - .encode_only = true, .size_multiplier_x2 = 2, }, { + /* RGB formats */ .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_RGB24, - .encode_only = true, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_BGR24, @@ -179,7 +170,6 @@ static struct bcm2835_codec_fmt raw_form .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_BGR24, - .encode_only = true, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_BGR32, @@ -187,17 +177,126 @@ static struct bcm2835_codec_fmt raw_form .bytesperline_align = 32, .flags = 0, .mmal_fmt = MMAL_ENCODING_BGRA, - .encode_only = true, .size_multiplier_x2 = 2, - }, -}; - -/* Supported encoded formats. Those supported for both encode and decode - * must come first, with those only supported for decode coming after (there - * are no formats supported for encode only). - */ -static struct bcm2835_codec_fmt encoded_formats[] = { - { + }, { + /* Bayer formats */ + /* 8 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB8, + .depth = 8, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .depth = 8, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = 8, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .depth = 8, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, + .size_multiplier_x2 = 2, + }, { + /* 10 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .depth = 10, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .depth = 10, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .depth = 10, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .depth = 10, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, + .size_multiplier_x2 = 2, + }, { + /* 12 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .depth = 12, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .depth = 12, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .depth = 12, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .depth = 12, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, + .size_multiplier_x2 = 2, + }, { + /* 16 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB16, + .depth = 16, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .depth = 16, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .depth = 16, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .depth = 16, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, + .size_multiplier_x2 = 2, + }, { + /* Compressed formats */ .fourcc = V4L2_PIX_FMT_H264, .depth = 0, .flags = V4L2_FMT_FLAG_COMPRESSED, @@ -212,30 +311,22 @@ static struct bcm2835_codec_fmt encoded_ .depth = 0, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal_fmt = MMAL_ENCODING_MP4V, - .decode_only = true, }, { .fourcc = V4L2_PIX_FMT_H263, .depth = 0, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal_fmt = MMAL_ENCODING_H263, - .decode_only = true, }, { .fourcc = V4L2_PIX_FMT_MPEG2, .depth = 0, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal_fmt = MMAL_ENCODING_MP2V, - .decode_only = true, }, { .fourcc = V4L2_PIX_FMT_VP8, .depth = 0, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal_fmt = MMAL_ENCODING_VP8, - .decode_only = true, }, - /* - * This list couold include VP6 and Theorafor decode, but V4L2 doesn't - * support them. - */ }; struct bcm2835_codec_fmt_list { @@ -243,19 +334,6 @@ struct bcm2835_codec_fmt_list { unsigned int num_entries; }; -#define RAW_LIST 0 -#define ENCODED_LIST 1 - -struct bcm2835_codec_fmt_list formats[] = { - { - .list = raw_formats, - .num_entries = ARRAY_SIZE(raw_formats), - }, { - .list = encoded_formats, - .num_entries = ARRAY_SIZE(encoded_formats), - }, -}; - struct m2m_mmal_buffer { struct v4l2_m2m_buffer m2m; struct mmal_buffer mmal; @@ -284,52 +362,6 @@ struct bcm2835_codec_q_data { bool eos_buffer_in_use; /* debug only */ }; -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode, - bool capture) -{ - return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST]; -} - -static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture) -{ - return &get_format_list(decode, capture)->list[0]; -} - -static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode, - bool capture) -{ - struct bcm2835_codec_fmt *fmt; - unsigned int k; - struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); - - for (k = 0; k < fmts->num_entries; k++) { - fmt = &fmts->list[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) - break; - } - - /* - * Some compressed formats are only supported for decoding, not - * encoding. - */ - if (!decode && fmts->list[k].decode_only) - return NULL; - - /* Some pixel formats are only supported for encoding, not decoding. */ - if (decode && fmts->list[k].encode_only) - return NULL; - - if (k == fmts->num_entries) - return NULL; - - return &fmts->list[k]; -} - struct bcm2835_codec_dev { struct platform_device *pdev; @@ -342,6 +374,9 @@ struct bcm2835_codec_dev { /* allocated mmal instance and components */ bool decode; /* Is this instance a decoder? */ + /* The list of formats supported on input and output queues. */ + struct bcm2835_codec_fmt_list supported_fmts[2]; + struct vchiq_mmal_instance *instance; struct v4l2_m2m_dev *m2m_dev; @@ -374,8 +409,59 @@ struct bcm2835_codec_ctx { struct bcm2835_codec_driver { struct bcm2835_codec_dev *encode; struct bcm2835_codec_dev *decode; + struct bcm2835_codec_dev *isp; +}; + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, }; +static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { + if (supported_formats[i].mmal_fmt == mmal_fmt) + return &supported_formats[i]; + } + return NULL; +} + +static inline +struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev, + bool capture) +{ + return &dev->supported_fmts[capture ? 1 : 0]; +} + +static +struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev, + bool capture) +{ + return &dev->supported_fmts[capture ? 1 : 0].list[0]; +} + +static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, + struct bcm2835_codec_dev *dev, + bool capture) +{ + struct bcm2835_codec_fmt *fmt; + unsigned int k; + struct bcm2835_codec_fmt_list *fmts = + &dev->supported_fmts[capture ? 1 : 0]; + + for (k = 0; k < fmts->num_entries; k++) { + fmt = &fmts->list[k]; + if (fmt->fourcc == f->fmt.pix.pixelformat) + break; + } + if (k == fmts->num_entries) + return NULL; + + return &fmts->list[k]; +} + static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) { return container_of(file->private_data, struct bcm2835_codec_ctx, fh); @@ -456,7 +542,6 @@ static inline unsigned int get_bytesperl } static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, - bool decode, struct bcm2835_codec_q_data *q_data, struct vchiq_mmal_port *port) { @@ -473,7 +558,7 @@ static void setup_mmal_port_format(struc port->es.video.frame_rate.den = 1; } else { /* Compressed format - leave resolution as 0 for decode */ - if (decode) { + if (ctx->dev->decode) { port->es.video.width = 0; port->es.video.height = 0; port->es.video.crop.width = 0; @@ -802,22 +887,15 @@ static int vidioc_querycap(struct file * return 0; } -static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture) +static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx, + bool capture) { struct bcm2835_codec_fmt *fmt; - struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); + struct bcm2835_codec_fmt_list *fmts = + get_format_list(ctx->dev, capture); if (f->index < fmts->num_entries) { /* Format found */ - /* Check format isn't a decode only format when encoding */ - if (!decode && - fmts->list[f->index].decode_only) - return -EINVAL; - /* Check format isn't a decode only format when encoding */ - if (decode && - fmts->list[f->index].encode_only) - return -EINVAL; - fmt = &fmts->list[f->index]; f->pixelformat = fmt->fourcc; f->flags = fmt->flags; @@ -833,7 +911,7 @@ static int vidioc_enum_fmt_vid_cap(struc { struct bcm2835_codec_ctx *ctx = file2ctx(file); - return enum_fmt(f, ctx->dev->decode, true); + return enum_fmt(f, ctx, true); } static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, @@ -841,7 +919,7 @@ static int vidioc_enum_fmt_vid_out(struc { struct bcm2835_codec_ctx *ctx = file2ctx(file); - return enum_fmt(f, ctx->dev->decode, false); + return enum_fmt(f, ctx, false); } static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f) @@ -933,11 +1011,11 @@ static int vidioc_try_fmt_vid_cap(struct struct bcm2835_codec_fmt *fmt; struct bcm2835_codec_ctx *ctx = file2ctx(file); - fmt = find_format(f, ctx->dev->decode, true); + fmt = find_format(f, ctx->dev, true); if (!fmt) { - f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, + f->fmt.pix.pixelformat = get_default_format(ctx->dev, true)->fourcc; - fmt = find_format(f, ctx->dev->decode, true); + fmt = find_format(f, ctx->dev, true); } return vidioc_try_fmt(f, fmt); @@ -949,11 +1027,11 @@ static int vidioc_try_fmt_vid_out(struct struct bcm2835_codec_fmt *fmt; struct bcm2835_codec_ctx *ctx = file2ctx(file); - fmt = find_format(f, ctx->dev->decode, false); + fmt = find_format(f, ctx->dev, false); if (!fmt) { - f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, + f->fmt.pix.pixelformat = get_default_format(ctx->dev, false)->fourcc; - fmt = find_format(f, ctx->dev->decode, false); + fmt = find_format(f, ctx->dev, false); } if (!f->fmt.pix.colorspace) @@ -988,7 +1066,7 @@ static int vidioc_s_fmt(struct bcm2835_c return -EBUSY; } - q_data->fmt = find_format(f, ctx->dev->decode, + q_data->fmt = find_format(f, ctx->dev, f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); q_data->crop_width = f->fmt.pix.width; q_data->height = f->fmt.pix.height; @@ -1041,7 +1119,7 @@ static int vidioc_s_fmt(struct bcm2835_c if (!port) return 0; - setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port); + setup_mmal_port_format(ctx, q_data, port); ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); if (ret) { v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", @@ -1064,8 +1142,7 @@ static int vidioc_s_fmt(struct bcm2835_c struct bcm2835_codec_q_data *q_data_dst = &ctx->q_data[V4L2_M2M_DST]; - setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst, - port_dst); + setup_mmal_port_format(ctx, q_data_dst, port_dst); ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst); if (ret) { v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n", @@ -1636,10 +1713,10 @@ static int bcm2835_codec_create_componen MMAL_PARAMETER_ZERO_COPY, &enable, sizeof(enable)); - setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC], + setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC], &ctx->component->input[0]); - setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST], + setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST], &ctx->component->output[0]); ret = vchiq_mmal_port_set_format(dev->instance, @@ -2025,8 +2102,8 @@ static int bcm2835_codec_open(struct fil goto open_unlock; } - ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false); - ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true); + ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); + ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); if (dev->decode) { /* * Input width and height are irrelevant as they will be defined @@ -2209,13 +2286,130 @@ static const struct v4l2_m2m_ops m2m_ops .job_abort = job_abort, }; +/* Size of the array to provide to the VPU when asking for the list of supported + * formats. + * The ISP component currently advertises 33 input formats, so add a small + * overhead on that. + */ +#define MAX_SUPPORTED_ENCODINGS 40 + +/* Populate dev->supported_fmts with the formats supported by those ports. */ +static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev) +{ + struct bcm2835_codec_fmt *list; + struct vchiq_mmal_component *component; + u32 fourccs[MAX_SUPPORTED_ENCODINGS]; + u32 param_size = sizeof(fourccs); + unsigned int i, j, num_encodings; + int ret; + + ret = vchiq_mmal_component_init(dev->instance, + dev->decode ? + "ril.video_decode" : + "ril.video_encode", + &component); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n", + __func__); + return -ENOMEM; + } + + ret = vchiq_mmal_port_parameter_get(dev->instance, + &component->input[0], + MMAL_PARAMETER_SUPPORTED_ENCODINGS, + &fourccs, + ¶m_size); + + if (ret) { + if (ret == MMAL_MSG_STATUS_ENOSPC) { + v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n", + __func__); + num_encodings = MAX_SUPPORTED_ENCODINGS; + } else { + v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n", + __func__, ret); + ret = -EINVAL; + goto destroy_component; + } + } else { + num_encodings = param_size / sizeof(u32); + } + + /* Assume at this stage that all encodings will be supported in V4L2. + * Any that aren't supported will waste a very small amount of memory. + */ + list = devm_kzalloc(&dev->pdev->dev, + sizeof(struct bcm2835_codec_fmt) * num_encodings, + GFP_KERNEL); + if (!list) { + ret = -ENOMEM; + goto destroy_component; + } + dev->supported_fmts[0].list = list; + + for (i = 0, j = 0; i < num_encodings; i++) { + const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]); + + if (fmt) { + list[j] = *fmt; + j++; + } + } + dev->supported_fmts[0].num_entries = j; + + param_size = sizeof(fourccs); + ret = vchiq_mmal_port_parameter_get(dev->instance, + &component->output[0], + MMAL_PARAMETER_SUPPORTED_ENCODINGS, + &fourccs, + ¶m_size); + + if (ret) { + if (ret == MMAL_MSG_STATUS_ENOSPC) { + v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n", + __func__); + num_encodings = MAX_SUPPORTED_ENCODINGS; + } else { + ret = -EINVAL; + goto destroy_component; + } + } else { + num_encodings = param_size / sizeof(u32); + } + /* Assume at this stage that all encodings will be supported in V4L2. */ + list = devm_kzalloc(&dev->pdev->dev, + sizeof(struct bcm2835_codec_fmt) * num_encodings, + GFP_KERNEL); + if (!list) { + ret = -ENOMEM; + goto destroy_component; + } + dev->supported_fmts[1].list = list; + + for (i = 0, j = 0; i < num_encodings; i++) { + const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]); + + if (fmt) { + list[j] = *fmt; + j++; + } + } + dev->supported_fmts[1].num_entries = j; + + ret = 0; + +destroy_component: + vchiq_mmal_component_finalise(dev->instance, component); + + return ret; +} + static int bcm2835_codec_create(struct platform_device *pdev, struct bcm2835_codec_dev **new_dev, bool decode) { struct bcm2835_codec_dev *dev; struct video_device *vfd; - struct vchiq_mmal_instance *instance = NULL; int video_nr; int ret; @@ -2227,10 +2421,18 @@ static int bcm2835_codec_create(struct p dev->decode = decode; - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + ret = vchiq_mmal_init(&dev->instance); if (ret) return ret; + ret = bcm2835_codec_get_supported_fmts(dev); + if (ret) + goto vchiq_finalise; + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto vchiq_finalise; + atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); @@ -2270,12 +2472,7 @@ static int bcm2835_codec_create(struct p goto err_m2m; } - ret = vchiq_mmal_init(&instance); - if (ret < 0) - goto err_m2m; - dev->instance = instance; - - v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n", + v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", dev->decode ? "decode" : "encode"); return 0; @@ -2284,7 +2481,8 @@ err_m2m: video_unregister_device(&dev->vfd); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); - +vchiq_finalise: + vchiq_mmal_finalise(dev->instance); return ret; } @@ -2297,6 +2495,7 @@ static int bcm2835_codec_destroy(struct v4l2_m2m_release(dev->m2m_dev); video_unregister_device(&dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); + vchiq_mmal_finalise(dev->instance); return 0; }