diff options
Diffstat (limited to 'drivers/media/test-drivers/vimc')
| -rw-r--r-- | drivers/media/test-drivers/vimc/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/Makefile | 2 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-capture.c | 291 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-common.c | 33 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-common.h | 20 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-core.c | 162 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-debayer.c | 511 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-lens.c | 103 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-scaler.c | 508 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-sensor.c | 363 | ||||
| -rw-r--r-- | drivers/media/test-drivers/vimc/vimc-streamer.c | 8 |
11 files changed, 1049 insertions, 955 deletions
diff --git a/drivers/media/test-drivers/vimc/Kconfig b/drivers/media/test-drivers/vimc/Kconfig index da4b2ad6e40c..0d5169819cac 100644 --- a/drivers/media/test-drivers/vimc/Kconfig +++ b/drivers/media/test-drivers/vimc/Kconfig @@ -1,12 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select FONT_SUPPORT select FONT_8x16 select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG help Skeleton driver for Virtual Media Controller diff --git a/drivers/media/test-drivers/vimc/Makefile b/drivers/media/test-drivers/vimc/Makefile index a53b2b532e9f..9b9631562473 100644 --- a/drivers/media/test-drivers/vimc/Makefile +++ b/drivers/media/test-drivers/vimc/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \ - vimc-debayer.o vimc-scaler.o vimc-sensor.o + vimc-debayer.o vimc-scaler.o vimc-sensor.o vimc-lens.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 5e9fd902cd37..7f6124025fc9 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -7,12 +7,13 @@ #include <media/v4l2-ioctl.h> #include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> #include <media/videobuf2-vmalloc.h> #include "vimc-common.h" #include "vimc-streamer.h" -struct vimc_cap_device { +struct vimc_capture_device { struct vimc_ent_device ved; struct video_device vdev; struct v4l2_pix_format format; @@ -40,7 +41,7 @@ static const struct v4l2_pix_format fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -struct vimc_cap_buffer { +struct vimc_capture_buffer { /* * struct vb2_v4l2_buffer must be the first element * the videobuf2 framework will allocate this struct based on @@ -51,37 +52,35 @@ struct vimc_cap_buffer { struct list_head list; }; -static int vimc_cap_querycap(struct file *file, void *priv, +static int vimc_capture_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver)); strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", VIMC_PDEV_NAME); return 0; } -static void vimc_cap_get_format(struct vimc_ent_device *ved, +static void vimc_capture_get_format(struct vimc_ent_device *ved, struct v4l2_pix_format *fmt) { - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + struct vimc_capture_device *vcapture = container_of(ved, struct vimc_capture_device, ved); - *fmt = vcap->format; + *fmt = vcapture->format; } -static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vimc_cap_device *vcap = video_drvdata(file); + struct vimc_capture_device *vcapture = video_drvdata(file); - f->fmt.pix = vcap->format; + f->fmt.pix = vcapture->format; return 0; } -static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *format = &f->fmt.pix; @@ -113,40 +112,40 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vimc_cap_device *vcap = video_drvdata(file); + struct vimc_capture_device *vcapture = video_drvdata(file); int ret; /* Do not change the format while stream is on */ - if (vb2_is_busy(&vcap->queue)) + if (vb2_is_busy(&vcapture->queue)) return -EBUSY; - ret = vimc_cap_try_fmt_vid_cap(file, priv, f); + ret = vimc_capture_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - dev_dbg(vcap->ved.dev, "%s: format update: " + dev_dbg(vcapture->ved.dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcapture->vdev.name, /* old */ - vcap->format.width, vcap->format.height, - vcap->format.pixelformat, vcap->format.colorspace, - vcap->format.quantization, vcap->format.xfer_func, - vcap->format.ycbcr_enc, + vcapture->format.width, vcapture->format.height, + vcapture->format.pixelformat, vcapture->format.colorspace, + vcapture->format.quantization, vcapture->format.xfer_func, + vcapture->format.ycbcr_enc, /* new */ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat, f->fmt.pix.colorspace, f->fmt.pix.quantization, f->fmt.pix.xfer_func, f->fmt.pix.ycbcr_enc); - vcap->format = f->fmt.pix; + vcapture->format = f->fmt.pix; return 0; } -static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct vimc_pix_map *vpix; @@ -168,7 +167,7 @@ static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vimc_cap_enum_framesizes(struct file *file, void *fh, +static int vimc_capture_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { const struct vimc_pix_map *vpix; @@ -192,7 +191,7 @@ static int vimc_cap_enum_framesizes(struct file *file, void *fh, return 0; } -static const struct v4l2_file_operations vimc_cap_fops = { +static const struct v4l2_file_operations vimc_capture_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -202,14 +201,14 @@ static const struct v4l2_file_operations vimc_cap_fops = { .mmap = vb2_fop_mmap, }; -static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { - .vidioc_querycap = vimc_cap_querycap, +static const struct v4l2_ioctl_ops vimc_capture_ioctl_ops = { + .vidioc_querycap = vimc_capture_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, - .vidioc_enum_framesizes = vimc_cap_enum_framesizes, + .vidioc_g_fmt_vid_cap = vimc_capture_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_capture_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_capture_try_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = vimc_capture_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_capture_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, @@ -220,42 +219,42 @@ static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_remove_bufs = vb2_ioctl_remove_bufs, }; -static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, +static void vimc_capture_return_all_buffers(struct vimc_capture_device *vcapture, enum vb2_buffer_state state) { - struct vimc_cap_buffer *vbuf, *node; + struct vimc_capture_buffer *vbuf, *node; - spin_lock(&vcap->qlock); + spin_lock(&vcapture->qlock); - list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) { + list_for_each_entry_safe(vbuf, node, &vcapture->buf_list, list) { list_del(&vbuf->list); vb2_buffer_done(&vbuf->vb2.vb2_buf, state); } - spin_unlock(&vcap->qlock); + spin_unlock(&vcapture->qlock); } -static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) +static int vimc_capture_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); - struct media_entity *entity = &vcap->vdev.entity; + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); int ret; - vcap->sequence = 0; + vcapture->sequence = 0; /* Start the media pipeline */ - ret = media_pipeline_start(entity, &vcap->stream.pipe); + ret = video_device_pipeline_start(&vcapture->vdev, &vcapture->stream.pipe); if (ret) { - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED); return ret; } - ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); + ret = vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 1); if (ret) { - media_pipeline_stop(entity); - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + video_device_pipeline_stop(&vcapture->vdev); + vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED); return ret; } @@ -266,171 +265,169 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) * Stop the stream engine. Any remaining buffers in the stream queue are * dequeued and passed on to the vb2 framework marked as STATE_ERROR. */ -static void vimc_cap_stop_streaming(struct vb2_queue *vq) +static void vimc_capture_stop_streaming(struct vb2_queue *vq) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); - vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0); + vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 0); /* Stop the media pipeline */ - media_pipeline_stop(&vcap->vdev.entity); + video_device_pipeline_stop(&vcapture->vdev); /* Release all active buffers */ - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR); + vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_ERROR); } -static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf) +static void vimc_capture_buf_queue(struct vb2_buffer *vb2_buf) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vb2_buf->vb2_queue); - struct vimc_cap_buffer *buf = container_of(vb2_buf, - struct vimc_cap_buffer, + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vb2_buf->vb2_queue); + struct vimc_capture_buffer *buf = container_of(vb2_buf, + struct vimc_capture_buffer, vb2.vb2_buf); - spin_lock(&vcap->qlock); - list_add_tail(&buf->list, &vcap->buf_list); - spin_unlock(&vcap->qlock); + spin_lock(&vcapture->qlock); + list_add_tail(&buf->list, &vcapture->buf_list); + spin_unlock(&vcapture->qlock); } -static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, +static int vimc_capture_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); if (*nplanes) - return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; + return sizes[0] < vcapture->format.sizeimage ? -EINVAL : 0; /* We don't support multiplanes for now */ *nplanes = 1; - sizes[0] = vcap->format.sizeimage; + sizes[0] = vcapture->format.sizeimage; return 0; } -static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) +static int vimc_capture_buffer_prepare(struct vb2_buffer *vb) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = vcap->format.sizeimage; + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = vcapture->format.sizeimage; if (vb2_plane_size(vb, 0) < size) { - dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n", - vcap->vdev.name, vb2_plane_size(vb, 0), size); + dev_err(vcapture->ved.dev, "%s: buffer too small (%lu < %lu)\n", + vcapture->vdev.name, vb2_plane_size(vb, 0), size); return -EINVAL; } return 0; } -static const struct vb2_ops vimc_cap_qops = { - .start_streaming = vimc_cap_start_streaming, - .stop_streaming = vimc_cap_stop_streaming, - .buf_queue = vimc_cap_buf_queue, - .queue_setup = vimc_cap_queue_setup, - .buf_prepare = vimc_cap_buffer_prepare, - /* - * Since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. - */ - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, +static const struct vb2_ops vimc_capture_qops = { + .start_streaming = vimc_capture_start_streaming, + .stop_streaming = vimc_capture_stop_streaming, + .buf_queue = vimc_capture_buf_queue, + .queue_setup = vimc_capture_queue_setup, + .buf_prepare = vimc_capture_buffer_prepare, }; -static const struct media_entity_operations vimc_cap_mops = { +static const struct media_entity_operations vimc_capture_mops = { .link_validate = vimc_vdev_link_validate, }; -static void vimc_cap_release(struct vimc_ent_device *ved) +static void vimc_capture_release(struct vimc_ent_device *ved) { - struct vimc_cap_device *vcap = - container_of(ved, struct vimc_cap_device, ved); + struct vimc_capture_device *vcapture = + container_of(ved, struct vimc_capture_device, ved); - media_entity_cleanup(vcap->ved.ent); - kfree(vcap); + media_entity_cleanup(vcapture->ved.ent); + kfree(vcapture); } -static void vimc_cap_unregister(struct vimc_ent_device *ved) +static void vimc_capture_unregister(struct vimc_ent_device *ved) { - struct vimc_cap_device *vcap = - container_of(ved, struct vimc_cap_device, ved); + struct vimc_capture_device *vcapture = + container_of(ved, struct vimc_capture_device, ved); - vb2_video_unregister_device(&vcap->vdev); + vb2_video_unregister_device(&vcapture->vdev); } -static void *vimc_cap_process_frame(struct vimc_ent_device *ved, +static void *vimc_capture_process_frame(struct vimc_ent_device *ved, const void *frame) { - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + struct vimc_capture_device *vcapture = container_of(ved, struct vimc_capture_device, ved); - struct vimc_cap_buffer *vimc_buf; + struct vimc_capture_buffer *vimc_buf; void *vbuf; - spin_lock(&vcap->qlock); + spin_lock(&vcapture->qlock); /* Get the first entry of the list */ - vimc_buf = list_first_entry_or_null(&vcap->buf_list, + vimc_buf = list_first_entry_or_null(&vcapture->buf_list, typeof(*vimc_buf), list); if (!vimc_buf) { - spin_unlock(&vcap->qlock); + spin_unlock(&vcapture->qlock); return ERR_PTR(-EAGAIN); } /* Remove this entry from the list */ list_del(&vimc_buf->list); - spin_unlock(&vcap->qlock); + spin_unlock(&vcapture->qlock); /* Fill the buffer */ vimc_buf->vb2.vb2_buf.timestamp = ktime_get_ns(); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; + vimc_buf->vb2.sequence = vcapture->sequence++; + vimc_buf->vb2.field = vcapture->format.field; vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0); - memcpy(vbuf, frame, vcap->format.sizeimage); + memcpy(vbuf, frame, vcapture->format.sizeimage); /* Set it as ready */ vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, - vcap->format.sizeimage); + vcapture->format.sizeimage); vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); return NULL; } -static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, +static struct vimc_ent_device *vimc_capture_add(struct vimc_device *vimc, const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; const struct vimc_pix_map *vpix; - struct vimc_cap_device *vcap; + struct vimc_capture_device *vcapture; struct video_device *vdev; struct vb2_queue *q; int ret; - /* Allocate the vimc_cap_device struct */ - vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); - if (!vcap) + /* Allocate the vimc_capture_device struct */ + vcapture = kzalloc(sizeof(*vcapture), GFP_KERNEL); + if (!vcapture) return ERR_PTR(-ENOMEM); /* Initialize the media entity */ - vcap->vdev.entity.name = vcfg_name; - vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; - vcap->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vcap->vdev.entity, - 1, &vcap->pad); + vcapture->vdev.entity.name = vcfg_name; + vcapture->vdev.entity.function = MEDIA_ENT_F_IO_V4L; + vcapture->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vcapture->vdev.entity, + 1, &vcapture->pad); if (ret) - goto err_free_vcap; + goto err_free_vcapture; /* Initialize the lock */ - mutex_init(&vcap->lock); + mutex_init(&vcapture->lock); /* Initialize the vb2 queue */ - q = &vcap->queue; + q = &vcapture->queue; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR; - q->drv_priv = vcap; - q->buf_struct_size = sizeof(struct vimc_cap_buffer); - q->ops = &vimc_cap_qops; - q->mem_ops = &vb2_vmalloc_memops; + q->io_modes = VB2_MMAP | VB2_DMABUF; + if (vimc_allocator == VIMC_ALLOCATOR_VMALLOC) + q->io_modes |= VB2_USERPTR; + q->drv_priv = vcapture; + q->buf_struct_size = sizeof(struct vimc_capture_buffer); + q->ops = &vimc_capture_qops; + q->mem_ops = vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG + ? &vb2_dma_contig_memops : &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &vcap->lock; + q->min_reqbufs_allocation = 2; + q->lock = &vcapture->lock; + q->dev = v4l2_dev->dev; ret = vb2_queue_init(q); if (ret) { @@ -440,57 +437,57 @@ static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, } /* Initialize buffer list and its lock */ - INIT_LIST_HEAD(&vcap->buf_list); - spin_lock_init(&vcap->qlock); + INIT_LIST_HEAD(&vcapture->buf_list); + spin_lock_init(&vcapture->qlock); /* Set default frame format */ - vcap->format = fmt_default; - vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; - vcap->format.sizeimage = vcap->format.bytesperline * - vcap->format.height; + vcapture->format = fmt_default; + vpix = vimc_pix_map_by_pixelformat(vcapture->format.pixelformat); + vcapture->format.bytesperline = vcapture->format.width * vpix->bpp; + vcapture->format.sizeimage = vcapture->format.bytesperline * + vcapture->format.height; /* Fill the vimc_ent_device struct */ - vcap->ved.ent = &vcap->vdev.entity; - vcap->ved.process_frame = vimc_cap_process_frame; - vcap->ved.vdev_get_format = vimc_cap_get_format; - vcap->ved.dev = vimc->mdev.dev; + vcapture->ved.ent = &vcapture->vdev.entity; + vcapture->ved.process_frame = vimc_capture_process_frame; + vcapture->ved.vdev_get_format = vimc_capture_get_format; + vcapture->ved.dev = vimc->mdev.dev; /* Initialize the video_device struct */ - vdev = &vcap->vdev; + vdev = &vcapture->vdev; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; - vdev->entity.ops = &vimc_cap_mops; + vdev->entity.ops = &vimc_capture_mops; vdev->release = video_device_release_empty; - vdev->fops = &vimc_cap_fops; - vdev->ioctl_ops = &vimc_cap_ioctl_ops; - vdev->lock = &vcap->lock; + vdev->fops = &vimc_capture_fops; + vdev->ioctl_ops = &vimc_capture_ioctl_ops; + vdev->lock = &vcapture->lock; vdev->queue = q; vdev->v4l2_dev = v4l2_dev; vdev->vfl_dir = VFL_DIR_RX; strscpy(vdev->name, vcfg_name, sizeof(vdev->name)); - video_set_drvdata(vdev, &vcap->ved); + video_set_drvdata(vdev, &vcapture->ved); /* Register the video_device with the v4l2 and the media framework */ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n", - vcap->vdev.name, ret); + vcapture->vdev.name, ret); goto err_clean_m_ent; } - return &vcap->ved; + return &vcapture->ved; err_clean_m_ent: - media_entity_cleanup(&vcap->vdev.entity); -err_free_vcap: - kfree(vcap); + media_entity_cleanup(&vcapture->vdev.entity); +err_free_vcapture: + kfree(vcapture); return ERR_PTR(ret); } -struct vimc_ent_type vimc_cap_type = { - .add = vimc_cap_add, - .unregister = vimc_cap_unregister, - .release = vimc_cap_release +const struct vimc_ent_type vimc_capture_type = { + .add = vimc_capture_add, + .unregister = vimc_capture_unregister, + .release = vimc_capture_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-common.c b/drivers/media/test-drivers/vimc/vimc-common.c index 7b27153c0728..4f4fcb26e236 100644 --- a/drivers/media/test-drivers/vimc/vimc-common.c +++ b/drivers/media/test-drivers/vimc/vimc-common.c @@ -8,6 +8,8 @@ #include <linux/init.h> #include <linux/module.h> +#include <media/v4l2-ctrls.h> + #include "vimc-common.h" /* @@ -241,13 +243,13 @@ static int vimc_get_pix_format(struct media_pad *pad, if (is_media_entity_v4l2_subdev(pad->entity)) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(pad->entity); - struct v4l2_subdev_format sd_fmt; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = pad->index, + }; const struct vimc_pix_map *pix_map; int ret; - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = pad->index; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); if (ret) return ret; @@ -358,6 +360,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, struct media_pad *pads, + const struct v4l2_subdev_internal_ops *int_ops, const struct v4l2_subdev_ops *sd_ops) { int ret; @@ -367,6 +370,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, /* Initialize the subdev */ v4l2_subdev_init(sd, sd_ops); + sd->internal_ops = int_ops; sd->entity.function = function; sd->entity.ops = &vimc_ent_sd_mops; sd->owner = THIS_MODULE; @@ -383,17 +387,36 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, if (ret) return ret; + /* + * Finalize the subdev initialization if it supports active states. Use + * the control handler lock as the state lock if available. + */ + if (int_ops && int_ops->init_state) { + if (sd->ctrl_handler) + sd->state_lock = sd->ctrl_handler->lock; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) { + dev_err(v4l2_dev->dev, + "%s: subdev initialization failed (err=%d)\n", + name, ret); + goto err_clean_m_ent; + } + } + /* Register the subdev with the v4l2 and the media framework */ ret = v4l2_device_register_subdev(v4l2_dev, sd); if (ret) { dev_err(v4l2_dev->dev, "%s: subdev register failed (err=%d)\n", name, ret); - goto err_clean_m_ent; + goto err_clean_sd; } return 0; +err_clean_sd: + v4l2_subdev_cleanup(sd); err_clean_m_ent: media_entity_cleanup(&sd->entity); return ret; diff --git a/drivers/media/test-drivers/vimc/vimc-common.h b/drivers/media/test-drivers/vimc/vimc-common.h index a289434e75ba..7a45a2117748 100644 --- a/drivers/media/test-drivers/vimc/vimc-common.h +++ b/drivers/media/test-drivers/vimc/vimc-common.h @@ -35,6 +35,13 @@ #define VIMC_PIX_FMT_MAX_CODES 8 +extern unsigned int vimc_allocator; + +enum vimc_allocator_type { + VIMC_ALLOCATOR_VMALLOC = 0, + VIMC_ALLOCATOR_DMA_CONTIG = 1, +}; + /** * vimc_colorimetry_clamp - Adjust colorimetry parameters * @@ -149,7 +156,7 @@ struct vimc_ent_type { */ struct vimc_ent_config { const char *name; - struct vimc_ent_type *type; + const struct vimc_ent_type *type; }; /** @@ -160,10 +167,11 @@ struct vimc_ent_config { */ bool vimc_is_source(struct media_entity *ent); -extern struct vimc_ent_type vimc_sen_type; -extern struct vimc_ent_type vimc_deb_type; -extern struct vimc_ent_type vimc_sca_type; -extern struct vimc_ent_type vimc_cap_type; +extern const struct vimc_ent_type vimc_sensor_type; +extern const struct vimc_ent_type vimc_debayer_type; +extern const struct vimc_ent_type vimc_scaler_type; +extern const struct vimc_ent_type vimc_capture_type; +extern const struct vimc_ent_type vimc_lens_type; /** * vimc_pix_map_by_index - get vimc_pix_map struct by its index @@ -207,6 +215,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); * @num_pads: number of pads to initialize * @pads: the array of pads of the entity, the caller should set the * flags of the pads + * @int_ops: pointer to &struct v4l2_subdev_internal_ops. * @sd_ops: pointer to &struct v4l2_subdev_ops. * * Helper function initialize and register the struct vimc_ent_device and struct @@ -219,6 +228,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, struct media_pad *pads, + const struct v4l2_subdev_internal_ops *int_ops, const struct v4l2_subdev_ops *sd_ops); /** diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c index 4b0ae6f51d76..f632c77e52f5 100644 --- a/drivers/media/test-drivers/vimc/vimc-core.c +++ b/drivers/media/test-drivers/vimc/vimc-core.c @@ -5,6 +5,7 @@ * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> */ +#include <linux/dma-mapping.h> #include <linux/font.h> #include <linux/init.h> #include <linux/module.h> @@ -15,9 +16,15 @@ #include "vimc-common.h" +unsigned int vimc_allocator; +module_param_named(allocator, vimc_allocator, uint, 0444); +MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n" + "\t\t 0 == vmalloc\n" + "\t\t 1 == dma-contig"); + #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" -#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ +#define VIMC_DATA_LINK(src, srcpad, sink, sinkpad, link_flags) { \ .src_ent = src, \ .src_pad = srcpad, \ .sink_ent = sink, \ @@ -25,8 +32,13 @@ .flags = link_flags, \ } -/* Structure which describes links between entities */ -struct vimc_ent_link { +#define VIMC_ANCILLARY_LINK(primary, ancillary) { \ + .primary_ent = primary, \ + .ancillary_ent = ancillary \ +} + +/* Structure which describes data links between entities */ +struct vimc_data_link { unsigned int src_ent; u16 src_pad; unsigned int sink_ent; @@ -34,82 +46,127 @@ struct vimc_ent_link { u32 flags; }; +/* Enum to improve clarity when defining vimc_data_links */ +enum vimc_data_link_ents { + SENSOR_A, + SENSOR_B, + DEBAYER_A, + DEBAYER_B, + RAW_CAPTURE_0, + RAW_CAPTURE_1, + RGB_YUV_INPUT, + SCALER, + RGB_YUV_CAPTURE, + LENS_A, + LENS_B, +}; + +/* Structure which describes ancillary links between entities */ +struct vimc_ancillary_link { + unsigned int primary_ent; + unsigned int ancillary_ent; +}; + /* Structure which describes the whole topology */ struct vimc_pipeline_config { const struct vimc_ent_config *ents; size_t num_ents; - const struct vimc_ent_link *links; - size_t num_links; + const struct vimc_data_link *data_links; + size_t num_data_links; + const struct vimc_ancillary_link *ancillary_links; + size_t num_ancillary_links; }; /* -------------------------------------------------------------------------- * Topology Configuration */ -static struct vimc_ent_config ent_config[] = { - { +static const struct vimc_ent_config ent_config[] = { + [SENSOR_A] = { .name = "Sensor A", - .type = &vimc_sen_type + .type = &vimc_sensor_type }, - { + [SENSOR_B] = { .name = "Sensor B", - .type = &vimc_sen_type + .type = &vimc_sensor_type }, - { + [DEBAYER_A] = { .name = "Debayer A", - .type = &vimc_deb_type + .type = &vimc_debayer_type }, - { + [DEBAYER_B] = { .name = "Debayer B", - .type = &vimc_deb_type + .type = &vimc_debayer_type }, - { + [RAW_CAPTURE_0] = { .name = "Raw Capture 0", - .type = &vimc_cap_type + .type = &vimc_capture_type }, - { + [RAW_CAPTURE_1] = { .name = "Raw Capture 1", - .type = &vimc_cap_type + .type = &vimc_capture_type }, - { + [RGB_YUV_INPUT] = { /* TODO: change this to vimc-input when it is implemented */ .name = "RGB/YUV Input", - .type = &vimc_sen_type + .type = &vimc_sensor_type }, - { + [SCALER] = { .name = "Scaler", - .type = &vimc_sca_type + .type = &vimc_scaler_type }, - { + [RGB_YUV_CAPTURE] = { .name = "RGB/YUV Capture", - .type = &vimc_cap_type + .type = &vimc_capture_type + }, + [LENS_A] = { + .name = "Lens A", + .type = &vimc_lens_type + }, + [LENS_B] = { + .name = "Lens B", + .type = &vimc_lens_type }, }; -static const struct vimc_ent_link ent_links[] = { +static const struct vimc_data_link data_links[] = { /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ - VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_A, 0, DEBAYER_A, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ - VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_A, 0, RAW_CAPTURE_0, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ - VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_B, 0, DEBAYER_B, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ - VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_B, 0, RAW_CAPTURE_1, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ - VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), + VIMC_DATA_LINK(DEBAYER_A, 1, SCALER, 0, MEDIA_LNK_FL_ENABLED), /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ - VIMC_ENT_LINK(3, 1, 7, 0, 0), + VIMC_DATA_LINK(DEBAYER_B, 1, SCALER, 0, 0), /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ - VIMC_ENT_LINK(6, 0, 7, 0, 0), + VIMC_DATA_LINK(RGB_YUV_INPUT, 0, SCALER, 0, 0), /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ - VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SCALER, 1, RGB_YUV_CAPTURE, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), +}; + +static const struct vimc_ancillary_link ancillary_links[] = { + /* Link: Sensor A -> Lens A */ + VIMC_ANCILLARY_LINK(0, 9), + /* Link: Sensor B -> Lens B */ + VIMC_ANCILLARY_LINK(1, 10), }; static struct vimc_pipeline_config pipe_cfg = { - .ents = ent_config, - .num_ents = ARRAY_SIZE(ent_config), - .links = ent_links, - .num_links = ARRAY_SIZE(ent_links) + .ents = ent_config, + .num_ents = ARRAY_SIZE(ent_config), + .data_links = data_links, + .num_data_links = ARRAY_SIZE(data_links), + .ancillary_links = ancillary_links, + .num_ancillary_links = ARRAY_SIZE(ancillary_links), }; /* -------------------------------------------------------------------------- */ @@ -128,8 +185,8 @@ static int vimc_create_links(struct vimc_device *vimc) int ret; /* Initialize the links between entities */ - for (i = 0; i < vimc->pipe_cfg->num_links; i++) { - const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; + for (i = 0; i < vimc->pipe_cfg->num_data_links; i++) { + const struct vimc_data_link *link = &vimc->pipe_cfg->data_links[i]; struct vimc_ent_device *ved_src = vimc->ent_devs[link->src_ent]; @@ -143,6 +200,22 @@ static int vimc_create_links(struct vimc_device *vimc) goto err_rm_links; } + for (i = 0; i < vimc->pipe_cfg->num_ancillary_links; i++) { + const struct vimc_ancillary_link *link = &vimc->pipe_cfg->ancillary_links[i]; + + struct vimc_ent_device *ved_primary = + vimc->ent_devs[link->primary_ent]; + struct vimc_ent_device *ved_ancillary = + vimc->ent_devs[link->ancillary_ent]; + struct media_link *ret_link = + media_create_ancillary_link(ved_primary->ent, ved_ancillary->ent); + + if (IS_ERR(ret_link)) { + ret = PTR_ERR(ret_link); + goto err_rm_links; + } + } + return 0; err_rm_links: @@ -278,6 +351,9 @@ static int vimc_probe(struct platform_device *pdev) tpg_set_font(font->data); + if (vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG) + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); if (!vimc) return -ENOMEM; @@ -290,8 +366,6 @@ static int vimc_probe(struct platform_device *pdev) /* Initialize media device */ strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, sizeof(vimc->mdev.model)); - snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), - "platform:%s", VIMC_PDEV_NAME); vimc->mdev.dev = &pdev->dev; media_device_init(&vimc->mdev); @@ -311,7 +385,7 @@ static int vimc_probe(struct platform_device *pdev) return 0; } -static int vimc_remove(struct platform_device *pdev) +static void vimc_remove(struct platform_device *pdev) { struct vimc_device *vimc = platform_get_drvdata(pdev); @@ -321,8 +395,6 @@ static int vimc_remove(struct platform_device *pdev) media_device_unregister(&vimc->mdev); v4l2_device_unregister(&vimc->v4l2_dev); v4l2_device_put(&vimc->v4l2_dev); - - return 0; } static void vimc_dev_release(struct device *dev) @@ -357,7 +429,7 @@ static int __init vimc_init(void) if (ret) { dev_err(&vimc_pdev.dev, "platform driver registration failed (err=%d)\n", ret); - platform_driver_unregister(&vimc_pdrv); + platform_device_unregister(&vimc_pdev); return ret; } diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c index 2d06cdbacc76..bbb7c7a86df0 100644 --- a/drivers/media/test-drivers/vimc/vimc-debayer.c +++ b/drivers/media/test-drivers/vimc/vimc-debayer.c @@ -15,32 +15,43 @@ #include "vimc-common.h" -enum vimc_deb_rgb_colors { - VIMC_DEB_RED = 0, - VIMC_DEB_GREEN = 1, - VIMC_DEB_BLUE = 2, +/* TODO: Add support for more output formats, we only support RGB888 for now. */ +#define VIMC_DEBAYER_SOURCE_MBUS_FMT MEDIA_BUS_FMT_RGB888_1X24 + +enum vimc_debayer_rgb_colors { + VIMC_DEBAYER_RED = 0, + VIMC_DEBAYER_GREEN = 1, + VIMC_DEBAYER_BLUE = 2, }; -struct vimc_deb_pix_map { +struct vimc_debayer_pix_map { u32 code; - enum vimc_deb_rgb_colors order[2][2]; + enum vimc_debayer_rgb_colors order[2][2]; }; -struct vimc_deb_device { +struct vimc_debayer_device { struct vimc_ent_device ved; struct v4l2_subdev sd; - /* The active format */ - struct v4l2_mbus_framefmt sink_fmt; - u32 src_code; - void (*set_rgb_src)(struct vimc_deb_device *vdeb, unsigned int lin, - unsigned int col, unsigned int rgb[3]); - /* Values calculated when the stream starts */ - u8 *src_frame; - const struct vimc_deb_pix_map *sink_pix_map; - unsigned int sink_bpp; - unsigned int mean_win_size; struct v4l2_ctrl_handler hdl; struct media_pad pads[2]; + + u8 *src_frame; + + void (*set_rgb_src)(struct vimc_debayer_device *vdebayer, + unsigned int lin, unsigned int col, + unsigned int rgb[3]); + + /* + * Virtual "hardware" configuration, filled when the stream starts or + * when controls are set. + */ + struct { + const struct vimc_debayer_pix_map *sink_pix_map; + unsigned int sink_bpp; + struct v4l2_area size; + unsigned int mean_win_size; + u32 src_code; + } hw; }; static const struct v4l2_mbus_framefmt sink_fmt_default = { @@ -51,7 +62,7 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -static const u32 vimc_deb_src_mbus_codes[] = { +static const u32 vimc_debayer_src_mbus_codes[] = { MEDIA_BUS_FMT_GBR888_1X24, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_BGR888_3X8, @@ -64,143 +75,139 @@ static const u32 vimc_deb_src_mbus_codes[] = { MEDIA_BUS_FMT_RGB888_1X32_PADHI, }; -static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { +static const struct vimc_debayer_pix_map vimc_debayer_pix_map_list[] = { { .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } + .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } } }, { .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE }, + { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED }, + { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } } }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } + .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } } }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE }, + { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED }, + { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } } }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } + .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } } }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE }, + { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED }, + { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } } }, }; -static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code(u32 code) +static const struct vimc_debayer_pix_map *vimc_debayer_pix_map_by_code(u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vimc_deb_pix_map_list); i++) - if (vimc_deb_pix_map_list[i].code == code) - return &vimc_deb_pix_map_list[i]; + for (i = 0; i < ARRAY_SIZE(vimc_debayer_pix_map_list); i++) + if (vimc_debayer_pix_map_list[i].code == code) + return &vimc_debayer_pix_map_list[i]; return NULL; } -static bool vimc_deb_src_code_is_valid(u32 code) +static bool vimc_debayer_src_code_is_valid(u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vimc_deb_src_mbus_codes); i++) - if (vimc_deb_src_mbus_codes[i] == code) + for (i = 0; i < ARRAY_SIZE(vimc_debayer_src_mbus_codes); i++) + if (vimc_debayer_src_mbus_codes[i] == code) return true; return false; } -static int vimc_deb_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_debayer_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; - unsigned int i; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); + mf = v4l2_subdev_state_get_format(sd_state, 0); *mf = sink_fmt_default; - for (i = 1; i < sd->entity.num_pads; i++) { - mf = v4l2_subdev_get_try_format(sd, sd_state, i); - *mf = sink_fmt_default; - mf->code = vdeb->src_code; - } + mf = v4l2_subdev_state_get_format(sd_state, 1); + *mf = sink_fmt_default; + mf->code = VIMC_DEBAYER_SOURCE_MBUS_FMT; return 0; } -static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) +static int vimc_debayer_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) { if (VIMC_IS_SRC(code->pad)) { - if (code->index >= ARRAY_SIZE(vimc_deb_src_mbus_codes)) + if (code->index >= ARRAY_SIZE(vimc_debayer_src_mbus_codes)) return -EINVAL; - code->code = vimc_deb_src_mbus_codes[code->index]; + code->code = vimc_debayer_src_mbus_codes[code->index]; } else { - if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) + if (code->index >= ARRAY_SIZE(vimc_debayer_pix_map_list)) return -EINVAL; - code->code = vimc_deb_pix_map_list[code->index].code; + code->code = vimc_debayer_pix_map_list[code->index].code; } return 0; } -static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) +static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) { if (fse->index) return -EINVAL; if (VIMC_IS_SINK(fse->pad)) { - const struct vimc_deb_pix_map *vpix = - vimc_deb_pix_map_by_code(fse->code); + const struct vimc_debayer_pix_map *vpix = + vimc_debayer_pix_map_by_code(fse->code); if (!vpix) return -EINVAL; - } else if (!vimc_deb_src_code_is_valid(fse->code)) { + } else if (!vimc_debayer_src_code_is_valid(fse->code)) { return -EINVAL; } @@ -212,30 +219,12 @@ static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int vimc_deb_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - /* Get the current sink format */ - fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? - *v4l2_subdev_get_try_format(sd, sd_state, 0) : - vdeb->sink_fmt; - - /* Set the right code for the source pad */ - if (VIMC_IS_SRC(fmt->pad)) - fmt->format.code = vdeb->src_code; - - return 0; -} - -static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) +static void vimc_debayer_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) { - const struct vimc_deb_pix_map *vpix; + const struct vimc_debayer_pix_map *vpix; /* Don't accept a code that is not on the debayer table */ - vpix = vimc_deb_pix_map_by_code(fmt->code); + vpix = vimc_debayer_pix_map_by_code(fmt->code); if (!vpix) fmt->code = sink_fmt_default.code; @@ -250,152 +239,157 @@ static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) vimc_colorimetry_clamp(fmt); } -static int vimc_deb_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static int vimc_debayer_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - u32 *src_code; + struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vdeb->src_frame) - return -EBUSY; - - sink_fmt = &vdeb->sink_fmt; - src_code = &vdeb->src_code; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code; - } + /* Do not change the format while stream is on. */ + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vdebayer->src_frame) + return -EBUSY; /* - * Do not change the format of the source pad, - * it is propagated from the sink + * Do not change the format of the source pad, it is propagated from + * the sink. */ - if (VIMC_IS_SRC(fmt->pad)) { - u32 code = fmt->format.code; + if (VIMC_IS_SRC(fmt->pad)) + return v4l2_subdev_get_fmt(sd, sd_state, fmt); - fmt->format = *sink_fmt; + /* Set the new format in the sink pad. */ + vimc_debayer_adjust_sink_fmt(&fmt->format); - if (vimc_deb_src_code_is_valid(code)) - *src_code = code; + format = v4l2_subdev_state_get_format(sd_state, 0); - fmt->format.code = *src_code; - } else { - /* Set the new format in the sink pad */ - vimc_deb_adjust_sink_fmt(&fmt->format); - - dev_dbg(vdeb->ved.dev, "%s: sink format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name, - /* old */ - sink_fmt->width, sink_fmt->height, sink_fmt->code, - sink_fmt->colorspace, sink_fmt->quantization, - sink_fmt->xfer_func, sink_fmt->ycbcr_enc, - /* new */ - fmt->format.width, fmt->format.height, fmt->format.code, - fmt->format.colorspace, fmt->format.quantization, - fmt->format.xfer_func, fmt->format.ycbcr_enc); - - *sink_fmt = fmt->format; - } + dev_dbg(vdebayer->ved.dev, "%s: sink format update: " + "old:%dx%d (0x%x, %d, %d, %d, %d) " + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name, + /* old */ + format->width, format->height, format->code, + format->colorspace, format->quantization, + format->xfer_func, format->ycbcr_enc, + /* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *format = fmt->format; + + /* Propagate the format to the source pad. */ + format = v4l2_subdev_state_get_format(sd_state, 1); + *format = fmt->format; + format->code = VIMC_DEBAYER_SOURCE_MBUS_FMT; return 0; } -static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { - .init_cfg = vimc_deb_init_cfg, - .enum_mbus_code = vimc_deb_enum_mbus_code, - .enum_frame_size = vimc_deb_enum_frame_size, - .get_fmt = vimc_deb_get_fmt, - .set_fmt = vimc_deb_set_fmt, +static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = { + .enum_mbus_code = vimc_debayer_enum_mbus_code, + .enum_frame_size = vimc_debayer_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = vimc_debayer_set_fmt, }; -static void vimc_deb_process_rgb_frame(struct vimc_deb_device *vdeb, - unsigned int lin, - unsigned int col, - unsigned int rgb[3]) +static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer, + unsigned int lin, + unsigned int col, + unsigned int rgb[3]) { const struct vimc_pix_map *vpix; unsigned int i, index; - vpix = vimc_pix_map_by_code(vdeb->src_code); - index = VIMC_FRAME_INDEX(lin, col, vdeb->sink_fmt.width, 3); + vpix = vimc_pix_map_by_code(vdebayer->hw.src_code); + index = VIMC_FRAME_INDEX(lin, col, vdebayer->hw.size.width, 3); for (i = 0; i < 3; i++) { switch (vpix->pixelformat) { case V4L2_PIX_FMT_RGB24: - vdeb->src_frame[index + i] = rgb[i]; + vdebayer->src_frame[index + i] = rgb[i]; break; case V4L2_PIX_FMT_BGR24: - vdeb->src_frame[index + i] = rgb[2 - i]; + vdebayer->src_frame[index + i] = rgb[2 - i]; break; } } } -static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) +static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); if (enable) { + const struct v4l2_mbus_framefmt *sink_fmt; + const struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_subdev_state *state; const struct vimc_pix_map *vpix; unsigned int frame_size; - if (vdeb->src_frame) + if (vdebayer->src_frame) return 0; + state = v4l2_subdev_lock_and_get_active_state(sd); + sink_fmt = v4l2_subdev_state_get_format(state, 0); + src_fmt = v4l2_subdev_state_get_format(state, 1); + /* Calculate the frame size of the source pad */ - vpix = vimc_pix_map_by_code(vdeb->src_code); - frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * - vpix->bpp; + vpix = vimc_pix_map_by_code(src_fmt->code); + frame_size = src_fmt->width * src_fmt->height * vpix->bpp; /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code); - vdeb->sink_bpp = vpix->bpp; + vpix = vimc_pix_map_by_code(sink_fmt->code); + vdebayer->hw.sink_bpp = vpix->bpp; /* Get the corresponding pixel map from the table */ - vdeb->sink_pix_map = - vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); + vdebayer->hw.sink_pix_map = + vimc_debayer_pix_map_by_code(sink_fmt->code); + + vdebayer->hw.size.width = sink_fmt->width; + vdebayer->hw.size.height = sink_fmt->height; + + vdebayer->hw.src_code = src_fmt->code; + + v4l2_subdev_unlock_state(state); /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory */ - vdeb->src_frame = vmalloc(frame_size); - if (!vdeb->src_frame) + vdebayer->src_frame = vmalloc(frame_size); + if (!vdebayer->src_frame) return -ENOMEM; - } else { - if (!vdeb->src_frame) + if (!vdebayer->src_frame) return 0; - vfree(vdeb->src_frame); - vdeb->src_frame = NULL; + vfree(vdebayer->src_frame); + vdebayer->src_frame = NULL; } return 0; } -static const struct v4l2_subdev_core_ops vimc_deb_core_ops = { +static const struct v4l2_subdev_core_ops vimc_debayer_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; -static const struct v4l2_subdev_video_ops vimc_deb_video_ops = { - .s_stream = vimc_deb_s_stream, +static const struct v4l2_subdev_video_ops vimc_debayer_video_ops = { + .s_stream = vimc_debayer_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_debayer_ops = { + .core = &vimc_debayer_core_ops, + .pad = &vimc_debayer_pad_ops, + .video = &vimc_debayer_video_ops, }; -static const struct v4l2_subdev_ops vimc_deb_ops = { - .core = &vimc_deb_core_ops, - .pad = &vimc_deb_pad_ops, - .video = &vimc_deb_video_ops, +static const struct v4l2_subdev_internal_ops vimc_debayer_internal_ops = { + .init_state = vimc_debayer_init_state, }; -static unsigned int vimc_deb_get_val(const u8 *bytes, - const unsigned int n_bytes) +static unsigned int vimc_debayer_get_val(const u8 *bytes, + const unsigned int n_bytes) { unsigned int i; unsigned int acc = 0; @@ -406,11 +400,11 @@ static unsigned int vimc_deb_get_val(const u8 *bytes, return acc; } -static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, - const u8 *frame, - const unsigned int lin, - const unsigned int col, - unsigned int rgb[3]) +static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer, + const u8 *frame, + const unsigned int lin, + const unsigned int col, + unsigned int rgb[3]) { unsigned int i, seek, wlin, wcol; unsigned int n_rgb[3] = {0, 0, 0}; @@ -423,13 +417,13 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * the top left corner of the mean window (considering the current * pixel as the center) */ - seek = vdeb->mean_win_size / 2; + seek = vdebayer->hw.mean_win_size / 2; /* Sum the values of the colors in the mean window */ - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n", - vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek); + vdebayer->sd.name, lin, col, vdebayer->hw.size.height, seek); /* * Iterate through all the lines in the mean window, start @@ -438,7 +432,7 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * frame */ for (wlin = seek > lin ? 0 : lin - seek; - wlin < lin + seek + 1 && wlin < vdeb->sink_fmt.height; + wlin < lin + seek + 1 && wlin < vdebayer->hw.size.height; wlin++) { /* @@ -448,78 +442,80 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * frame */ for (wcol = seek > col ? 0 : col - seek; - wcol < col + seek + 1 && wcol < vdeb->sink_fmt.width; + wcol < col + seek + 1 && wcol < vdebayer->hw.size.width; wcol++) { - enum vimc_deb_rgb_colors color; + enum vimc_debayer_rgb_colors color; unsigned int index; /* Check which color this pixel is */ - color = vdeb->sink_pix_map->order[wlin % 2][wcol % 2]; + color = vdebayer->hw.sink_pix_map->order[wlin % 2][wcol % 2]; index = VIMC_FRAME_INDEX(wlin, wcol, - vdeb->sink_fmt.width, - vdeb->sink_bpp); + vdebayer->hw.size.width, + vdebayer->hw.sink_bpp); - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n", - vdeb->sd.name, index, wlin, wcol, color); + vdebayer->sd.name, index, wlin, wcol, color); /* Get its value */ rgb[color] = rgb[color] + - vimc_deb_get_val(&frame[index], vdeb->sink_bpp); + vimc_debayer_get_val(&frame[index], + vdebayer->hw.sink_bpp); /* Save how many values we already added */ n_rgb[color]++; - dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", - vdeb->sd.name, rgb[color], n_rgb[color]); + dev_dbg(vdebayer->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", + vdebayer->sd.name, rgb[color], n_rgb[color]); } } /* Calculate the mean */ for (i = 0; i < 3; i++) { - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n", - vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]); + vdebayer->sd.name, lin, col, i, rgb[i], n_rgb[i]); if (n_rgb[i]) rgb[i] = rgb[i] / n_rgb[i]; - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: FINAL CALC: %dx%d Color %d, val %d\n", - vdeb->sd.name, lin, col, i, rgb[i]); + vdebayer->sd.name, lin, col, i, rgb[i]); } } -static void *vimc_deb_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) +static void *vimc_debayer_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { - struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, - ved); + struct vimc_debayer_device *vdebayer = + container_of(ved, struct vimc_debayer_device, ved); + unsigned int rgb[3]; unsigned int i, j; /* If the stream in this node is not active, just return */ - if (!vdeb->src_frame) + if (!vdebayer->src_frame) return ERR_PTR(-EINVAL); - for (i = 0; i < vdeb->sink_fmt.height; i++) - for (j = 0; j < vdeb->sink_fmt.width; j++) { - vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb); - vdeb->set_rgb_src(vdeb, i, j, rgb); + for (i = 0; i < vdebayer->hw.size.height; i++) + for (j = 0; j < vdebayer->hw.size.width; j++) { + vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, i, j, rgb); + vdebayer->set_rgb_src(vdebayer, i, j, rgb); } - return vdeb->src_frame; + return vdebayer->src_frame; } -static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) +static int vimc_debayer_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vimc_deb_device *vdeb = - container_of(ctrl->handler, struct vimc_deb_device, hdl); + struct vimc_debayer_device *vdebayer = + container_of(ctrl->handler, struct vimc_debayer_device, hdl); switch (ctrl->id) { case VIMC_CID_MEAN_WIN_SIZE: - vdeb->mean_win_size = ctrl->val; + vdebayer->hw.mean_win_size = ctrl->val; break; default: return -EINVAL; @@ -527,29 +523,30 @@ static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = { - .s_ctrl = vimc_deb_s_ctrl, +static const struct v4l2_ctrl_ops vimc_debayer_ctrl_ops = { + .s_ctrl = vimc_debayer_s_ctrl, }; -static void vimc_deb_release(struct vimc_ent_device *ved) +static void vimc_debayer_release(struct vimc_ent_device *ved) { - struct vimc_deb_device *vdeb = - container_of(ved, struct vimc_deb_device, ved); + struct vimc_debayer_device *vdebayer = + container_of(ved, struct vimc_debayer_device, ved); - v4l2_ctrl_handler_free(&vdeb->hdl); - media_entity_cleanup(vdeb->ved.ent); - kfree(vdeb); + v4l2_ctrl_handler_free(&vdebayer->hdl); + v4l2_subdev_cleanup(&vdebayer->sd); + media_entity_cleanup(vdebayer->ved.ent); + kfree(vdebayer); } -static const struct v4l2_ctrl_config vimc_deb_ctrl_class = { +static const struct v4l2_ctrl_config vimc_debayer_ctrl_class = { .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, .id = VIMC_CID_VIMC_CLASS, .name = "VIMC Controls", .type = V4L2_CTRL_TYPE_CTRL_CLASS, }; -static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { - .ops = &vimc_deb_ctrl_ops, +static const struct v4l2_ctrl_config vimc_debayer_ctrl_mean_win_size = { + .ops = &vimc_debayer_ctrl_ops, .id = VIMC_CID_MEAN_WIN_SIZE, .name = "Debayer Mean Window Size", .type = V4L2_CTRL_TYPE_INTEGER, @@ -559,65 +556,57 @@ static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { .def = 3, }; -static struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, - const char *vcfg_name) +static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc, + const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_deb_device *vdeb; + struct vimc_debayer_device *vdebayer; int ret; - /* Allocate the vdeb struct */ - vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL); - if (!vdeb) + /* Allocate the vdebayer struct */ + vdebayer = kzalloc(sizeof(*vdebayer), GFP_KERNEL); + if (!vdebayer) return ERR_PTR(-ENOMEM); /* Create controls: */ - v4l2_ctrl_handler_init(&vdeb->hdl, 2); - v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL); - v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL); - vdeb->sd.ctrl_handler = &vdeb->hdl; - if (vdeb->hdl.error) { - ret = vdeb->hdl.error; - goto err_free_vdeb; + v4l2_ctrl_handler_init(&vdebayer->hdl, 2); + v4l2_ctrl_new_custom(&vdebayer->hdl, &vimc_debayer_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vdebayer->hdl, &vimc_debayer_ctrl_mean_win_size, NULL); + vdebayer->sd.ctrl_handler = &vdebayer->hdl; + if (vdebayer->hdl.error) { + ret = vdebayer->hdl.error; + goto err_free_vdebayer; } /* Initialize ved and sd */ - vdeb->pads[0].flags = MEDIA_PAD_FL_SINK; - vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE; + vdebayer->pads[0].flags = MEDIA_PAD_FL_SINK; + vdebayer->pads[1].flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, + ret = vimc_ent_sd_register(&vdebayer->ved, &vdebayer->sd, v4l2_dev, vcfg_name, MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, - vdeb->pads, &vimc_deb_ops); + vdebayer->pads, &vimc_debayer_internal_ops, + &vimc_debayer_ops); if (ret) goto err_free_hdl; - vdeb->ved.process_frame = vimc_deb_process_frame; - vdeb->ved.dev = vimc->mdev.dev; - vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def; + vdebayer->ved.process_frame = vimc_debayer_process_frame; + vdebayer->ved.dev = vimc->mdev.dev; + vdebayer->hw.mean_win_size = vimc_debayer_ctrl_mean_win_size.def; - /* Initialize the frame format */ - vdeb->sink_fmt = sink_fmt_default; - /* - * TODO: Add support for more output formats, we only support - * RGB888 for now - * NOTE: the src format is always the same as the sink, except - * for the code - */ - vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24; - vdeb->set_rgb_src = vimc_deb_process_rgb_frame; + vdebayer->set_rgb_src = vimc_debayer_process_rgb_frame; - return &vdeb->ved; + return &vdebayer->ved; err_free_hdl: - v4l2_ctrl_handler_free(&vdeb->hdl); -err_free_vdeb: - kfree(vdeb); + v4l2_ctrl_handler_free(&vdebayer->hdl); +err_free_vdebayer: + kfree(vdebayer); return ERR_PTR(ret); } -struct vimc_ent_type vimc_deb_type = { - .add = vimc_deb_add, - .release = vimc_deb_release +const struct vimc_ent_type vimc_debayer_type = { + .add = vimc_debayer_add, + .release = vimc_debayer_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-lens.c b/drivers/media/test-drivers/vimc/vimc-lens.c new file mode 100644 index 000000000000..96399057a2b5 --- /dev/null +++ b/drivers/media/test-drivers/vimc/vimc-lens.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-lens.c Virtual Media Controller Driver + * Copyright (C) 2022 Google, Inc + * Author: yunkec@google.com (Yunke Cao) + */ + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> + +#include "vimc-common.h" + +#define VIMC_LENS_MAX_FOCUS_POS 1023 +#define VIMC_LENS_MAX_FOCUS_STEP 1 + +struct vimc_lens_device { + struct vimc_ent_device ved; + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + u32 focus_absolute; +}; + +static const struct v4l2_subdev_core_ops vimc_lens_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops vimc_lens_ops = { + .core = &vimc_lens_core_ops +}; + +static int vimc_lens_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vimc_lens_device *vlens = + container_of(ctrl->handler, struct vimc_lens_device, hdl); + if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { + vlens->focus_absolute = ctrl->val; + return 0; + } + return -EINVAL; +} + +static const struct v4l2_ctrl_ops vimc_lens_ctrl_ops = { + .s_ctrl = vimc_lens_s_ctrl, +}; + +static struct vimc_ent_device *vimc_lens_add(struct vimc_device *vimc, + const char *vcfg_name) +{ + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; + struct vimc_lens_device *vlens; + int ret; + + /* Allocate the vlens struct */ + vlens = kzalloc(sizeof(*vlens), GFP_KERNEL); + if (!vlens) + return ERR_PTR(-ENOMEM); + + v4l2_ctrl_handler_init(&vlens->hdl, 1); + + v4l2_ctrl_new_std(&vlens->hdl, &vimc_lens_ctrl_ops, + V4L2_CID_FOCUS_ABSOLUTE, 0, + VIMC_LENS_MAX_FOCUS_POS, VIMC_LENS_MAX_FOCUS_STEP, 0); + vlens->sd.ctrl_handler = &vlens->hdl; + if (vlens->hdl.error) { + ret = vlens->hdl.error; + goto err_free_vlens; + } + vlens->ved.dev = vimc->mdev.dev; + + ret = vimc_ent_sd_register(&vlens->ved, &vlens->sd, v4l2_dev, + vcfg_name, MEDIA_ENT_F_LENS, 0, + NULL, NULL, &vimc_lens_ops); + if (ret) + goto err_free_hdl; + + return &vlens->ved; + +err_free_hdl: + v4l2_ctrl_handler_free(&vlens->hdl); +err_free_vlens: + kfree(vlens); + + return ERR_PTR(ret); +} + +static void vimc_lens_release(struct vimc_ent_device *ved) +{ + struct vimc_lens_device *vlens = + container_of(ved, struct vimc_lens_device, ved); + + v4l2_ctrl_handler_free(&vlens->hdl); + v4l2_subdev_cleanup(&vlens->sd); + media_entity_cleanup(vlens->ved.ent); + kfree(vlens); +} + +const struct vimc_ent_type vimc_lens_type = { + .add = vimc_lens_add, + .release = vimc_lens_release +}; diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c index 06880dd0b6ac..47d0d63865a0 100644 --- a/drivers/media/test-drivers/vimc/vimc-scaler.c +++ b/drivers/media/test-drivers/vimc/vimc-scaler.c @@ -6,6 +6,7 @@ */ #include <linux/moduleparam.h> +#include <linux/string.h> #include <linux/vmalloc.h> #include <linux/v4l2-mediabus.h> #include <media/v4l2-rect.h> @@ -13,41 +14,45 @@ #include "vimc-common.h" -static unsigned int sca_mult = 3; -module_param(sca_mult, uint, 0000); -MODULE_PARM_DESC(sca_mult, " the image size multiplier"); - -#define MAX_ZOOM 8 +/* Pad identifier */ +enum vimc_scaler_pad { + VIMC_SCALER_SINK = 0, + VIMC_SCALER_SRC = 1, +}; -#define VIMC_SCA_FMT_WIDTH_DEFAULT 640 -#define VIMC_SCA_FMT_HEIGHT_DEFAULT 480 +#define VIMC_SCALER_FMT_WIDTH_DEFAULT 640 +#define VIMC_SCALER_FMT_HEIGHT_DEFAULT 480 -struct vimc_sca_device { +struct vimc_scaler_device { struct vimc_ent_device ved; struct v4l2_subdev sd; - /* NOTE: the source fmt is the same as the sink - * with the width and hight multiplied by mult - */ - struct v4l2_mbus_framefmt sink_fmt; - struct v4l2_rect crop_rect; - /* Values calculated when the stream starts */ - u8 *src_frame; - unsigned int src_line_size; - unsigned int bpp; struct media_pad pads[2]; + + u8 *src_frame; + + /* + * Virtual "hardware" configuration, filled when the stream starts or + * when controls are set. + */ + struct { + struct v4l2_mbus_framefmt sink_fmt; + struct v4l2_mbus_framefmt src_fmt; + struct v4l2_rect sink_crop; + unsigned int bpp; + } hw; }; -static const struct v4l2_mbus_framefmt sink_fmt_default = { - .width = VIMC_SCA_FMT_WIDTH_DEFAULT, - .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, +static const struct v4l2_mbus_framefmt fmt_default = { + .width = VIMC_SCALER_FMT_WIDTH_DEFAULT, + .height = VIMC_SCALER_FMT_HEIGHT_DEFAULT, .code = MEDIA_BUS_FMT_RGB888_1X24, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_SRGB, }; static const struct v4l2_rect crop_rect_default = { - .width = VIMC_SCA_FMT_WIDTH_DEFAULT, - .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, + .width = VIMC_SCALER_FMT_WIDTH_DEFAULT, + .height = VIMC_SCALER_FMT_HEIGHT_DEFAULT, .top = 0, .left = 0, }; @@ -60,7 +65,7 @@ static const struct v4l2_rect crop_rect_min = { }; static struct v4l2_rect -vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) +vimc_scaler_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) { /* Get the crop bounds to clamp the crop rectangle correctly */ struct v4l2_rect r = { @@ -72,41 +77,25 @@ vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) return r; } -static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r, - const struct v4l2_mbus_framefmt *sink_fmt) -{ - const struct v4l2_rect sink_rect = - vimc_sca_get_crop_bound_sink(sink_fmt); - - /* Disallow rectangles smaller than the minimal one. */ - v4l2_rect_set_min_size(r, &crop_rect_min); - v4l2_rect_map_inside(r, &sink_rect); -} - -static int vimc_sca_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_scaler_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mf; struct v4l2_rect *r; unsigned int i; - mf = v4l2_subdev_get_try_format(sd, sd_state, 0); - *mf = sink_fmt_default; + for (i = 0; i < sd->entity.num_pads; i++) { + mf = v4l2_subdev_state_get_format(sd_state, i); + *mf = fmt_default; + } - r = v4l2_subdev_get_try_crop(sd, sd_state, 0); + r = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK); *r = crop_rect_default; - for (i = 1; i < sd->entity.num_pads; i++) { - mf = v4l2_subdev_get_try_format(sd, sd_state, i); - *mf = sink_fmt_default; - mf->width = mf->width * sca_mult; - mf->height = mf->height * sca_mult; - } - return 0; } -static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, +static int vimc_scaler_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { @@ -127,7 +116,7 @@ static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, +static int vimc_scaler_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { @@ -144,140 +133,92 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; - if (VIMC_IS_SINK(fse->pad)) { - fse->max_width = VIMC_FRAME_MAX_WIDTH; - fse->max_height = VIMC_FRAME_MAX_HEIGHT; - } else { - fse->max_width = VIMC_FRAME_MAX_WIDTH * MAX_ZOOM; - fse->max_height = VIMC_FRAME_MAX_HEIGHT * MAX_ZOOM; - } + fse->max_width = VIMC_FRAME_MAX_WIDTH; + fse->max_height = VIMC_FRAME_MAX_HEIGHT; return 0; } -static int vimc_sca_get_fmt(struct v4l2_subdev *sd, +static int vimc_scaler_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_rect *crop_rect; + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *fmt; - /* Get the current sink format */ - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - } else { - format->format = vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } - - /* Scale the frame size for the source pad */ - if (VIMC_IS_SRC(format->pad)) { - format->format.width = crop_rect->width * sca_mult; - format->format.height = crop_rect->height * sca_mult; - } + /* Do not change the active format while stream is on */ + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame) + return -EBUSY; - return 0; -} + fmt = v4l2_subdev_state_get_format(sd_state, format->pad); -static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) -{ - const struct vimc_pix_map *vpix; + /* + * The media bus code and colorspace can only be changed on the sink + * pad, the source pad only follows. + */ + if (format->pad == VIMC_SCALER_SINK) { + const struct vimc_pix_map *vpix; - /* Only accept code in the pix map table in non bayer format */ - vpix = vimc_pix_map_by_code(fmt->code); - if (!vpix || vpix->bayer) - fmt->code = sink_fmt_default.code; + /* Only accept code in the pix map table in non bayer format. */ + vpix = vimc_pix_map_by_code(format->format.code); + if (vpix && !vpix->bayer) + fmt->code = format->format.code; + else + fmt->code = fmt_default.code; + + /* Clamp the colorspace to valid values. */ + fmt->colorspace = format->format.colorspace; + fmt->ycbcr_enc = format->format.ycbcr_enc; + fmt->quantization = format->format.quantization; + fmt->xfer_func = format->format.xfer_func; + vimc_colorimetry_clamp(fmt); + } - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, + /* Clamp and align the width and height */ + fmt->width = clamp_t(u32, format->format.width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; - fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, + fmt->height = clamp_t(u32, format->format.height, VIMC_FRAME_MIN_HEIGHT, VIMC_FRAME_MAX_HEIGHT) & ~1; - if (fmt->field == V4L2_FIELD_ANY) - fmt->field = sink_fmt_default.field; - - vimc_colorimetry_clamp(fmt); -} - -static int vimc_sca_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsca->src_frame) - return -EBUSY; - - sink_fmt = &vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - } - /* - * Do not change the format of the source pad, - * it is propagated from the sink + * Propagate the sink pad format to the crop rectangle and the source + * pad. */ - if (VIMC_IS_SRC(fmt->pad)) { - fmt->format = *sink_fmt; - fmt->format.width = crop_rect->width * sca_mult; - fmt->format.height = crop_rect->height * sca_mult; - } else { - /* Set the new format in the sink pad */ - vimc_sca_adjust_sink_fmt(&fmt->format); - - dev_dbg(vsca->ved.dev, "%s: sink format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name, - /* old */ - sink_fmt->width, sink_fmt->height, sink_fmt->code, - sink_fmt->colorspace, sink_fmt->quantization, - sink_fmt->xfer_func, sink_fmt->ycbcr_enc, - /* new */ - fmt->format.width, fmt->format.height, fmt->format.code, - fmt->format.colorspace, fmt->format.quantization, - fmt->format.xfer_func, fmt->format.ycbcr_enc); - - *sink_fmt = fmt->format; - - /* Do the crop, but respect the current bounds */ - vimc_sca_adjust_sink_crop(crop_rect, sink_fmt); + if (format->pad == VIMC_SCALER_SINK) { + struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_rect *crop; + + crop = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK); + crop->width = fmt->width; + crop->height = fmt->height; + crop->top = 0; + crop->left = 0; + + src_fmt = v4l2_subdev_state_get_format(sd_state, VIMC_SCALER_SRC); + *src_fmt = *fmt; } + format->format = *fmt; + return 0; } -static int vimc_sca_get_selection(struct v4l2_subdev *sd, +static int vimc_scaler_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; if (VIMC_IS_SRC(sel->pad)) return -EINVAL; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = &vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - } - switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *crop_rect; + sel->r = *v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK); break; case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r = vimc_sca_get_crop_bound_sink(sink_fmt); + sink_fmt = v4l2_subdev_state_get_format(sd_state, VIMC_SCALER_SINK); + sel->r = vimc_scaler_get_crop_bound_sink(sink_fmt); break; default: return -EINVAL; @@ -286,237 +227,196 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd, return 0; } -static int vimc_sca_set_selection(struct v4l2_subdev *sd, +static void vimc_scaler_adjust_sink_crop(struct v4l2_rect *r, + const struct v4l2_mbus_framefmt *sink_fmt) +{ + const struct v4l2_rect sink_rect = + vimc_scaler_get_crop_bound_sink(sink_fmt); + + /* Disallow rectangles smaller than the minimal one. */ + v4l2_rect_set_min_size(r, &crop_rect_min); + v4l2_rect_map_inside(r, &sink_rect); +} + +static int vimc_scaler_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *crop_rect; - if (VIMC_IS_SRC(sel->pad)) + /* Only support setting the crop of the sink pad */ + if (VIMC_IS_SRC(sel->pad) || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsca->src_frame) - return -EBUSY; + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame) + return -EBUSY; - crop_rect = &vsca->crop_rect; - sink_fmt = &vsca->sink_fmt; - } else { - crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0); - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - /* Do the crop, but respect the current bounds */ - vimc_sca_adjust_sink_crop(&sel->r, sink_fmt); - *crop_rect = sel->r; - break; - default: - return -EINVAL; - } + crop_rect = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK); + sink_fmt = v4l2_subdev_state_get_format(sd_state, VIMC_SCALER_SINK); + vimc_scaler_adjust_sink_crop(&sel->r, sink_fmt); + *crop_rect = sel->r; return 0; } -static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { - .init_cfg = vimc_sca_init_cfg, - .enum_mbus_code = vimc_sca_enum_mbus_code, - .enum_frame_size = vimc_sca_enum_frame_size, - .get_fmt = vimc_sca_get_fmt, - .set_fmt = vimc_sca_set_fmt, - .get_selection = vimc_sca_get_selection, - .set_selection = vimc_sca_set_selection, +static const struct v4l2_subdev_pad_ops vimc_scaler_pad_ops = { + .enum_mbus_code = vimc_scaler_enum_mbus_code, + .enum_frame_size = vimc_scaler_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = vimc_scaler_set_fmt, + .get_selection = vimc_scaler_get_selection, + .set_selection = vimc_scaler_set_selection, }; -static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) +static int vimc_scaler_s_stream(struct v4l2_subdev *sd, int enable) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); if (enable) { - const struct vimc_pix_map *vpix; + struct v4l2_subdev_state *state; + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *rect; unsigned int frame_size; - if (vsca->src_frame) + if (vscaler->src_frame) return 0; - /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); - vsca->bpp = vpix->bpp; + state = v4l2_subdev_lock_and_get_active_state(sd); + + /* Save the bytes per pixel of the sink. */ + format = v4l2_subdev_state_get_format(state, VIMC_SCALER_SINK); + vscaler->hw.sink_fmt = *format; + vscaler->hw.bpp = vimc_pix_map_by_code(format->code)->bpp; - /* Calculate the width in bytes of the src frame */ - vsca->src_line_size = vsca->crop_rect.width * - sca_mult * vsca->bpp; + /* Calculate the frame size of the source pad. */ + format = v4l2_subdev_state_get_format(state, VIMC_SCALER_SRC); + vscaler->hw.src_fmt = *format; + frame_size = format->width * format->height * vscaler->hw.bpp; - /* Calculate the frame size of the source pad */ - frame_size = vsca->src_line_size * vsca->crop_rect.height * - sca_mult; + rect = v4l2_subdev_state_get_crop(state, VIMC_SCALER_SINK); + vscaler->hw.sink_crop = *rect; - /* Allocate the frame buffer. Use vmalloc to be able to - * allocate a large amount of memory + v4l2_subdev_unlock_state(state); + + /* + * Allocate the frame buffer. Use vmalloc to be able to allocate + * a large amount of memory. */ - vsca->src_frame = vmalloc(frame_size); - if (!vsca->src_frame) + vscaler->src_frame = vmalloc(frame_size); + if (!vscaler->src_frame) return -ENOMEM; - } else { - if (!vsca->src_frame) + if (!vscaler->src_frame) return 0; - vfree(vsca->src_frame); - vsca->src_frame = NULL; + vfree(vscaler->src_frame); + vscaler->src_frame = NULL; } return 0; } -static const struct v4l2_subdev_video_ops vimc_sca_video_ops = { - .s_stream = vimc_sca_s_stream, +static const struct v4l2_subdev_video_ops vimc_scaler_video_ops = { + .s_stream = vimc_scaler_s_stream, }; -static const struct v4l2_subdev_ops vimc_sca_ops = { - .pad = &vimc_sca_pad_ops, - .video = &vimc_sca_video_ops, +static const struct v4l2_subdev_ops vimc_scaler_ops = { + .pad = &vimc_scaler_pad_ops, + .video = &vimc_scaler_video_ops, }; -static void vimc_sca_fill_pix(u8 *const ptr, - const u8 *const pixel, - const unsigned int bpp) -{ - unsigned int i; - - /* copy the pixel to the pointer */ - for (i = 0; i < bpp; i++) - ptr[i] = pixel[i]; -} +static const struct v4l2_subdev_internal_ops vimc_scaler_internal_ops = { + .init_state = vimc_scaler_init_state, +}; -static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, - unsigned int lin, unsigned int col, - const u8 *const sink_frame) +static void vimc_scaler_fill_src_frame(const struct vimc_scaler_device *const vscaler, + const u8 *const sink_frame) { - const struct v4l2_rect crop_rect = vsca->crop_rect; - unsigned int i, j, index; - const u8 *pixel; - - /* Point to the pixel value in position (lin, col) in the sink frame */ - index = VIMC_FRAME_INDEX(lin, col, - vsca->sink_fmt.width, - vsca->bpp); - pixel = &sink_frame[index]; - - dev_dbg(vsca->ved.dev, - "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n", - vsca->sd.name, lin, col, index); - - /* point to the place we are going to put the first pixel - * in the scaled src frame - */ - lin -= crop_rect.top; - col -= crop_rect.left; - index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult, - crop_rect.width * sca_mult, vsca->bpp); - - dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n", - vsca->sd.name, lin * sca_mult, col * sca_mult, index); - - /* Repeat this pixel mult times */ - for (i = 0; i < sca_mult; i++) { - /* Iterate through each beginning of a - * pixel repetition in a line - */ - for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) { - dev_dbg(vsca->ved.dev, - "sca: %s: sca: scale_pix src pos %d\n", - vsca->sd.name, index + j); - - /* copy the pixel to the position index + j */ - vimc_sca_fill_pix(&vsca->src_frame[index + j], - pixel, vsca->bpp); + const struct v4l2_mbus_framefmt *sink_fmt = &vscaler->hw.sink_fmt; + const struct v4l2_mbus_framefmt *src_fmt = &vscaler->hw.src_fmt; + const struct v4l2_rect *r = &vscaler->hw.sink_crop; + unsigned int src_x, src_y; + u8 *walker = vscaler->src_frame; + + /* Set each pixel at the src_frame to its sink_frame equivalent */ + for (src_y = 0; src_y < src_fmt->height; src_y++) { + unsigned int snk_y, y_offset; + + snk_y = (src_y * r->height) / src_fmt->height + r->top; + y_offset = snk_y * sink_fmt->width * vscaler->hw.bpp; + + for (src_x = 0; src_x < src_fmt->width; src_x++) { + unsigned int snk_x, x_offset, index; + + snk_x = (src_x * r->width) / src_fmt->width + r->left; + x_offset = snk_x * vscaler->hw.bpp; + index = y_offset + x_offset; + memcpy(walker, &sink_frame[index], vscaler->hw.bpp); + walker += vscaler->hw.bpp; } - - /* move the index to the next line */ - index += vsca->src_line_size; } } -static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca, - const u8 *const sink_frame) -{ - const struct v4l2_rect r = vsca->crop_rect; - unsigned int i, j; - - /* Scale each pixel from the original sink frame */ - /* TODO: implement scale down, only scale up is supported for now */ - for (i = r.top; i < r.top + r.height; i++) - for (j = r.left; j < r.left + r.width; j++) - vimc_sca_scale_pix(vsca, i, j, sink_frame); -} - -static void *vimc_sca_process_frame(struct vimc_ent_device *ved, +static void *vimc_scaler_process_frame(struct vimc_ent_device *ved, const void *sink_frame) { - struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + struct vimc_scaler_device *vscaler = container_of(ved, struct vimc_scaler_device, ved); /* If the stream in this node is not active, just return */ - if (!vsca->src_frame) + if (!vscaler->src_frame) return ERR_PTR(-EINVAL); - vimc_sca_fill_src_frame(vsca, sink_frame); + vimc_scaler_fill_src_frame(vscaler, sink_frame); - return vsca->src_frame; + return vscaler->src_frame; }; -static void vimc_sca_release(struct vimc_ent_device *ved) +static void vimc_scaler_release(struct vimc_ent_device *ved) { - struct vimc_sca_device *vsca = - container_of(ved, struct vimc_sca_device, ved); + struct vimc_scaler_device *vscaler = + container_of(ved, struct vimc_scaler_device, ved); - media_entity_cleanup(vsca->ved.ent); - kfree(vsca); + v4l2_subdev_cleanup(&vscaler->sd); + media_entity_cleanup(vscaler->ved.ent); + kfree(vscaler); } -static struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, +static struct vimc_ent_device *vimc_scaler_add(struct vimc_device *vimc, const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_sca_device *vsca; + struct vimc_scaler_device *vscaler; int ret; - /* Allocate the vsca struct */ - vsca = kzalloc(sizeof(*vsca), GFP_KERNEL); - if (!vsca) + /* Allocate the vscaler struct */ + vscaler = kzalloc(sizeof(*vscaler), GFP_KERNEL); + if (!vscaler) return ERR_PTR(-ENOMEM); /* Initialize ved and sd */ - vsca->pads[0].flags = MEDIA_PAD_FL_SINK; - vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE; + vscaler->pads[VIMC_SCALER_SINK].flags = MEDIA_PAD_FL_SINK; + vscaler->pads[VIMC_SCALER_SRC].flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, + ret = vimc_ent_sd_register(&vscaler->ved, &vscaler->sd, v4l2_dev, vcfg_name, MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, - vsca->pads, &vimc_sca_ops); + vscaler->pads, &vimc_scaler_internal_ops, + &vimc_scaler_ops); if (ret) { - kfree(vsca); + kfree(vscaler); return ERR_PTR(ret); } - vsca->ved.process_frame = vimc_sca_process_frame; - vsca->ved.dev = vimc->mdev.dev; - - /* Initialize the frame format */ - vsca->sink_fmt = sink_fmt_default; - - /* Initialize the crop selection */ - vsca->crop_rect = crop_rect_default; + vscaler->ved.process_frame = vimc_scaler_process_frame; + vscaler->ved.dev = vimc->mdev.dev; - return &vsca->ved; + return &vscaler->ved; } -struct vimc_ent_type vimc_sca_type = { - .add = vimc_sca_add, - .release = vimc_sca_release +const struct vimc_ent_type vimc_scaler_type = { + .add = vimc_scaler_add, + .release = vimc_scaler_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 74ab79cadb5d..027767777763 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -14,23 +14,30 @@ #include "vimc-common.h" -enum vimc_sen_osd_mode { - VIMC_SEN_OSD_SHOW_ALL = 0, - VIMC_SEN_OSD_SHOW_COUNTERS = 1, - VIMC_SEN_OSD_SHOW_NONE = 2 +enum vimc_sensor_osd_mode { + VIMC_SENSOR_OSD_SHOW_ALL = 0, + VIMC_SENSOR_OSD_SHOW_COUNTERS = 1, + VIMC_SENSOR_OSD_SHOW_NONE = 2 }; -struct vimc_sen_device { +struct vimc_sensor_device { struct vimc_ent_device ved; struct v4l2_subdev sd; struct tpg_data tpg; - u8 *frame; - enum vimc_sen_osd_mode osd_value; - u64 start_stream_ts; - /* The active format */ - struct v4l2_mbus_framefmt mbus_format; struct v4l2_ctrl_handler hdl; struct media_pad pad; + + u8 *frame; + + /* + * Virtual "hardware" configuration, filled when the stream starts or + * when controls are set. + */ + struct { + struct v4l2_area size; + enum vimc_sensor_osd_mode osd_value; + u64 start_stream_ts; + } hw; }; static const struct v4l2_mbus_framefmt fmt_default = { @@ -41,24 +48,20 @@ static const struct v4l2_mbus_framefmt fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -static int vimc_sen_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_sensor_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - unsigned int i; - - for (i = 0; i < sd->entity.num_pads; i++) { - struct v4l2_mbus_framefmt *mf; + struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(sd, sd_state, i); - *mf = fmt_default; - } + mf = v4l2_subdev_state_get_format(sd_state, 0); + *mf = fmt_default; return 0; } -static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) +static int vimc_sensor_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) { u32 mbus_code = vimc_mbus_code_by_index(code->index); @@ -70,9 +73,9 @@ static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) +static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) { const struct vimc_pix_map *vpix; @@ -92,39 +95,25 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int vimc_sen_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor, + const struct v4l2_mbus_framefmt *format) { - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); - - fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) : - vsen->mbus_format; - - return 0; -} + const struct vimc_pix_map *vpix = vimc_pix_map_by_code(format->code); -static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) -{ - const struct vimc_pix_map *vpix = - vimc_pix_map_by_code(vsen->mbus_format.code); - - tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height, vsen->mbus_format.field); - tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); - tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); - tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); + tpg_reset_source(&vsensor->tpg, format->width, format->height, + format->field); + tpg_s_bytesperline(&vsensor->tpg, 0, format->width * vpix->bpp); + tpg_s_buf_height(&vsensor->tpg, format->height); + tpg_s_fourcc(&vsensor->tpg, vpix->pixelformat); /* TODO: add support for V4L2_FIELD_ALTERNATE */ - tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); - tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); - tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc); - tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization); - tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); + tpg_s_field(&vsensor->tpg, format->field, false); + tpg_s_colorspace(&vsensor->tpg, format->colorspace); + tpg_s_ycbcr_enc(&vsensor->tpg, format->ycbcr_enc); + tpg_s_quantization(&vsensor->tpg, format->quantization); + tpg_s_xfer_func(&vsensor->tpg, format->xfer_func); } -static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) +static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) { const struct vimc_pix_map *vpix; @@ -145,29 +134,25 @@ static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) vimc_colorimetry_clamp(fmt); } -static int vimc_sen_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); + struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsen->frame) - return -EBUSY; + /* Do not change the format while stream is on */ + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsensor->frame) + return -EBUSY; - mf = &vsen->mbus_format; - } else { - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); - } + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); /* Set the new format */ - vimc_sen_adjust_fmt(&fmt->format); + vimc_sensor_adjust_fmt(&fmt->format); - dev_dbg(vsen->ved.dev, "%s: format update: " + dev_dbg(vsensor->ved.dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsensor->sd.name, /* old */ mf->width, mf->height, mf->code, mf->colorspace, mf->quantization, @@ -182,146 +167,157 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { - .init_cfg = vimc_sen_init_cfg, - .enum_mbus_code = vimc_sen_enum_mbus_code, - .enum_frame_size = vimc_sen_enum_frame_size, - .get_fmt = vimc_sen_get_fmt, - .set_fmt = vimc_sen_set_fmt, +static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = { + .enum_mbus_code = vimc_sensor_enum_mbus_code, + .enum_frame_size = vimc_sensor_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = vimc_sensor_set_fmt, }; -static void *vimc_sen_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) +static void *vimc_sensor_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { - struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, - ved); + struct vimc_sensor_device *vsensor = + container_of(ved, struct vimc_sensor_device, ved); + const unsigned int line_height = 16; u8 *basep[TPG_MAX_PLANES][2]; unsigned int line = 1; char str[100]; - tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); - tpg_calc_text_basep(&vsen->tpg, basep, 0, vsen->frame); - switch (vsen->osd_value) { - case VIMC_SEN_OSD_SHOW_ALL: { - const char *order = tpg_g_color_order(&vsen->tpg); + tpg_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame); + tpg_calc_text_basep(&vsensor->tpg, basep, 0, vsensor->frame); + switch (vsensor->hw.osd_value) { + case VIMC_SENSOR_OSD_SHOW_ALL: { + const char *order = tpg_g_color_order(&vsensor->tpg); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, order); snprintf(str, sizeof(str), "brightness %3d, contrast %3d, saturation %3d, hue %d ", - vsen->tpg.brightness, - vsen->tpg.contrast, - vsen->tpg.saturation, - vsen->tpg.hue); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); + vsensor->tpg.brightness, + vsensor->tpg.contrast, + vsensor->tpg.saturation, + vsensor->tpg.hue); + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), "sensor size: %dx%d", - vsen->mbus_format.width, - vsen->mbus_format.height); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); + vsensor->hw.size.width, vsensor->hw.size.height); + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); fallthrough; } - case VIMC_SEN_OSD_SHOW_COUNTERS: { + case VIMC_SENSOR_OSD_SHOW_COUNTERS: { unsigned int ms; - ms = div_u64(ktime_get_ns() - vsen->start_stream_ts, 1000000); + ms = div_u64(ktime_get_ns() - vsensor->hw.start_stream_ts, 1000000); snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d", (ms / (60 * 60 * 1000)) % 24, (ms / (60 * 1000)) % 60, (ms / 1000) % 60, ms % 1000); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); break; } - case VIMC_SEN_OSD_SHOW_NONE: + case VIMC_SENSOR_OSD_SHOW_NONE: default: break; } - return vsen->frame; + return vsensor->frame; } -static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) +static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable) { - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); + struct vimc_sensor_device *vsensor = + container_of(sd, struct vimc_sensor_device, sd); if (enable) { + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; const struct vimc_pix_map *vpix; unsigned int frame_size; - vsen->start_stream_ts = ktime_get_ns(); + state = v4l2_subdev_lock_and_get_active_state(sd); + format = v4l2_subdev_state_get_format(state, 0); + + /* Configure the test pattern generator. */ + vimc_sensor_tpg_s_format(vsensor, format); + + /* Calculate the frame size. */ + vpix = vimc_pix_map_by_code(format->code); + frame_size = format->width * vpix->bpp * format->height; + + vsensor->hw.size.width = format->width; + vsensor->hw.size.height = format->height; - /* Calculate the frame size */ - vpix = vimc_pix_map_by_code(vsen->mbus_format.code); - frame_size = vsen->mbus_format.width * vpix->bpp * - vsen->mbus_format.height; + v4l2_subdev_unlock_state(state); /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory */ - vsen->frame = vmalloc(frame_size); - if (!vsen->frame) + vsensor->frame = vmalloc(frame_size); + if (!vsensor->frame) return -ENOMEM; - /* configure the test pattern generator */ - vimc_sen_tpg_s_format(vsen); - + vsensor->hw.start_stream_ts = ktime_get_ns(); } else { - vfree(vsen->frame); - vsen->frame = NULL; + vfree(vsensor->frame); + vsensor->frame = NULL; } return 0; } -static const struct v4l2_subdev_core_ops vimc_sen_core_ops = { +static const struct v4l2_subdev_core_ops vimc_sensor_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; -static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { - .s_stream = vimc_sen_s_stream, +static const struct v4l2_subdev_video_ops vimc_sensor_video_ops = { + .s_stream = vimc_sensor_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_sensor_ops = { + .core = &vimc_sensor_core_ops, + .pad = &vimc_sensor_pad_ops, + .video = &vimc_sensor_video_ops, }; -static const struct v4l2_subdev_ops vimc_sen_ops = { - .core = &vimc_sen_core_ops, - .pad = &vimc_sen_pad_ops, - .video = &vimc_sen_video_ops, +static const struct v4l2_subdev_internal_ops vimc_sensor_internal_ops = { + .init_state = vimc_sensor_init_state, }; -static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) +static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vimc_sen_device *vsen = - container_of(ctrl->handler, struct vimc_sen_device, hdl); + struct vimc_sensor_device *vsensor = + container_of(ctrl->handler, struct vimc_sensor_device, hdl); switch (ctrl->id) { case VIMC_CID_TEST_PATTERN: - tpg_s_pattern(&vsen->tpg, ctrl->val); + tpg_s_pattern(&vsensor->tpg, ctrl->val); break; case V4L2_CID_HFLIP: - tpg_s_hflip(&vsen->tpg, ctrl->val); + tpg_s_hflip(&vsensor->tpg, ctrl->val); break; case V4L2_CID_VFLIP: - tpg_s_vflip(&vsen->tpg, ctrl->val); + tpg_s_vflip(&vsensor->tpg, ctrl->val); break; case V4L2_CID_BRIGHTNESS: - tpg_s_brightness(&vsen->tpg, ctrl->val); + tpg_s_brightness(&vsensor->tpg, ctrl->val); break; case V4L2_CID_CONTRAST: - tpg_s_contrast(&vsen->tpg, ctrl->val); + tpg_s_contrast(&vsensor->tpg, ctrl->val); break; case V4L2_CID_HUE: - tpg_s_hue(&vsen->tpg, ctrl->val); + tpg_s_hue(&vsensor->tpg, ctrl->val); break; case V4L2_CID_SATURATION: - tpg_s_saturation(&vsen->tpg, ctrl->val); + tpg_s_saturation(&vsensor->tpg, ctrl->val); break; case VIMC_CID_OSD_TEXT_MODE: - vsen->osd_value = ctrl->val; + vsensor->hw.osd_value = ctrl->val; break; default: return -EINVAL; @@ -329,31 +325,32 @@ static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { - .s_ctrl = vimc_sen_s_ctrl, +static const struct v4l2_ctrl_ops vimc_sensor_ctrl_ops = { + .s_ctrl = vimc_sensor_s_ctrl, }; -static void vimc_sen_release(struct vimc_ent_device *ved) +static void vimc_sensor_release(struct vimc_ent_device *ved) { - struct vimc_sen_device *vsen = - container_of(ved, struct vimc_sen_device, ved); - - v4l2_ctrl_handler_free(&vsen->hdl); - tpg_free(&vsen->tpg); - media_entity_cleanup(vsen->ved.ent); - kfree(vsen); + struct vimc_sensor_device *vsensor = + container_of(ved, struct vimc_sensor_device, ved); + + v4l2_ctrl_handler_free(&vsensor->hdl); + tpg_free(&vsensor->tpg); + v4l2_subdev_cleanup(&vsensor->sd); + media_entity_cleanup(vsensor->ved.ent); + kfree(vsensor); } /* Image Processing Controls */ -static const struct v4l2_ctrl_config vimc_sen_ctrl_class = { +static const struct v4l2_ctrl_config vimc_sensor_ctrl_class = { .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, .id = VIMC_CID_VIMC_CLASS, .name = "VIMC Controls", .type = V4L2_CTRL_TYPE_CTRL_CLASS, }; -static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = { - .ops = &vimc_sen_ctrl_ops, +static const struct v4l2_ctrl_config vimc_sensor_ctrl_test_pattern = { + .ops = &vimc_sensor_ctrl_ops, .id = VIMC_CID_TEST_PATTERN, .name = "Test Pattern", .type = V4L2_CTRL_TYPE_MENU, @@ -368,8 +365,8 @@ static const char * const vimc_ctrl_osd_mode_strings[] = { NULL, }; -static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = { - .ops = &vimc_sen_ctrl_ops, +static const struct v4l2_ctrl_config vimc_sensor_ctrl_osd_mode = { + .ops = &vimc_sensor_ctrl_ops, .id = VIMC_CID_OSD_TEXT_MODE, .name = "Show Information", .type = V4L2_CTRL_TYPE_MENU, @@ -377,76 +374,72 @@ static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = { .qmenu = vimc_ctrl_osd_mode_strings, }; -static struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, - const char *vcfg_name) +static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc, + const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_sen_device *vsen; + struct vimc_sensor_device *vsensor; int ret; - /* Allocate the vsen struct */ - vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); - if (!vsen) + /* Allocate the vsensor struct */ + vsensor = kzalloc(sizeof(*vsensor), GFP_KERNEL); + if (!vsensor) return ERR_PTR(-ENOMEM); - v4l2_ctrl_handler_init(&vsen->hdl, 4); + v4l2_ctrl_handler_init(&vsensor->hdl, 4); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_osd_mode, NULL); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_test_pattern, NULL); + v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_osd_mode, NULL); + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_HUE, -128, 127, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_SATURATION, 0, 255, 1, 128); - vsen->sd.ctrl_handler = &vsen->hdl; - if (vsen->hdl.error) { - ret = vsen->hdl.error; - goto err_free_vsen; + vsensor->sd.ctrl_handler = &vsensor->hdl; + if (vsensor->hdl.error) { + ret = vsensor->hdl.error; + goto err_free_vsensor; } /* Initialize the test pattern generator */ - tpg_init(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH); + tpg_init(&vsensor->tpg, fmt_default.width, fmt_default.height); + ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH); if (ret) goto err_free_hdl; /* Initialize ved and sd */ - vsen->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, + vsensor->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = vimc_ent_sd_register(&vsensor->ved, &vsensor->sd, v4l2_dev, vcfg_name, - MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad, - &vimc_sen_ops); + MEDIA_ENT_F_CAM_SENSOR, 1, &vsensor->pad, + &vimc_sensor_internal_ops, &vimc_sensor_ops); if (ret) goto err_free_tpg; - vsen->ved.process_frame = vimc_sen_process_frame; - vsen->ved.dev = vimc->mdev.dev; - - /* Initialize the frame format */ - vsen->mbus_format = fmt_default; + vsensor->ved.process_frame = vimc_sensor_process_frame; + vsensor->ved.dev = vimc->mdev.dev; - return &vsen->ved; + return &vsensor->ved; err_free_tpg: - tpg_free(&vsen->tpg); + tpg_free(&vsensor->tpg); err_free_hdl: - v4l2_ctrl_handler_free(&vsen->hdl); -err_free_vsen: - kfree(vsen); + v4l2_ctrl_handler_free(&vsensor->hdl); +err_free_vsensor: + kfree(vsensor); return ERR_PTR(ret); } -struct vimc_ent_type vimc_sen_type = { - .add = vimc_sen_add, - .release = vimc_sen_release +const struct vimc_ent_type vimc_sensor_type = { + .add = vimc_sensor_add, + .release = vimc_sensor_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c index 65feb3c596db..15d863f97cbf 100644 --- a/drivers/media/test-drivers/vimc/vimc-streamer.c +++ b/drivers/media/test-drivers/vimc/vimc-streamer.c @@ -30,7 +30,7 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent) for (i = 0; i < ent->num_pads; i++) { if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) continue; - pad = media_entity_remote_pad(&ent->pads[i]); + pad = media_pad_remote_pad_first(&ent->pads[i]); return pad ? pad->entity : NULL; } return NULL; @@ -59,6 +59,12 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) continue; sd = media_entity_to_v4l2_subdev(ved->ent); + /* + * Do not call .s_stream() to stop an already + * stopped/unstarted subdev. + */ + if (!v4l2_subdev_is_streaming(sd)) + continue; v4l2_subdev_call(sd, video, s_stream, 0); } } |
