]> Git Repo - linux.git/blame - drivers/media/platform/vicodec/vicodec-core.c
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / media / platform / vicodec / vicodec-core.c
CommitLineData
256bf813
HV
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * A virtual codec example device.
4 *
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 *
7 * This is a virtual codec device driver for testing the codec framework.
8 * It simulates a device that uses memory buffers for both source and
9 * destination and encodes or decodes the data.
10 */
11
12#include <linux/module.h>
13#include <linux/delay.h>
14#include <linux/fs.h>
15#include <linux/sched.h>
16#include <linux/slab.h>
17
18#include <linux/platform_device.h>
19#include <media/v4l2-mem2mem.h>
20#include <media/v4l2-device.h>
21#include <media/v4l2-ioctl.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-event.h>
24#include <media/videobuf2-vmalloc.h>
25
cd12b401 26#include "codec-v4l2-fwht.h"
256bf813
HV
27
28MODULE_DESCRIPTION("Virtual codec device");
29MODULE_AUTHOR("Hans Verkuil <[email protected]>");
30MODULE_LICENSE("GPL v2");
31
32static bool multiplanar;
33module_param(multiplanar, bool, 0444);
34MODULE_PARM_DESC(multiplanar,
35 " use multi-planar API instead of single-planar API");
36
37static unsigned int debug;
38module_param(debug, uint, 0644);
39MODULE_PARM_DESC(debug, " activates debug info");
40
41#define VICODEC_NAME "vicodec"
42#define MAX_WIDTH 4096U
43#define MIN_WIDTH 640U
44#define MAX_HEIGHT 2160U
7cf7b2e9 45#define MIN_HEIGHT 360U
256bf813
HV
46
47#define dprintk(dev, fmt, arg...) \
48 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
49
50
29a7a5e9
HV
51struct pixfmt_info {
52 u32 id;
53 unsigned int bytesperline_mult;
54 unsigned int sizeimage_mult;
55 unsigned int sizeimage_div;
56 unsigned int luma_step;
57 unsigned int chroma_step;
58 /* Chroma plane subsampling */
59 unsigned int width_div;
60 unsigned int height_div;
61};
62
cd12b401 63static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
29a7a5e9
HV
64 V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1
65};
66
256bf813
HV
67static void vicodec_dev_release(struct device *dev)
68{
69}
70
71static struct platform_device vicodec_pdev = {
72 .name = VICODEC_NAME,
73 .dev.release = vicodec_dev_release,
74};
75
76/* Per-queue, driver-specific private data */
77struct vicodec_q_data {
78 unsigned int width;
79 unsigned int height;
256bf813
HV
80 unsigned int sizeimage;
81 unsigned int sequence;
cd12b401 82 const struct v4l2_fwht_pixfmt_info *info;
256bf813
HV
83};
84
85enum {
86 V4L2_M2M_SRC = 0,
87 V4L2_M2M_DST = 1,
88};
89
90struct vicodec_dev {
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;
96#endif
97
98 struct mutex enc_mutex;
99 struct mutex dec_mutex;
100 spinlock_t enc_lock;
101 spinlock_t dec_lock;
102
103 struct v4l2_m2m_dev *enc_dev;
104 struct v4l2_m2m_dev *dec_dev;
105};
106
107struct vicodec_ctx {
108 struct v4l2_fh fh;
109 struct vicodec_dev *dev;
110 bool is_enc;
111 spinlock_t *lock;
112
113 struct v4l2_ctrl_handler hdl;
256bf813 114
256bf813
HV
115 struct vb2_v4l2_buffer *last_src_buf;
116 struct vb2_v4l2_buffer *last_dst_buf;
117
256bf813
HV
118 /* Source and destination queue data */
119 struct vicodec_q_data q_data[2];
cd12b401
HV
120 struct v4l2_fwht_state state;
121
256bf813
HV
122 u32 cur_buf_offset;
123 u32 comp_max_size;
124 u32 comp_size;
125 u32 comp_magic_cnt;
126 u32 comp_frame_size;
127 bool comp_has_frame;
128 bool comp_has_next_frame;
129};
130
256bf813
HV
131static inline struct vicodec_ctx *file2ctx(struct file *file)
132{
133 return container_of(file->private_data, struct vicodec_ctx, fh);
134}
135
136static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
137 enum v4l2_buf_type type)
138{
139 switch (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];
146 default:
147 WARN_ON(1);
148 break;
149 }
150 return NULL;
151}
152
256bf813
HV
153static int device_process(struct vicodec_ctx *ctx,
154 struct vb2_v4l2_buffer *in_vb,
155 struct vb2_v4l2_buffer *out_vb)
156{
157 struct vicodec_dev *dev = ctx->dev;
703fe34b 158 struct vicodec_q_data *q_cap;
cd12b401 159 struct v4l2_fwht_state *state = &ctx->state;
256bf813
HV
160 u8 *p_in, *p_out;
161 int ret;
162
256bf813
HV
163 q_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
164 if (ctx->is_enc)
165 p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
166 else
cd12b401 167 p_in = state->compressed_frame;
256bf813
HV
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");
172 return -EFAULT;
173 }
174
175 if (ctx->is_enc) {
b09d8b25 176 struct vicodec_q_data *q_out;
256bf813 177
b09d8b25
HV
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);
181 if (ret < 0)
182 return ret;
183 vb2_set_plane_payload(&out_vb->vb2_buf, 0, ret);
256bf813 184 } else {
b09d8b25 185 state->info = q_cap->info;
cd12b401 186 ret = v4l2_fwht_decode(state, p_in, p_out);
b09d8b25 187 if (ret < 0)
256bf813 188 return ret;
29a7a5e9 189 vb2_set_plane_payload(&out_vb->vb2_buf, 0, q_cap->sizeimage);
256bf813
HV
190 }
191
192 out_vb->sequence = q_cap->sequence++;
193 out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
194
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);
205
206 return 0;
207}
208
209/*
210 * mem2mem callbacks
211 */
212
213/* device_run() - prepares and starts the device */
214static void device_run(void *priv)
215{
216 static const struct v4l2_event eos_event = {
217 .type = V4L2_EVENT_EOS
218 };
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;
223 u32 state;
224
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);
228
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;
233
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);
238 }
239 if (ctx->is_enc) {
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;
249 }
250 v4l2_m2m_buf_done(dst_buf, state);
251 ctx->comp_size = 0;
252 ctx->comp_magic_cnt = 0;
253 ctx->comp_has_frame = false;
254 spin_unlock(ctx->lock);
255
256 if (ctx->is_enc)
257 v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
258 else
259 v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
260}
261
262static void job_remove_out_buf(struct vicodec_ctx *ctx, u32 state)
263{
264 struct vb2_v4l2_buffer *src_buf;
265 struct vicodec_q_data *q_out;
266
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);
274}
275
276static int job_ready(void *priv)
277{
278 static const u8 magic[] = {
279 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
280 };
281 struct vicodec_ctx *ctx = priv;
282 struct vb2_v4l2_buffer *src_buf;
283 u8 *p_out;
284 u8 *p;
285 u32 sz;
286 u32 state;
287
288 if (ctx->is_enc || ctx->comp_has_frame)
289 return 1;
290
291restart:
292 ctx->comp_has_next_frame = false;
293 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
294 if (!src_buf)
295 return 0;
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;
299
300 state = VB2_BUF_STATE_DONE;
301
302 if (!ctx->comp_size) {
303 state = VB2_BUF_STATE_ERROR;
304 for (; p < p_out + sz; p++) {
305 u32 copy;
306
307 p = memchr(p, magic[ctx->comp_magic_cnt], sz);
308 if (!p) {
309 ctx->comp_magic_cnt = 0;
310 break;
311 }
312 copy = sizeof(magic) - ctx->comp_magic_cnt;
313 if (p_out + sz - p < copy)
314 copy = p_out + sz - p;
cd12b401 315 memcpy(ctx->state.compressed_frame + ctx->comp_magic_cnt,
256bf813
HV
316 p, copy);
317 ctx->comp_magic_cnt += copy;
cd12b401
HV
318 if (!memcmp(ctx->state.compressed_frame, magic,
319 ctx->comp_magic_cnt)) {
256bf813
HV
320 p += copy;
321 state = VB2_BUF_STATE_DONE;
322 break;
323 }
324 ctx->comp_magic_cnt = 0;
325 }
326 if (ctx->comp_magic_cnt < sizeof(magic)) {
327 job_remove_out_buf(ctx, state);
328 goto restart;
329 }
330 ctx->comp_size = sizeof(magic);
331 }
21abebf0
HV
332 if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
333 struct fwht_cframe_hdr *p_hdr =
cd12b401 334 (struct fwht_cframe_hdr *)ctx->state.compressed_frame;
21abebf0 335 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->comp_size;
256bf813
HV
336
337 if (copy > p_out + sz - p)
338 copy = p_out + sz - p;
cd12b401 339 memcpy(ctx->state.compressed_frame + ctx->comp_size,
256bf813
HV
340 p, copy);
341 p += copy;
342 ctx->comp_size += copy;
21abebf0 343 if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
256bf813
HV
344 job_remove_out_buf(ctx, state);
345 goto restart;
346 }
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;
350 }
351 if (ctx->comp_size < ctx->comp_frame_size) {
352 u32 copy = ctx->comp_frame_size - ctx->comp_size;
353
354 if (copy > p_out + sz - p)
355 copy = p_out + sz - p;
cd12b401 356 memcpy(ctx->state.compressed_frame + ctx->comp_size,
256bf813
HV
357 p, copy);
358 p += copy;
359 ctx->comp_size += copy;
360 if (ctx->comp_size < ctx->comp_frame_size) {
361 job_remove_out_buf(ctx, state);
362 goto restart;
363 }
364 }
365 ctx->cur_buf_offset = p - p_out;
366 ctx->comp_has_frame = true;
367 ctx->comp_has_next_frame = false;
21abebf0
HV
368 if (sz - ctx->cur_buf_offset >= sizeof(struct fwht_cframe_hdr)) {
369 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
256bf813
HV
370 u32 frame_size = ntohl(p_hdr->size);
371 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
372
373 if (!memcmp(p, magic, sizeof(magic)))
374 ctx->comp_has_next_frame = remaining >= frame_size;
375 }
376 return 1;
377}
378
256bf813
HV
379/*
380 * video ioctls
381 */
382
cd12b401 383static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
256bf813 384{
cd12b401
HV
385 const struct v4l2_fwht_pixfmt_info *info =
386 v4l2_fwht_find_pixfmt(fmt);
256bf813 387
cd12b401
HV
388 if (!info)
389 info = v4l2_fwht_get_pixfmt(0);
390 return info;
256bf813
HV
391}
392
393static int vidioc_querycap(struct file *file, void *priv,
394 struct v4l2_capability *cap)
395{
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);
400 cap->device_caps = V4L2_CAP_STREAMING |
401 (multiplanar ?
402 V4L2_CAP_VIDEO_M2M_MPLANE :
403 V4L2_CAP_VIDEO_M2M);
404 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
405 return 0;
406}
407
408static int enum_fmt(struct v4l2_fmtdesc *f, bool is_enc, bool is_out)
409{
29a7a5e9 410 bool is_uncomp = (is_enc && is_out) || (!is_enc && !is_out);
256bf813
HV
411
412 if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
413 return -EINVAL;
414 if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
415 return -EINVAL;
256bf813 416
cd12b401
HV
417 if (is_uncomp) {
418 const struct v4l2_fwht_pixfmt_info *info =
419 v4l2_fwht_get_pixfmt(f->index);
420
421 if (!info)
422 return -EINVAL;
423 f->pixelformat = info->id;
424 } else {
425 if (f->index)
426 return -EINVAL;
256bf813 427 f->pixelformat = V4L2_PIX_FMT_FWHT;
cd12b401 428 }
256bf813
HV
429 return 0;
430}
431
432static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
433 struct v4l2_fmtdesc *f)
434{
435 struct vicodec_ctx *ctx = file2ctx(file);
436
437 return enum_fmt(f, ctx->is_enc, false);
438}
439
440static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
441 struct v4l2_fmtdesc *f)
442{
443 struct vicodec_ctx *ctx = file2ctx(file);
444
445 return enum_fmt(f, ctx->is_enc, true);
446}
447
448static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
449{
450 struct vb2_queue *vq;
451 struct vicodec_q_data *q_data;
452 struct v4l2_pix_format_mplane *pix_mp;
453 struct v4l2_pix_format *pix;
cd12b401 454 const struct v4l2_fwht_pixfmt_info *info;
256bf813
HV
455
456 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
457 if (!vq)
458 return -EINVAL;
459
460 q_data = get_q_data(ctx, f->type);
29a7a5e9 461 info = q_data->info;
256bf813
HV
462
463 switch (f->type) {
464 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
465 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
466 if (multiplanar)
467 return -EINVAL;
468 pix = &f->fmt.pix;
469 pix->width = q_data->width;
470 pix->height = q_data->height;
471 pix->field = V4L2_FIELD_NONE;
29a7a5e9
HV
472 pix->pixelformat = info->id;
473 pix->bytesperline = q_data->width * info->bytesperline_mult;
256bf813 474 pix->sizeimage = q_data->sizeimage;
cd12b401
HV
475 pix->colorspace = ctx->state.colorspace;
476 pix->xfer_func = ctx->state.xfer_func;
477 pix->ycbcr_enc = ctx->state.ycbcr_enc;
478 pix->quantization = ctx->state.quantization;
256bf813
HV
479 break;
480
481 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
482 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
483 if (!multiplanar)
484 return -EINVAL;
485 pix_mp = &f->fmt.pix_mp;
486 pix_mp->width = q_data->width;
487 pix_mp->height = q_data->height;
488 pix_mp->field = V4L2_FIELD_NONE;
29a7a5e9 489 pix_mp->pixelformat = info->id;
256bf813 490 pix_mp->num_planes = 1;
29a7a5e9
HV
491 pix_mp->plane_fmt[0].bytesperline =
492 q_data->width * info->bytesperline_mult;
256bf813 493 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
cd12b401
HV
494 pix_mp->colorspace = ctx->state.colorspace;
495 pix_mp->xfer_func = ctx->state.xfer_func;
496 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
497 pix_mp->quantization = ctx->state.quantization;
256bf813
HV
498 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
499 memset(pix_mp->plane_fmt[0].reserved, 0,
500 sizeof(pix_mp->plane_fmt[0].reserved));
501 break;
502 default:
503 return -EINVAL;
504 }
505 return 0;
506}
507
508static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
509 struct v4l2_format *f)
510{
511 return vidioc_g_fmt(file2ctx(file), f);
512}
513
514static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
515 struct v4l2_format *f)
516{
517 return vidioc_g_fmt(file2ctx(file), f);
518}
519
520static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
521{
522 struct v4l2_pix_format_mplane *pix_mp;
523 struct v4l2_pix_format *pix;
29a7a5e9 524 struct v4l2_plane_pix_format *plane;
cd12b401 525 const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
256bf813
HV
526
527 switch (f->type) {
528 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
529 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
530 pix = &f->fmt.pix;
29a7a5e9
HV
531 if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
532 info = find_fmt(pix->pixelformat);
256bf813
HV
533 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7;
534 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
256bf813 535 pix->field = V4L2_FIELD_NONE;
29a7a5e9
HV
536 pix->bytesperline =
537 pix->width * info->bytesperline_mult;
538 pix->sizeimage = pix->width * pix->height *
539 info->sizeimage_mult / info->sizeimage_div;
540 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
21abebf0 541 pix->sizeimage += sizeof(struct fwht_cframe_hdr);
256bf813
HV
542 break;
543 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
544 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
545 pix_mp = &f->fmt.pix_mp;
29a7a5e9
HV
546 plane = pix_mp->plane_fmt;
547 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
548 info = find_fmt(pix_mp->pixelformat);
549 pix_mp->num_planes = 1;
256bf813
HV
550 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7;
551 pix_mp->height =
552 clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
256bf813 553 pix_mp->field = V4L2_FIELD_NONE;
29a7a5e9
HV
554 plane->bytesperline =
555 pix_mp->width * info->bytesperline_mult;
556 plane->sizeimage = pix_mp->width * pix_mp->height *
557 info->sizeimage_mult / info->sizeimage_div;
558 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
21abebf0 559 plane->sizeimage += sizeof(struct fwht_cframe_hdr);
256bf813 560 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
29a7a5e9 561 memset(plane->reserved, 0, sizeof(plane->reserved));
256bf813
HV
562 break;
563 default:
564 return -EINVAL;
565 }
566
567 return 0;
568}
569
570static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
571 struct v4l2_format *f)
572{
573 struct vicodec_ctx *ctx = file2ctx(file);
574 struct v4l2_pix_format_mplane *pix_mp;
575 struct v4l2_pix_format *pix;
576
577 switch (f->type) {
578 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
579 if (multiplanar)
580 return -EINVAL;
581 pix = &f->fmt.pix;
582 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 583 find_fmt(f->fmt.pix.pixelformat)->id;
cd12b401
HV
584 pix->colorspace = ctx->state.colorspace;
585 pix->xfer_func = ctx->state.xfer_func;
586 pix->ycbcr_enc = ctx->state.ycbcr_enc;
587 pix->quantization = ctx->state.quantization;
256bf813
HV
588 break;
589 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
590 if (!multiplanar)
591 return -EINVAL;
592 pix_mp = &f->fmt.pix_mp;
593 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 594 find_fmt(pix_mp->pixelformat)->id;
cd12b401
HV
595 pix_mp->colorspace = ctx->state.colorspace;
596 pix_mp->xfer_func = ctx->state.xfer_func;
597 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
598 pix_mp->quantization = ctx->state.quantization;
256bf813
HV
599 break;
600 default:
601 return -EINVAL;
602 }
603
604 return vidioc_try_fmt(ctx, f);
605}
606
607static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
608 struct v4l2_format *f)
609{
610 struct vicodec_ctx *ctx = file2ctx(file);
611 struct v4l2_pix_format_mplane *pix_mp;
612 struct v4l2_pix_format *pix;
613
614 switch (f->type) {
615 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
616 if (multiplanar)
617 return -EINVAL;
618 pix = &f->fmt.pix;
619 pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 620 find_fmt(pix->pixelformat)->id;
256bf813
HV
621 if (!pix->colorspace)
622 pix->colorspace = V4L2_COLORSPACE_REC709;
623 break;
624 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
625 if (!multiplanar)
626 return -EINVAL;
627 pix_mp = &f->fmt.pix_mp;
628 pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
29a7a5e9 629 find_fmt(pix_mp->pixelformat)->id;
256bf813
HV
630 if (!pix_mp->colorspace)
631 pix_mp->colorspace = V4L2_COLORSPACE_REC709;
632 break;
633 default:
634 return -EINVAL;
635 }
636
637 return vidioc_try_fmt(ctx, f);
638}
639
640static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
641{
642 struct vicodec_q_data *q_data;
643 struct vb2_queue *vq;
644 bool fmt_changed = true;
645 struct v4l2_pix_format_mplane *pix_mp;
646 struct v4l2_pix_format *pix;
647
648 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
649 if (!vq)
650 return -EINVAL;
651
652 q_data = get_q_data(ctx, f->type);
653 if (!q_data)
654 return -EINVAL;
655
656 switch (f->type) {
657 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
658 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
659 pix = &f->fmt.pix;
660 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
661 fmt_changed =
29a7a5e9 662 q_data->info->id != pix->pixelformat ||
256bf813
HV
663 q_data->width != pix->width ||
664 q_data->height != pix->height;
665
666 if (vb2_is_busy(vq) && fmt_changed)
667 return -EBUSY;
668
29a7a5e9
HV
669 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
670 q_data->info = &pixfmt_fwht;
671 else
672 q_data->info = find_fmt(pix->pixelformat);
256bf813
HV
673 q_data->width = pix->width;
674 q_data->height = pix->height;
675 q_data->sizeimage = pix->sizeimage;
676 break;
677 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
678 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
679 pix_mp = &f->fmt.pix_mp;
680 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
681 fmt_changed =
29a7a5e9 682 q_data->info->id != pix_mp->pixelformat ||
256bf813
HV
683 q_data->width != pix_mp->width ||
684 q_data->height != pix_mp->height;
685
686 if (vb2_is_busy(vq) && fmt_changed)
687 return -EBUSY;
688
29a7a5e9
HV
689 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
690 q_data->info = &pixfmt_fwht;
691 else
692 q_data->info = find_fmt(pix_mp->pixelformat);
256bf813
HV
693 q_data->width = pix_mp->width;
694 q_data->height = pix_mp->height;
695 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
696 break;
697 default:
698 return -EINVAL;
699 }
700
701 dprintk(ctx->dev,
702 "Setting format for type %d, wxh: %dx%d, fourcc: %08x\n",
29a7a5e9 703 f->type, q_data->width, q_data->height, q_data->info->id);
256bf813
HV
704
705 return 0;
706}
707
708static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
709 struct v4l2_format *f)
710{
711 int ret;
712
713 ret = vidioc_try_fmt_vid_cap(file, priv, f);
714 if (ret)
715 return ret;
716
717 return vidioc_s_fmt(file2ctx(file), f);
718}
719
720static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
721 struct v4l2_format *f)
722{
723 struct vicodec_ctx *ctx = file2ctx(file);
724 struct v4l2_pix_format_mplane *pix_mp;
725 struct v4l2_pix_format *pix;
726 int ret;
727
728 ret = vidioc_try_fmt_vid_out(file, priv, f);
729 if (ret)
730 return ret;
731
732 ret = vidioc_s_fmt(file2ctx(file), f);
733 if (!ret) {
734 switch (f->type) {
735 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
736 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
737 pix = &f->fmt.pix;
cd12b401
HV
738 ctx->state.colorspace = pix->colorspace;
739 ctx->state.xfer_func = pix->xfer_func;
740 ctx->state.ycbcr_enc = pix->ycbcr_enc;
741 ctx->state.quantization = pix->quantization;
256bf813
HV
742 break;
743 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
744 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
745 pix_mp = &f->fmt.pix_mp;
cd12b401
HV
746 ctx->state.colorspace = pix_mp->colorspace;
747 ctx->state.xfer_func = pix_mp->xfer_func;
748 ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
749 ctx->state.quantization = pix_mp->quantization;
256bf813
HV
750 break;
751 default:
752 break;
753 }
754 }
755 return ret;
756}
757
758static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
759{
760 static const struct v4l2_event eos_event = {
761 .type = V4L2_EVENT_EOS
762 };
763
764 spin_lock(ctx->lock);
765 ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
766 if (!ctx->last_src_buf && ctx->last_dst_buf) {
767 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
768 v4l2_event_queue_fh(&ctx->fh, &eos_event);
769 }
770 spin_unlock(ctx->lock);
771}
772
773static int vicodec_try_encoder_cmd(struct file *file, void *fh,
774 struct v4l2_encoder_cmd *ec)
775{
776 if (ec->cmd != V4L2_ENC_CMD_STOP)
777 return -EINVAL;
778
779 if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
780 return -EINVAL;
781
782 return 0;
783}
784
785static int vicodec_encoder_cmd(struct file *file, void *fh,
786 struct v4l2_encoder_cmd *ec)
787{
788 struct vicodec_ctx *ctx = file2ctx(file);
789 int ret;
790
791 ret = vicodec_try_encoder_cmd(file, fh, ec);
792 if (ret < 0)
793 return ret;
794
795 vicodec_mark_last_buf(ctx);
796 return 0;
797}
798
799static int vicodec_try_decoder_cmd(struct file *file, void *fh,
800 struct v4l2_decoder_cmd *dc)
801{
802 if (dc->cmd != V4L2_DEC_CMD_STOP)
803 return -EINVAL;
804
805 if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
806 return -EINVAL;
807
808 if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
809 return -EINVAL;
810
811 return 0;
812}
813
814static int vicodec_decoder_cmd(struct file *file, void *fh,
815 struct v4l2_decoder_cmd *dc)
816{
817 struct vicodec_ctx *ctx = file2ctx(file);
818 int ret;
819
820 ret = vicodec_try_decoder_cmd(file, fh, dc);
821 if (ret < 0)
822 return ret;
823
824 vicodec_mark_last_buf(ctx);
825 return 0;
826}
827
828static int vicodec_enum_framesizes(struct file *file, void *fh,
829 struct v4l2_frmsizeenum *fsize)
830{
831 switch (fsize->pixel_format) {
832 case V4L2_PIX_FMT_FWHT:
833 break;
834 default:
29a7a5e9 835 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
256bf813
HV
836 break;
837 return -EINVAL;
838 }
839
840 if (fsize->index)
841 return -EINVAL;
842
843 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
844
845 fsize->stepwise.min_width = MIN_WIDTH;
846 fsize->stepwise.max_width = MAX_WIDTH;
847 fsize->stepwise.step_width = 8;
848 fsize->stepwise.min_height = MIN_HEIGHT;
849 fsize->stepwise.max_height = MAX_HEIGHT;
850 fsize->stepwise.step_height = 8;
851
852 return 0;
853}
854
855static int vicodec_subscribe_event(struct v4l2_fh *fh,
856 const struct v4l2_event_subscription *sub)
857{
858 switch (sub->type) {
859 case V4L2_EVENT_EOS:
860 return v4l2_event_subscribe(fh, sub, 0, NULL);
861 default:
862 return v4l2_ctrl_subscribe_event(fh, sub);
863 }
864}
865
866static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
867 .vidioc_querycap = vidioc_querycap,
868
869 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
870 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
871 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
872 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
873
874 .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
875 .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
876 .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
877 .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
878
879 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
880 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
881 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
882 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
883
884 .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
885 .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
886 .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
887 .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
888
889 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
890 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
891 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
892 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
893 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
894 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
895 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
896
897 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
898 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
899
900 .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
901 .vidioc_encoder_cmd = vicodec_encoder_cmd,
902 .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
903 .vidioc_decoder_cmd = vicodec_decoder_cmd,
904 .vidioc_enum_framesizes = vicodec_enum_framesizes,
905
906 .vidioc_subscribe_event = vicodec_subscribe_event,
907 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
908};
909
910
911/*
912 * Queue operations
913 */
914
915static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
916 unsigned int *nplanes, unsigned int sizes[],
917 struct device *alloc_devs[])
918{
919 struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
920 struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
921 unsigned int size = q_data->sizeimage;
922
923 if (*nplanes)
924 return sizes[0] < size ? -EINVAL : 0;
925
926 *nplanes = 1;
927 sizes[0] = size;
928 return 0;
929}
930
931static int vicodec_buf_prepare(struct vb2_buffer *vb)
932{
933 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
934 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
935 struct vicodec_q_data *q_data;
936
937 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
938
939 q_data = get_q_data(ctx, vb->vb2_queue->type);
940 if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
941 if (vbuf->field == V4L2_FIELD_ANY)
942 vbuf->field = V4L2_FIELD_NONE;
943 if (vbuf->field != V4L2_FIELD_NONE) {
944 dprintk(ctx->dev, "%s field isn't supported\n",
945 __func__);
946 return -EINVAL;
947 }
948 }
949
950 if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
951 dprintk(ctx->dev,
952 "%s data will not fit into plane (%lu < %lu)\n",
953 __func__, vb2_plane_size(vb, 0),
954 (long)q_data->sizeimage);
955 return -EINVAL;
956 }
957
958 return 0;
959}
960
961static void vicodec_buf_queue(struct vb2_buffer *vb)
962{
963 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
964 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
965
966 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
967}
968
969static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
970{
971 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
972 struct vb2_v4l2_buffer *vbuf;
973
974 for (;;) {
975 if (V4L2_TYPE_IS_OUTPUT(q->type))
976 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
977 else
978 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
979 if (vbuf == NULL)
980 return;
981 spin_lock(ctx->lock);
982 v4l2_m2m_buf_done(vbuf, state);
983 spin_unlock(ctx->lock);
984 }
985}
986
987static int vicodec_start_streaming(struct vb2_queue *q,
988 unsigned int count)
989{
990 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
991 struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
cd12b401 992 struct v4l2_fwht_state *state = &ctx->state;
256bf813 993 unsigned int size = q_data->width * q_data->height;
cd12b401 994 const struct v4l2_fwht_pixfmt_info *info = q_data->info;
29a7a5e9 995 unsigned int chroma_div = info->width_div * info->height_div;
256bf813
HV
996
997 q_data->sequence = 0;
998
999 if (!V4L2_TYPE_IS_OUTPUT(q->type))
1000 return 0;
1001
cd12b401
HV
1002 state->width = q_data->width;
1003 state->height = q_data->height;
1004 state->ref_frame.width = state->ref_frame.height = 0;
1005 state->ref_frame.luma = kvmalloc(size + 2 * size / chroma_div,
1006 GFP_KERNEL);
29a7a5e9 1007 ctx->comp_max_size = size + 2 * size / chroma_div +
21abebf0 1008 sizeof(struct fwht_cframe_hdr);
cd12b401
HV
1009 state->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1010 if (!state->ref_frame.luma || !state->compressed_frame) {
1011 kvfree(state->ref_frame.luma);
1012 kvfree(state->compressed_frame);
256bf813
HV
1013 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1014 return -ENOMEM;
1015 }
cd12b401
HV
1016 state->ref_frame.cb = state->ref_frame.luma + size;
1017 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
256bf813
HV
1018 ctx->last_src_buf = NULL;
1019 ctx->last_dst_buf = NULL;
cd12b401 1020 state->gop_cnt = 0;
256bf813
HV
1021 ctx->cur_buf_offset = 0;
1022 ctx->comp_size = 0;
1023 ctx->comp_magic_cnt = 0;
1024 ctx->comp_has_frame = false;
1025
1026 return 0;
1027}
1028
1029static void vicodec_stop_streaming(struct vb2_queue *q)
1030{
1031 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1032
1033 vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1034
1035 if (!V4L2_TYPE_IS_OUTPUT(q->type))
1036 return;
1037
cd12b401
HV
1038 kvfree(ctx->state.ref_frame.luma);
1039 kvfree(ctx->state.compressed_frame);
256bf813
HV
1040}
1041
1042static const struct vb2_ops vicodec_qops = {
1043 .queue_setup = vicodec_queue_setup,
1044 .buf_prepare = vicodec_buf_prepare,
1045 .buf_queue = vicodec_buf_queue,
1046 .start_streaming = vicodec_start_streaming,
1047 .stop_streaming = vicodec_stop_streaming,
1048 .wait_prepare = vb2_ops_wait_prepare,
1049 .wait_finish = vb2_ops_wait_finish,
1050};
1051
1052static int queue_init(void *priv, struct vb2_queue *src_vq,
1053 struct vb2_queue *dst_vq)
1054{
1055 struct vicodec_ctx *ctx = priv;
1056 int ret;
1057
1058 src_vq->type = (multiplanar ?
1059 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1060 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1061 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1062 src_vq->drv_priv = ctx;
1063 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1064 src_vq->ops = &vicodec_qops;
1065 src_vq->mem_ops = &vb2_vmalloc_memops;
1066 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1067 src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1068 &ctx->dev->dec_mutex;
1069
1070 ret = vb2_queue_init(src_vq);
1071 if (ret)
1072 return ret;
1073
1074 dst_vq->type = (multiplanar ?
1075 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1076 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1077 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1078 dst_vq->drv_priv = ctx;
1079 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1080 dst_vq->ops = &vicodec_qops;
1081 dst_vq->mem_ops = &vb2_vmalloc_memops;
1082 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1083 dst_vq->lock = src_vq->lock;
1084
1085 return vb2_queue_init(dst_vq);
1086}
1087
48568b0c
HV
1088#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
1089#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
1090#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
1091
1092static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1093{
1094 struct vicodec_ctx *ctx = container_of(ctrl->handler,
1095 struct vicodec_ctx, hdl);
1096
1097 switch (ctrl->id) {
1098 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
cd12b401 1099 ctx->state.gop_size = ctrl->val;
48568b0c
HV
1100 return 0;
1101 case VICODEC_CID_I_FRAME_QP:
cd12b401 1102 ctx->state.i_frame_qp = ctrl->val;
48568b0c
HV
1103 return 0;
1104 case VICODEC_CID_P_FRAME_QP:
cd12b401 1105 ctx->state.p_frame_qp = ctrl->val;
48568b0c
HV
1106 return 0;
1107 }
1108 return -EINVAL;
1109}
1110
cd12b401 1111static struct v4l2_ctrl_ops vicodec_ctrl_ops = {
48568b0c
HV
1112 .s_ctrl = vicodec_s_ctrl,
1113};
1114
1115static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1116 .ops = &vicodec_ctrl_ops,
1117 .id = VICODEC_CID_I_FRAME_QP,
1118 .name = "FWHT I-Frame QP Value",
1119 .type = V4L2_CTRL_TYPE_INTEGER,
1120 .min = 1,
1121 .max = 31,
1122 .def = 20,
1123 .step = 1,
1124};
1125
1126static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1127 .ops = &vicodec_ctrl_ops,
1128 .id = VICODEC_CID_P_FRAME_QP,
1129 .name = "FWHT P-Frame QP Value",
1130 .type = V4L2_CTRL_TYPE_INTEGER,
1131 .min = 1,
1132 .max = 31,
1133 .def = 20,
1134 .step = 1,
1135};
1136
256bf813
HV
1137/*
1138 * File operations
1139 */
1140static int vicodec_open(struct file *file)
1141{
1142 struct video_device *vfd = video_devdata(file);
1143 struct vicodec_dev *dev = video_drvdata(file);
1144 struct vicodec_ctx *ctx = NULL;
1145 struct v4l2_ctrl_handler *hdl;
1146 unsigned int size;
1147 int rc = 0;
1148
1149 if (mutex_lock_interruptible(vfd->lock))
1150 return -ERESTARTSYS;
1151 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1152 if (!ctx) {
1153 rc = -ENOMEM;
1154 goto open_unlock;
1155 }
1156
1157 if (vfd == &dev->enc_vfd)
1158 ctx->is_enc = true;
1159
1160 v4l2_fh_init(&ctx->fh, video_devdata(file));
1161 file->private_data = &ctx->fh;
1162 ctx->dev = dev;
1163 hdl = &ctx->hdl;
1164 v4l2_ctrl_handler_init(hdl, 4);
48568b0c
HV
1165 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1166 1, 16, 1, 10);
1167 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1168 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
256bf813
HV
1169 if (hdl->error) {
1170 rc = hdl->error;
1171 v4l2_ctrl_handler_free(hdl);
1172 kfree(ctx);
1173 goto open_unlock;
1174 }
1175 ctx->fh.ctrl_handler = hdl;
1176 v4l2_ctrl_handler_setup(hdl);
1177
29a7a5e9 1178 ctx->q_data[V4L2_M2M_SRC].info =
cd12b401 1179 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
256bf813
HV
1180 ctx->q_data[V4L2_M2M_SRC].width = 1280;
1181 ctx->q_data[V4L2_M2M_SRC].height = 720;
29a7a5e9
HV
1182 size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1183 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
55f6fe09
HV
1184 if (ctx->is_enc)
1185 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1186 else
1187 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1188 size + sizeof(struct fwht_cframe_hdr);
256bf813 1189 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
29a7a5e9 1190 ctx->q_data[V4L2_M2M_DST].info =
cd12b401 1191 ctx->is_enc ? &pixfmt_fwht : v4l2_fwht_get_pixfmt(0);
29a7a5e9
HV
1192 size = 1280 * 720 * ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1193 ctx->q_data[V4L2_M2M_DST].info->sizeimage_div;
55f6fe09
HV
1194 if (ctx->is_enc)
1195 ctx->q_data[V4L2_M2M_DST].sizeimage =
1196 size + sizeof(struct fwht_cframe_hdr);
1197 else
1198 ctx->q_data[V4L2_M2M_DST].sizeimage = size;
cd12b401 1199 ctx->state.colorspace = V4L2_COLORSPACE_REC709;
256bf813 1200
256bf813 1201 if (ctx->is_enc) {
256bf813
HV
1202 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1203 &queue_init);
1204 ctx->lock = &dev->enc_lock;
1205 } else {
256bf813
HV
1206 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1207 &queue_init);
1208 ctx->lock = &dev->dec_lock;
1209 }
1210
1211 if (IS_ERR(ctx->fh.m2m_ctx)) {
1212 rc = PTR_ERR(ctx->fh.m2m_ctx);
1213
1214 v4l2_ctrl_handler_free(hdl);
1215 v4l2_fh_exit(&ctx->fh);
1216 kfree(ctx);
1217 goto open_unlock;
1218 }
1219
1220 v4l2_fh_add(&ctx->fh);
1221
1222open_unlock:
1223 mutex_unlock(vfd->lock);
1224 return rc;
1225}
1226
1227static int vicodec_release(struct file *file)
1228{
1229 struct video_device *vfd = video_devdata(file);
1230 struct vicodec_ctx *ctx = file2ctx(file);
1231
1232 v4l2_fh_del(&ctx->fh);
1233 v4l2_fh_exit(&ctx->fh);
1234 v4l2_ctrl_handler_free(&ctx->hdl);
1235 mutex_lock(vfd->lock);
1236 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1237 mutex_unlock(vfd->lock);
1238 kfree(ctx);
1239
1240 return 0;
1241}
1242
1243static const struct v4l2_file_operations vicodec_fops = {
1244 .owner = THIS_MODULE,
1245 .open = vicodec_open,
1246 .release = vicodec_release,
1247 .poll = v4l2_m2m_fop_poll,
1248 .unlocked_ioctl = video_ioctl2,
1249 .mmap = v4l2_m2m_fop_mmap,
1250};
1251
1252static const struct video_device vicodec_videodev = {
1253 .name = VICODEC_NAME,
1254 .vfl_dir = VFL_DIR_M2M,
1255 .fops = &vicodec_fops,
1256 .ioctl_ops = &vicodec_ioctl_ops,
1257 .minor = -1,
1258 .release = video_device_release_empty,
1259};
1260
1261static const struct v4l2_m2m_ops m2m_ops = {
1262 .device_run = device_run,
256bf813
HV
1263 .job_ready = job_ready,
1264};
1265
1266static int vicodec_probe(struct platform_device *pdev)
1267{
1268 struct vicodec_dev *dev;
1269 struct video_device *vfd;
1270 int ret;
1271
1272 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1273 if (!dev)
1274 return -ENOMEM;
1275
1276 spin_lock_init(&dev->enc_lock);
1277 spin_lock_init(&dev->dec_lock);
1278
1279 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1280 if (ret)
1281 return ret;
1282
1283#ifdef CONFIG_MEDIA_CONTROLLER
1284 dev->mdev.dev = &pdev->dev;
c0decac1 1285 strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
256bf813
HV
1286 media_device_init(&dev->mdev);
1287 dev->v4l2_dev.mdev = &dev->mdev;
1288#endif
1289
1290 mutex_init(&dev->enc_mutex);
1291 mutex_init(&dev->dec_mutex);
1292
1293 platform_set_drvdata(pdev, dev);
1294
1295 dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1296 if (IS_ERR(dev->enc_dev)) {
1297 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1298 ret = PTR_ERR(dev->enc_dev);
1299 goto unreg_dev;
1300 }
1301
1302 dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1303 if (IS_ERR(dev->dec_dev)) {
1304 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1305 ret = PTR_ERR(dev->dec_dev);
1306 goto err_enc_m2m;
1307 }
1308
1309 dev->enc_vfd = vicodec_videodev;
1310 vfd = &dev->enc_vfd;
1311 vfd->lock = &dev->enc_mutex;
1312 vfd->v4l2_dev = &dev->v4l2_dev;
c0decac1 1313 strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
256bf813
HV
1314 v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1315 v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1316 video_set_drvdata(vfd, dev);
1317
1318 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1319 if (ret) {
1320 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1321 goto err_dec_m2m;
1322 }
1323 v4l2_info(&dev->v4l2_dev,
1324 "Device registered as /dev/video%d\n", vfd->num);
1325
1326 dev->dec_vfd = vicodec_videodev;
1327 vfd = &dev->dec_vfd;
1328 vfd->lock = &dev->dec_mutex;
1329 vfd->v4l2_dev = &dev->v4l2_dev;
c0decac1 1330 strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
256bf813
HV
1331 v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1332 v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1333 video_set_drvdata(vfd, dev);
1334
1335 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1336 if (ret) {
1337 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1338 goto unreg_enc;
1339 }
1340 v4l2_info(&dev->v4l2_dev,
1341 "Device registered as /dev/video%d\n", vfd->num);
1342
1343#ifdef CONFIG_MEDIA_CONTROLLER
1344 ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1345 &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1346 if (ret) {
1347 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1348 goto unreg_m2m;
1349 }
1350
1351 ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1352 &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1353 if (ret) {
1354 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1355 goto unreg_m2m_enc_mc;
1356 }
1357
1358 ret = media_device_register(&dev->mdev);
1359 if (ret) {
1360 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1361 goto unreg_m2m_dec_mc;
1362 }
1363#endif
1364 return 0;
1365
1366#ifdef CONFIG_MEDIA_CONTROLLER
1367unreg_m2m_dec_mc:
1368 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1369unreg_m2m_enc_mc:
1370 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1371unreg_m2m:
1372 video_unregister_device(&dev->dec_vfd);
1373#endif
1374unreg_enc:
1375 video_unregister_device(&dev->enc_vfd);
1376err_dec_m2m:
1377 v4l2_m2m_release(dev->dec_dev);
1378err_enc_m2m:
1379 v4l2_m2m_release(dev->enc_dev);
1380unreg_dev:
1381 v4l2_device_unregister(&dev->v4l2_dev);
1382
1383 return ret;
1384}
1385
1386static int vicodec_remove(struct platform_device *pdev)
1387{
1388 struct vicodec_dev *dev = platform_get_drvdata(pdev);
1389
1390 v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1391
1392#ifdef CONFIG_MEDIA_CONTROLLER
1393 media_device_unregister(&dev->mdev);
1394 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1395 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1396 media_device_cleanup(&dev->mdev);
1397#endif
1398
1399 v4l2_m2m_release(dev->enc_dev);
1400 v4l2_m2m_release(dev->dec_dev);
1401 video_unregister_device(&dev->enc_vfd);
1402 video_unregister_device(&dev->dec_vfd);
1403 v4l2_device_unregister(&dev->v4l2_dev);
1404
1405 return 0;
1406}
1407
1408static struct platform_driver vicodec_pdrv = {
1409 .probe = vicodec_probe,
1410 .remove = vicodec_remove,
1411 .driver = {
1412 .name = VICODEC_NAME,
1413 },
1414};
1415
1416static void __exit vicodec_exit(void)
1417{
1418 platform_driver_unregister(&vicodec_pdrv);
1419 platform_device_unregister(&vicodec_pdev);
1420}
1421
1422static int __init vicodec_init(void)
1423{
1424 int ret;
1425
1426 ret = platform_device_register(&vicodec_pdev);
1427 if (ret)
1428 return ret;
1429
1430 ret = platform_driver_register(&vicodec_pdrv);
1431 if (ret)
1432 platform_device_unregister(&vicodec_pdev);
1433
1434 return ret;
1435}
1436
1437module_init(vicodec_init);
1438module_exit(vicodec_exit);
This page took 0.281138 seconds and 4 git commands to generate.