diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-08 11:13:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-08 11:13:17 -0700 |
commit | e7a1414f9dc3498c4c35b9ca266d539e8bccab53 (patch) | |
tree | f50a78785859182f9916c93dcf97c6539dbe3f3e /drivers/media | |
parent | 85c1a25494837ff33fdfebe98b2e4cf5b0c78475 (diff) | |
parent | 0d672fffb447aa1699d76fdacd90dc31eeb66d97 (diff) | |
download | linux-e7a1414f9dc3498c4c35b9ca266d539e8bccab53.tar.bz2 |
Merge tag 'media/v5.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- remove the deprecated Zoran driver from staging
- new I2C driver: ST MIPID02 CSI-2 camera bridge
- new platform driver: Amlogic Meson AO CEC G12A Controller
- add support for USB audio via the media controller
- au0828 driver is now supported via the media controller on both on
media and on usbaudio
- new kernel test for the media device allocator
- add support for stateless decoder at vicodec driver
- lots of other driver improvements fixes and cleanups
* tag 'media/v5.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (218 commits)
media: dt-bindings: aspeed-video: Add missing memory-region property
media: platform: Aspeed: Make reserved memory optional
media: platform: Aspeed: Remove use of reset line
media: stm32-dcmi: return appropriate error codes during probe
media: vsp1: Add support for missing 16-bit RGB555 formats
media: vsp1: Add support for missing 16-bit RGB444 formats
media: vsp1: Add support for missing 32-bit RGB formats
media: v4l: Add definitions for missing 16-bit RGB555 formats
media: v4l: Add definitions for missing 16-bit RGB4444 formats
media: v4l: Add definitions for missing 32-bit RGB formats
media: zoran: remove deprecated driver
media: MAINTAINERS: Update AO CEC with ao-cec-g12a driver
media: platform: meson: Add Amlogic Meson G12A AO CEC Controller driver
media: dt-bindings: media: meson-ao-cec: Add G12A AO-CEC-B Compatible
media: cros-ec-cec: decrement HDMI device refcount
media: seco-cec: decrement HDMI device refcount
media: tegra_cec: use new cec_notifier_parse_hdmi_phandle helper
media: stih_cec: use new cec_notifier_parse_hdmi_phandle helper
media: s5p_cec: use new cec_notifier_parse_hdmi_phandle helper
media: meson: ao-cec: use new cec_notifier_parse_hdmi_phandle helper
...
Diffstat (limited to 'drivers/media')
202 files changed, 5408 insertions, 2465 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 102eb35fcf3f..8efaf99243e0 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -31,14 +31,14 @@ comment "Multimedia core support" # config MEDIA_CAMERA_SUPPORT bool "Cameras/video grabbers support" - ---help--- + help Enable support for webcams and video grabbers. Say Y when you have a webcam or a video capture grabber board. config MEDIA_ANALOG_TV_SUPPORT bool "Analog TV support" - ---help--- + help Enable analog TV support. Say Y when you have a TV board with analog support or with a @@ -50,7 +50,7 @@ config MEDIA_ANALOG_TV_SUPPORT config MEDIA_DIGITAL_TV_SUPPORT bool "Digital TV support" - ---help--- + help Enable digital TV support. Say Y when you have a board with digital support or a board with @@ -58,7 +58,7 @@ config MEDIA_DIGITAL_TV_SUPPORT config MEDIA_RADIO_SUPPORT bool "AM/FM radio receivers/transmitters support" - ---help--- + help Enable AM/FM radio support. Additional info and docs are available on the web at @@ -72,14 +72,14 @@ config MEDIA_RADIO_SUPPORT config MEDIA_SDR_SUPPORT bool "Software defined radio support" - ---help--- + help Enable software defined radio support. Say Y when you have a software defined radio device. config MEDIA_CEC_SUPPORT bool "HDMI CEC support" - ---help--- + help Enable support for HDMI CEC (Consumer Electronics Control), which is an optional HDMI feature. @@ -96,7 +96,7 @@ source "drivers/media/cec/Kconfig" config MEDIA_CONTROLLER bool "Media Controller API" depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT - ---help--- + help Enable the media controller API used to query media devices internal topology and configure it dynamically. @@ -105,7 +105,7 @@ config MEDIA_CONTROLLER config MEDIA_CONTROLLER_DVB bool "Enable Media controller for DVB (EXPERIMENTAL)" depends on MEDIA_CONTROLLER && DVB_CORE - ---help--- + help Enable the media controller API support for DVB. This is currently experimental. @@ -114,7 +114,7 @@ config MEDIA_CONTROLLER_REQUEST_API bool "Enable Media controller Request API (EXPERIMENTAL)" depends on MEDIA_CONTROLLER && STAGING_MEDIA default n - ---help--- + help DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. This option enables the Request API for the Media controller and V4L2 @@ -137,7 +137,7 @@ config VIDEO_DEV config VIDEO_V4L2_SUBDEV_API bool "V4L2 sub-device userspace API" depends on VIDEO_DEV && MEDIA_CONTROLLER - ---help--- + help Enables the V4L2 sub-device pad-level userspace API used to configure video format, size and frame rate between hardware blocks. diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 985d35ec6b29..4a330d0e5e40 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -6,6 +6,12 @@ media-objs := media-device.o media-devnode.o media-entity.o \ media-request.o +ifeq ($(CONFIG_MEDIA_CONTROLLER),y) + ifeq ($(CONFIG_USB),y) + media-objs += media-dev-allocator.o + endif +endif + # # I2C drivers should come before other drivers, otherwise they'll fail # when compiled as builtin drivers diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index 9c2b108c613a..b5aadacf335a 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -2,11 +2,11 @@ config MEDIA_CEC_RC bool "HDMI CEC RC integration" depends on CEC_CORE && RC_CORE depends on CEC_CORE=m || RC_CORE=y - ---help--- + help Pass on CEC remote control messages to the RC framework. config CEC_PIN_ERROR_INJ bool "Enable CEC error injection support" depends on CEC_PIN && DEBUG_FS - ---help--- + help This option enables CEC error injection using debugfs. diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index cc875dabd765..f5d1578e256a 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -126,6 +126,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &cec_devnode_fops); devnode->cdev.owner = owner; + kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret) { diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index dd2078b27a41..9598c7778871 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/kref.h> +#include <linux/of_platform.h> #include <media/cec.h> #include <media/cec-notifier.h> @@ -127,3 +128,32 @@ void cec_notifier_unregister(struct cec_notifier *n) cec_notifier_put(n); } EXPORT_SYMBOL_GPL(cec_notifier_unregister); + +struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) +{ + struct platform_device *hdmi_pdev; + struct device *hdmi_dev = NULL; + struct device_node *np; + + np = of_parse_phandle(dev->of_node, "hdmi-phandle", 0); + + if (!np) { + dev_err(dev, "Failed to find HDMI node in device tree\n"); + return ERR_PTR(-ENODEV); + } + hdmi_pdev = of_find_device_by_node(np); + of_node_put(np); + if (hdmi_pdev) { + hdmi_dev = &hdmi_pdev->dev; + /* + * Note that the device struct is only used as a key into the + * cec_notifiers list, it is never actually accessed. + * So we decrement the reference here so we don't leak + * memory. + */ + put_device(hdmi_dev); + return hdmi_dev; + } + return ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL_GPL(cec_notifier_parse_hdmi_phandle); diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c index 1dcc39b87bb7..121cda73ff88 100644 --- a/drivers/media/common/cx2341x.c +++ b/drivers/media/common/cx2341x.c @@ -1028,7 +1028,7 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, return func(priv, cmd, args, 0, data); } -#define NEQ(field) (old->field != new->field) +#define CMP_FIELD(__old, __new, __field) (__old->__field != __new->__field) int cx2341x_update(void *priv, cx2341x_mbox_func func, const struct cx2341x_mpeg_params *old, @@ -1042,20 +1042,22 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, 11, /* VCD */ 12, /* SVCD */ }; - - int err = 0; - int force = (old == NULL); - u16 temporal = new->video_temporal_filter; + int err; cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); - if (force || NEQ(is_50hz)) { + if (!old || + CMP_FIELD(old, new, is_50hz)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz); - if (err) return err; + if (err) + return err; } - if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { + if (!old || + CMP_FIELD(old, new, width) || + CMP_FIELD(old, new, height) || + CMP_FIELD(old, new, video_encoding)) { u16 w = new->width; u16 h = new->height; @@ -1065,94 +1067,127 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, } err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); - if (err) return err; + if (err) + return err; } - if (force || NEQ(stream_type)) { + if (!old || + CMP_FIELD(old, new, stream_type)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_aspect)) { + if (!old || + CMP_FIELD(old, new, video_aspect)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { + if (!old || + CMP_FIELD(old, new, video_b_frames) || + CMP_FIELD(old, new, video_gop_size)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, - new->video_gop_size, new->video_b_frames + 1); - if (err) return err; + new->video_gop_size, new->video_b_frames + 1); + if (err) + return err; } - if (force || NEQ(video_gop_closure)) { + if (!old || + CMP_FIELD(old, new, video_gop_closure)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure); - if (err) return err; + if (err) + return err; } - if (force || NEQ(audio_properties)) { + if (!old || + CMP_FIELD(old, new, audio_properties)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); - if (err) return err; + if (err) + return err; } - if (force || NEQ(audio_mute)) { + if (!old || + CMP_FIELD(old, new, audio_mute)) { err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || - NEQ(video_bitrate_peak)) { + if (!old || + CMP_FIELD(old, new, video_bitrate_mode) || + CMP_FIELD(old, new, video_bitrate) || + CMP_FIELD(old, new, video_bitrate_peak)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, - new->video_bitrate_mode, new->video_bitrate, - new->video_bitrate_peak / 400, 0, 0); - if (err) return err; + new->video_bitrate_mode, new->video_bitrate, + new->video_bitrate_peak / 400, 0, 0); + if (err) + return err; } - if (force || NEQ(video_spatial_filter_mode) || - NEQ(video_temporal_filter_mode) || - NEQ(video_median_filter_type)) { + if (!old || + CMP_FIELD(old, new, video_spatial_filter_mode) || + CMP_FIELD(old, new, video_temporal_filter_mode) || + CMP_FIELD(old, new, video_median_filter_type)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, - 2, new->video_spatial_filter_mode | + 2, + new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1), - new->video_median_filter_type); - if (err) return err; + new->video_median_filter_type); + if (err) + return err; } - if (force || NEQ(video_luma_median_filter_bottom) || - NEQ(video_luma_median_filter_top) || - NEQ(video_chroma_median_filter_bottom) || - NEQ(video_chroma_median_filter_top)) { + if (!old || + CMP_FIELD(old, new, video_luma_median_filter_bottom) || + CMP_FIELD(old, new, video_luma_median_filter_top) || + CMP_FIELD(old, new, video_chroma_median_filter_bottom) || + CMP_FIELD(old, new, video_chroma_median_filter_top)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, - new->video_luma_median_filter_bottom, - new->video_luma_median_filter_top, - new->video_chroma_median_filter_bottom, - new->video_chroma_median_filter_top); - if (err) return err; + new->video_luma_median_filter_bottom, + new->video_luma_median_filter_top, + new->video_chroma_median_filter_bottom, + new->video_chroma_median_filter_top); + if (err) + return err; } - if (force || NEQ(video_luma_spatial_filter_type) || - NEQ(video_chroma_spatial_filter_type)) { + if (!old || + CMP_FIELD(old, new, video_luma_spatial_filter_type) || + CMP_FIELD(old, new, video_chroma_spatial_filter_type)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_spatial_filter) || - old->video_temporal_filter != temporal) { + if (!old || + CMP_FIELD(old, new, video_spatial_filter) || + CMP_FIELD(old, new, video_temporal_filter)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, - 2, new->video_spatial_filter, temporal); - if (err) return err; + 2, new->video_spatial_filter, + new->video_temporal_filter); + if (err) + return err; } - if (force || NEQ(video_temporal_decimation)) { + if (!old || + CMP_FIELD(old, new, video_temporal_decimation)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1, new->video_temporal_decimation); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_mute) || - (new->video_mute && NEQ(video_mute_yuv))) { + if (!old || + CMP_FIELD(old, new, video_mute) || + (new->video_mute && CMP_FIELD(old, new, video_mute_yuv))) { err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, - new->video_mute | (new->video_mute_yuv << 8)); - if (err) return err; + new->video_mute | (new->video_mute_yuv << 8)); + if (err) + return err; } - if (force || NEQ(stream_insert_nav_packets)) { + if (!old || + CMP_FIELD(old, new, stream_insert_nav_packets)) { err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, - 7, new->stream_insert_nav_packets); - if (err) return err; + 7, new->stream_insert_nav_packets); + if (err) + return err; } return 0; } diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig index 4bfbd5f463d1..577880b133eb 100644 --- a/drivers/media/common/siano/Kconfig +++ b/drivers/media/common/siano/Kconfig @@ -15,7 +15,7 @@ config SMS_SIANO_RC depends on SMS_USB_DRV || SMS_SDIO_DRV depends on MEDIA_COMMON_OPTIONS default y - ---help--- + help Choose Y to select Remote Controller support for Siano driver. config SMS_SIANO_DEBUGFS @@ -24,7 +24,7 @@ config SMS_SIANO_DEBUGFS depends on DEBUG_FS depends on SMS_USB_DRV = SMS_SDIO_DRV - ---help--- + help Choose Y to enable visualizing a dump of the frontend statistics response packets via debugfs. Currently, works only with Siano USB devices. diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 15b6b9c0a2e4..7ebd58a1c431 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -672,6 +672,11 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, return -EBUSY; } + if (q->waiting_in_dqbuf && *count) { + dprintk(1, "another dup()ped fd is waiting for a buffer\n"); + return -EBUSY; + } + if (*count == 0 || q->num_buffers != 0 || (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) { /* @@ -807,6 +812,10 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, } if (!q->num_buffers) { + if (q->waiting_in_dqbuf && *count) { + dprintk(1, "another dup()ped fd is waiting for a buffer\n"); + return -EBUSY; + } memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); q->memory = memory; q->waiting_for_buffers = !q->is_output; @@ -915,8 +924,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) if (WARN_ON(state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR && - state != VB2_BUF_STATE_QUEUED && - state != VB2_BUF_STATE_REQUEUEING)) + state != VB2_BUF_STATE_QUEUED)) state = VB2_BUF_STATE_ERROR; #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -929,8 +937,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) dprintk(4, "done processing on buffer %d, state: %d\n", vb->index, state); - if (state != VB2_BUF_STATE_QUEUED && - state != VB2_BUF_STATE_REQUEUEING) { + if (state != VB2_BUF_STATE_QUEUED) { /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, finish, vb->planes[plane].mem_priv); @@ -938,8 +945,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) } spin_lock_irqsave(&q->done_lock, flags); - if (state == VB2_BUF_STATE_QUEUED || - state == VB2_BUF_STATE_REQUEUEING) { + if (state == VB2_BUF_STATE_QUEUED) { vb->state = VB2_BUF_STATE_QUEUED; } else { /* Add the buffer to the done buffers list */ @@ -949,8 +955,6 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) atomic_dec(&q->owned_by_drv_count); if (state != VB2_BUF_STATE_QUEUED && vb->req_obj.req) { - /* This is not supported at the moment */ - WARN_ON(state == VB2_BUF_STATE_REQUEUEING); media_request_object_unbind(&vb->req_obj); media_request_object_put(&vb->req_obj); } @@ -962,10 +966,6 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) switch (state) { case VB2_BUF_STATE_QUEUED: return; - case VB2_BUF_STATE_REQUEUEING: - if (q->start_streaming_called) - __enqueue_in_driver(vb); - return; default: /* Inform any processes that may be waiting for buffers */ wake_up(&q->done_wq); @@ -1516,6 +1516,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, vb = q->bufs[index]; + if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && + q->requires_requests) { + dprintk(1, "qbuf requires a request\n"); + return -EBADR; + } + if ((req && q->uses_qbuf) || (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && q->uses_requests)) { @@ -1659,6 +1665,11 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) for (;;) { int ret; + if (q->waiting_in_dqbuf) { + dprintk(1, "another dup()ped fd is waiting for a buffer\n"); + return -EBUSY; + } + if (!q->streaming) { dprintk(1, "streaming off, will not wait for buffers\n"); return -EINVAL; @@ -1686,6 +1697,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) return -EAGAIN; } + q->waiting_in_dqbuf = 1; /* * We are streaming and blocking, wait for another buffer to * become ready or for streamoff. Driver's lock is released to @@ -1706,6 +1718,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * the locks or return an error if one occurred. */ call_void_qop(q, wait_finish, q); + q->waiting_in_dqbuf = 0; if (ret) { dprintk(1, "sleep was interrupted\n"); return ret; @@ -2247,6 +2260,9 @@ int vb2_core_queue_init(struct vb2_queue *q) WARN_ON(!q->ops->buf_queue)) return -EINVAL; + if (WARN_ON(q->requires_requests && !q->supports_requests)) + return -EINVAL; + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); @@ -2585,6 +2601,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ if (!data) return -EINVAL; + if (q->waiting_in_dqbuf) { + dprintk(3, "another dup()ped fd is %s\n", + read ? "reading" : "writing"); + return -EBUSY; + } + /* * Initialize emulator on first call. */ diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index d09dee20e421..fb9ac7696fc6 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -122,9 +122,9 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /* - * __init_v4l2_vb2_buffer() - initialize the v4l2_vb2_buffer struct + * __init_vb2_v4l2_buffer() - initialize the vb2_v4l2_buffer struct */ -static void __init_v4l2_vb2_buffer(struct vb2_buffer *vb) +static void __init_vb2_v4l2_buffer(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -368,6 +368,12 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md if (ret) return ret; + if (!is_prepare && (b->flags & V4L2_BUF_FLAG_REQUEST_FD) && + vb->state != VB2_BUF_STATE_DEQUEUED) { + dprintk(1, "%s: buffer is not in dequeued state\n", opname); + return -EINVAL; + } + if (!vb->prepared) { /* Copy relevant information provided by the userspace */ memset(vbuf->planes, 0, @@ -381,6 +387,10 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md return 0; if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) { + if (q->requires_requests) { + dprintk(1, "%s: queue requires requests\n", opname); + return -EBADR; + } if (q->uses_requests) { dprintk(1, "%s: queue uses requests\n", opname); return -EBUSY; @@ -388,7 +398,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md return 0; } else if (!q->supports_requests) { dprintk(1, "%s: queue does not support requests\n", opname); - return -EACCES; + return -EBADR; } else if (q->uses_qbuf) { dprintk(1, "%s: queue does not use requests\n", opname); return -EBUSY; @@ -419,11 +429,6 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md !q->ops->buf_out_validate)) return -EINVAL; - if (vb->state != VB2_BUF_STATE_DEQUEUED) { - dprintk(1, "%s: buffer is not in dequeued state\n", opname); - return -EINVAL; - } - if (b->request_fd < 0) { dprintk(1, "%s: request_fd < 0\n", opname); return -EINVAL; @@ -543,7 +548,6 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) break; case VB2_BUF_STATE_PREPARING: case VB2_BUF_STATE_DEQUEUED: - case VB2_BUF_STATE_REQUEUEING: /* nothing */ break; } @@ -592,7 +596,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes) static const struct vb2_buf_ops v4l2_buf_ops = { .verify_planes_array = __verify_planes_array_core, - .init_buffer = __init_v4l2_vb2_buffer, + .init_buffer = __init_vb2_v4l2_buffer, .fill_user_buffer = __fill_v4l2_buffer, .fill_vb2_buffer = __fill_vb2_buffer, .copy_timestamp = __copy_timestamp, diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 6dfbd5b05907..1c6659f7c394 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -46,17 +46,17 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, buf->size = size; buf->vaddr = vmalloc_user(buf->size); - buf->dma_dir = dma_dir; - buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_vmalloc_put; - buf->handler.arg = buf; - if (!buf->vaddr) { pr_debug("vmalloc of size %ld failed\n", buf->size); kfree(buf); return ERR_PTR(-ENOMEM); } + buf->dma_dir = dma_dir; + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_vmalloc_put; + buf->handler.arg = buf; + refcount_set(&buf->refcount, 1); return buf; } diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 4a5834a1c3b7..a3393cd4e584 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -526,7 +526,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvb_media_device_free(dvbdev); kfree(dvbdevfops); kfree(dvbdev); - up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return ret; } diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index f59a102b0a64..9ba8f39fe310 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -467,7 +467,7 @@ struct dvb_frontend *as102_attach(const char *name, /* init frontend callback ops */ memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); - strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); + strscpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); return fe; diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index f8040f6def62..d869029ca87d 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2774,7 +2774,8 @@ static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_a dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); /* init 7090 tuner adapter */ - strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name)); + strscpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", + sizeof(st->dib7090_tuner_adap.name)); st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo; st->dib7090_tuner_adap.algo_data = NULL; st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 85c429cce23e..564669338dc6 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -4458,8 +4458,8 @@ static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_ad dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); /* init 8096p tuner adapter */ - strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", - sizeof(state->dib8096p_tuner_adap.name)); + strscpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", + sizeof(state->dib8096p_tuner_adap.name)); state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; state->dib8096p_tuner_adap.algo_data = NULL; state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 1875da07c150..e7838926e6bc 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -2521,7 +2521,8 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); st->tuner_adap.dev.parent = i2c_adap->dev.parent; - strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name)); + strscpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", + sizeof(st->tuner_adap.name)); st->tuner_adap.algo = &dib9000_tuner_algo; st->tuner_adap.algo_data = NULL; i2c_set_adapdata(&st->tuner_adap, st); @@ -2529,7 +2530,8 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c goto error; st->component_bus.dev.parent = i2c_adap->dev.parent; - strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name)); + strscpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", + sizeof(st->component_bus.name)); st->component_bus.algo = &dib9000_component_bus_algo; st->component_bus.algo_data = NULL; st->component_bus_speed = 340; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 0a5b15bee1d7..c597d6fc3046 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2263,61 +2263,41 @@ static int DRX_Start(struct drxd_state *state, s32 off) case DRX_CHANNEL_LOW: transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO; status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000); - if (status < 0) - break; break; case DRX_CHANNEL_HIGH: transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI; status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000); - if (status < 0) - break; break; - } switch (p->code_rate_HP) { case FEC_1_2: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000); - if (status < 0) - break; - } break; default: operationMode |= SC_RA_RAM_OP_AUTO_RATE__M; /* fall through */ case FEC_2_3: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000); - if (status < 0) - break; - } break; case FEC_3_4: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000); - if (status < 0) - break; - } break; case FEC_5_6: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000); - if (status < 0) - break; - } break; case FEC_7_8: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000); - if (status < 0) - break; - } break; } if (status < 0) diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 29836c1a40e9..da1b48a18515 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -839,7 +839,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); - strncpy(fe->ops.tuner_ops.info.name, desc->name, + strscpy(fe->ops.tuner_ops.info.name, desc->name, sizeof(fe->ops.tuner_ops.info.name)); fe->ops.tuner_ops.info.frequency_min_hz = desc->min; diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 123f2a33738b..b543e1c4c4f9 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -309,6 +309,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u16 u16tmp; u32 tuner_frequency_khz, target_mclk; s32 s32tmp; + static const struct reg_sequence reset_buf[] = { + {0x07, 0x80}, {0x07, 0x00} + }; dev_dbg(&client->dev, "delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", @@ -321,11 +324,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) } /* reset */ - ret = regmap_write(dev->regmap, 0x07, 0x80); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x07, 0x00); + ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2); if (ret) goto err; @@ -1470,7 +1469,7 @@ static int m88ds3103_probe(struct i2c_client *client, /* create dvb_frontend */ memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); if (dev->chip_id == M88RS6000_CHIP_ID) - strncpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", + strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", sizeof(dev->fe.ops.info.name)); if (!pdata->attach_in_use) dev->fe.ops.release = NULL; diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index feacd8da421d..c9bcd2e95417 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -275,18 +275,20 @@ static u32 si2165_get_fe_clk(struct si2165_state *state) static int si2165_wait_init_done(struct si2165_state *state) { - int ret = -EINVAL; + int ret; u8 val = 0; int i; for (i = 0; i < 3; ++i) { - si2165_readreg8(state, REG_INIT_DONE, &val); + ret = si2165_readreg8(state, REG_INIT_DONE, &val); + if (ret < 0) + return ret; if (val == 0x01) return 0; usleep_range(1000, 50000); } dev_err(&state->client->dev, "init_done was not set\n"); - return ret; + return -EINVAL; } static int si2165_upload_firmware_block(struct si2165_state *state, @@ -1299,7 +1301,6 @@ MODULE_DEVICE_TABLE(i2c, si2165_id_table); static struct i2c_driver si2165_driver = { .driver = { - .owner = THIS_MODULE, .name = "si2165", }, .probe = si2165_probe, diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index e5cd2cd414f4..0af9b335be12 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -180,6 +180,9 @@ static int ts2020_set_tuner_rf(struct dvb_frontend *fe) unsigned int utmp; ret = regmap_read(dev->regmap, 0x3d, &utmp); + if (ret) + return ret; + utmp &= 0x7f; if (utmp < 0x16) utmp = 0xa1; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6d32f8dcf83b..7793358ab8b3 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -8,7 +8,7 @@ config VIDEO_IR_I2C tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT depends on I2C && RC_CORE default y - ---help--- + help Most boards have an IR chip directly connected via GPIO. However, some video boards have the IR connected via I2C bus. @@ -29,7 +29,7 @@ comment "Audio decoders, processors and mixers" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, tea6320, tea6420, tda8425, ta8874z. @@ -41,7 +41,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for tda7432 audio decoder chip found on some bt8xx boards. To compile this driver as a module, choose M here: the @@ -50,7 +50,7 @@ config VIDEO_TDA7432 config VIDEO_TDA9840 tristate "Philips TDA9840 audio processor" depends on I2C - ---help--- + help Support for tda9840 audio decoder chip found on some Zoran boards. To compile this driver as a module, choose M here: the @@ -60,9 +60,10 @@ config VIDEO_TDA1997X tristate "NXP TDA1997x HDMI receiver" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on SND_SOC - select SND_PCM select HDMI - ---help--- + select SND_PCM + select V4L2_FWNODE + help V4L2 subdevice driver for the NXP TDA1997x HDMI receivers. To compile this driver as a module, choose M here: the @@ -71,7 +72,7 @@ config VIDEO_TDA1997X config VIDEO_TEA6415C tristate "Philips TEA6415C audio processor" depends on I2C - ---help--- + help Support for tea6415c audio decoder chip found on some bt8xx boards. To compile this driver as a module, choose M here: the @@ -80,7 +81,7 @@ config VIDEO_TEA6415C config VIDEO_TEA6420 tristate "Philips TEA6420 audio processor" depends on I2C - ---help--- + help Support for tea6420 audio decoder chip found on some bt8xx boards. To compile this driver as a module, choose M here: the @@ -89,7 +90,7 @@ config VIDEO_TEA6420 config VIDEO_MSP3400 tristate "Micronas MSP34xx audio decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Micronas MSP34xx series of audio decoders. To compile this driver as a module, choose M here: the @@ -98,7 +99,7 @@ config VIDEO_MSP3400 config VIDEO_CS3308 tristate "Cirrus Logic CS3308 audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Cirrus Logic CS3308 High Performance 8-Channel Analog Volume Control @@ -108,7 +109,7 @@ config VIDEO_CS3308 config VIDEO_CS5345 tristate "Cirrus Logic CS5345 audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Cirrus Logic CS5345 24-bit, 192 kHz stereo A/D converter. @@ -118,7 +119,7 @@ config VIDEO_CS5345 config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -128,7 +129,7 @@ config VIDEO_CS53L32A config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Texas Instruments TLV320AIC23B audio codec. To compile this driver as a module, choose M here: the @@ -137,7 +138,7 @@ config VIDEO_TLV320AIC23B config VIDEO_UDA1342 tristate "Philips UDA1342 audio codec" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips UDA1342 audio codec. To compile this driver as a module, choose M here: the @@ -146,7 +147,7 @@ config VIDEO_UDA1342 config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -156,7 +157,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -166,7 +167,7 @@ config VIDEO_WM8739 config VIDEO_VP27SMPX tristate "Panasonic VP27's internal MPX" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the internal MPX of the Panasonic VP27s tuner. To compile this driver as a module, choose M here: the @@ -200,7 +201,7 @@ comment "Video decoders" config VIDEO_ADV7180 tristate "Analog Devices ADV7180 decoder" depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - ---help--- + help Support for the Analog Devices ADV7180 video decoder. To compile this driver as a module, choose M here: the @@ -209,7 +210,7 @@ config VIDEO_ADV7180 config VIDEO_ADV7183 tristate "Analog Devices ADV7183 decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help V4l2 subdevice driver for the Analog Devices ADV7183 video decoder. @@ -221,7 +222,8 @@ config VIDEO_ADV748X depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on OF select REGMAP_I2C - ---help--- + select V4L2_FWNODE + help V4L2 subdevice driver for the Analog Devices ADV7481 and ADV7482 HDMI/Analog video decoders. @@ -234,7 +236,7 @@ config VIDEO_ADV7604 depends on GPIOLIB || COMPILE_TEST select HDMI select V4L2_FWNODE - ---help--- + help Support for the Analog Devices ADV7604 video decoder. This is a Analog Devices Component/Graphics Digitizer @@ -247,7 +249,7 @@ config VIDEO_ADV7604_CEC bool "Enable Analog Devices ADV7604 CEC support" depends on VIDEO_ADV7604 select CEC_CORE - ---help--- + help When selected the adv7604 will support the optional HDMI CEC feature. @@ -255,7 +257,7 @@ config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI - ---help--- + help Support for the Analog Devices ADV7842 video decoder. This is a Analog Devices Component/Graphics/SD Digitizer @@ -268,14 +270,14 @@ config VIDEO_ADV7842_CEC bool "Enable Analog Devices ADV7842 CEC support" depends on VIDEO_ADV7842 select CEC_CORE - ---help--- + help When selected the adv7842 will support the optional HDMI CEC feature. config VIDEO_BT819 tristate "BT819A VideoStream decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for BT819A video decoder. To compile this driver as a module, choose M here: the @@ -284,7 +286,7 @@ config VIDEO_BT819 config VIDEO_BT856 tristate "BT856 VideoStream decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for BT856 video decoder. To compile this driver as a module, choose M here: the @@ -293,7 +295,7 @@ config VIDEO_BT856 config VIDEO_BT866 tristate "BT866 VideoStream decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for BT866 video decoder. To compile this driver as a module, choose M here: the @@ -302,7 +304,7 @@ config VIDEO_BT866 config VIDEO_KS0127 tristate "KS0127 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for KS0127 video decoder. This chip is used on AverMedia AVS6EYES Zoran-based MJPEG @@ -314,53 +316,16 @@ config VIDEO_KS0127 config VIDEO_ML86V7667 tristate "OKI ML86V7667 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the OKI Semiconductor ML86V7667 video decoder. To compile this driver as a module, choose M here: the module will be called ml86v7667. -config VIDEO_AD5820 - tristate "AD5820 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - ---help--- - This is a driver for the AD5820 camera lens voice coil. - It is used for example in Nokia N900 (RX-51). - -config VIDEO_AK7375 - tristate "AK7375 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API - help - This is a driver for the AK7375 camera lens voice coil. - AK7375 is a 12 bit DAC with 120mA output current sink - capability. This is designed for linear control of - voice coil motors, controlled via I2C serial interface. - -config VIDEO_DW9714 - tristate "DW9714 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API - ---help--- - This is a driver for the DW9714 camera lens voice coil. - DW9714 is a 10 bit DAC with 120mA output current sink - capability. This is designed for linear control of - voice coil motors, controlled via I2C serial interface. - -config VIDEO_DW9807_VCM - tristate "DW9807 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API - ---help--- - This is a driver for the DW9807 camera lens voice coil. - DW9807 is a 10 bit DAC with 100mA output current sink - capability. This is designed for linear control of - voice coil motors, controlled via I2C serial interface. - config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7110 video decoders. To compile this driver as a module, choose M here: the @@ -369,7 +334,7 @@ config VIDEO_SAA7110 config VIDEO_SAA711X tristate "Philips SAA7111/3/4/5 video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7111/3/4/5 video decoders. To compile this driver as a module, choose M here: the @@ -380,7 +345,7 @@ config VIDEO_TC358743 depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI select V4L2_FWNODE - ---help--- + help Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge. To compile this driver as a module, choose M here: the @@ -390,7 +355,7 @@ config VIDEO_TC358743_CEC bool "Enable Toshiba TC358743 CEC support" depends on VIDEO_TC358743 select CEC_CORE - ---help--- + help When selected the tc358743 will support the optional HDMI CEC feature. @@ -398,7 +363,7 @@ config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" depends on VIDEO_V4L2 && I2C select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the TI TVP5146/47 decoder. It is currently working with the TI OMAP3 camera controller. @@ -410,7 +375,7 @@ config VIDEO_TVP5150 tristate "Texas Instruments TVP5150 video decoder" depends on VIDEO_V4L2 && I2C select V4L2_FWNODE - ---help--- + help Support for the Texas Instruments TVP5150 video decoder. To compile this driver as a module, choose M here: the @@ -420,7 +385,7 @@ config VIDEO_TVP7002 tristate "Texas Instruments TVP7002 video decoder" depends on VIDEO_V4L2 && I2C select V4L2_FWNODE - ---help--- + help Support for the Texas Instruments TVP7002 video decoder. To compile this driver as a module, choose M here: the @@ -429,7 +394,7 @@ config VIDEO_TVP7002 config VIDEO_TW2804 tristate "Techwell TW2804 multiple video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Techwell tw2804 multiple video decoder. To compile this driver as a module, choose M here: the @@ -438,7 +403,7 @@ config VIDEO_TW2804 config VIDEO_TW9903 tristate "Techwell TW9903 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Techwell tw9903 multi-standard video decoder with high quality down scaler. @@ -448,7 +413,7 @@ config VIDEO_TW9903 config VIDEO_TW9906 tristate "Techwell TW9906 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Techwell tw9906 enhanced multi-standard comb filter video decoder with YCbCr input support. @@ -458,7 +423,7 @@ config VIDEO_TW9906 config VIDEO_TW9910 tristate "Techwell TW9910 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for Techwell TW9910 NTSC/PAL/SECAM video decoder. To compile this driver as a module, choose M here: the @@ -467,7 +432,7 @@ config VIDEO_TW9910 config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for VPX322x video decoders. To compile this driver as a module, choose M here: the @@ -478,7 +443,7 @@ comment "Video and audio decoders" config VIDEO_SAA717X tristate "Philips SAA7171/3/4 audio/video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7171/3/4 audio/video decoders. To compile this driver as a module, choose M here: the @@ -491,7 +456,7 @@ comment "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7127/9 digital video encoders. To compile this driver as a module, choose M here: the @@ -500,7 +465,7 @@ config VIDEO_SAA7127 config VIDEO_SAA7185 tristate "Philips SAA7185 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7185 video encoder. To compile this driver as a module, choose M here: the @@ -509,7 +474,7 @@ config VIDEO_SAA7185 config VIDEO_ADV7170 tristate "Analog Devices ADV7170 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Analog Devices ADV7170 video encoder driver To compile this driver as a module, choose M here: the @@ -518,7 +483,7 @@ config VIDEO_ADV7170 config VIDEO_ADV7175 tristate "Analog Devices ADV7175 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Analog Devices ADV7175 video encoder driver To compile this driver as a module, choose M here: the @@ -546,7 +511,7 @@ config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI - ---help--- + help Support for the Analog Devices ADV7511 video encoder. This is a Analog Devices HDMI transmitter. @@ -558,14 +523,14 @@ config VIDEO_ADV7511_CEC bool "Enable Analog Devices ADV7511 CEC support" depends on VIDEO_ADV7511 select CEC_CORE - ---help--- + help When selected the adv7511 will support the optional HDMI CEC feature. config VIDEO_AD9389B tristate "Analog Devices AD9389B encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - ---help--- + help Support for the Analog Devices AD9389B video encoder. This is a Analog Devices HDMI transmitter. @@ -582,7 +547,7 @@ config VIDEO_AK881X config VIDEO_THS8200 tristate "Texas Instruments THS8200 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Texas Instruments THS8200 video encoder. To compile this driver as a module, choose M here: the @@ -612,7 +577,7 @@ config VIDEO_IMX258 tristate "Sony IMX258 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Sony IMX258 camera. @@ -624,7 +589,7 @@ config VIDEO_IMX274 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C - ---help--- + help This is a V4L2 sensor driver for the Sony IMX274 CMOS image sensor. @@ -666,7 +631,7 @@ config VIDEO_OV2659 depends on VIDEO_V4L2 && I2C depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV2659 camera. @@ -678,7 +643,7 @@ config VIDEO_OV2680 depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV2680 camera. @@ -690,7 +655,7 @@ config VIDEO_OV2685 depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV2685 camera. @@ -703,7 +668,7 @@ config VIDEO_OV5640 depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the Omnivision OV5640 camera sensor with a MIPI CSI-2 interface. @@ -713,7 +678,7 @@ config VIDEO_OV5645 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5645 camera. @@ -725,7 +690,7 @@ config VIDEO_OV5647 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5647 camera. @@ -736,7 +701,7 @@ config VIDEO_OV6650 tristate "OmniVision OV6650 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV6650 camera. @@ -749,7 +714,7 @@ config VIDEO_OV5670 depends on MEDIA_CAMERA_SUPPORT depends on MEDIA_CONTROLLER select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5670 camera. @@ -760,7 +725,7 @@ config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5695 camera. @@ -784,7 +749,7 @@ config VIDEO_OV772X depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT select REGMAP_SCCB - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV772x camera. @@ -795,7 +760,7 @@ config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV7640 camera. @@ -807,7 +772,7 @@ config VIDEO_OV7670 depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV7670 VGA camera. It currently only works with the M88ALP01 controller. @@ -816,7 +781,7 @@ config VIDEO_OV7740 tristate "OmniVision OV7740 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV7740 VGA camera sensor. @@ -843,7 +808,7 @@ config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select REGMAP_SCCB - ---help--- + help This is a V4L2 sensor driver for the Omnivision OV9650 and OV9652 camera sensors. @@ -852,7 +817,7 @@ config VIDEO_OV13858 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV13858 camera. @@ -860,7 +825,7 @@ config VIDEO_VS6624 tristate "ST VS6624 sensor support" depends on VIDEO_V4L2 && I2C depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the ST VS6624 camera. @@ -880,7 +845,7 @@ config VIDEO_MT9M032 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL - ---help--- + help This driver supports MT9M032 camera sensors from Aptina, monochrome models only. @@ -897,7 +862,7 @@ config VIDEO_MT9P031 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL - ---help--- + help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt9p031 5 Mpixel camera. @@ -905,7 +870,7 @@ config VIDEO_MT9T001 tristate "Aptina MT9T001 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt0t001 3 Mpixel camera. @@ -913,7 +878,7 @@ config VIDEO_MT9T112 tristate "Aptina MT9T111/MT9T112 support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Aptina (Micron) MT9T111 and MT9T112 3 Mpixel camera. @@ -924,7 +889,7 @@ config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Micron mt0v011 1.3 Mpixel camera. It currently only works with the em28xx driver. @@ -935,7 +900,7 @@ config VIDEO_MT9V032 depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the Micron MT9V032 752x480 CMOS sensor. @@ -954,14 +919,14 @@ config VIDEO_SR030PC30 tristate "Siliconfile SR030PC30 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This driver supports SR030PC30 VGA camera from Siliconfile config VIDEO_NOON010PC30 tristate "Siliconfile NOON010PC30 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This driver supports NOON010PC30 CIF camera from Siliconfile source "drivers/media/i2c/m5mols/Kconfig" @@ -981,7 +946,7 @@ config VIDEO_S5K6AA tristate "Samsung S5K6AAFX sensor support" depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- + help This is a V4L2 sensor driver for Samsung S5K6AA(FX) 1.3M camera sensor with an embedded SoC image signal processor. @@ -989,7 +954,7 @@ config VIDEO_S5K6A3 tristate "Samsung S5K6A3 sensor support" depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- + help This is a V4L2 sensor driver for Samsung S5K6A3 raw camera sensor. @@ -997,7 +962,7 @@ config VIDEO_S5K4ECGX tristate "Samsung S5K4ECGX sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select CRC32 - ---help--- + help This is a V4L2 sensor driver for Samsung S5K4ECGX 5M camera sensor with an embedded SoC image signal processor. @@ -1005,7 +970,7 @@ config VIDEO_S5K5BAF tristate "Samsung S5K5BAF sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - ---help--- + help This is a V4L2 sensor driver for Samsung S5K5BAF 2M camera sensor with an embedded SoC image signal processor. @@ -1016,17 +981,56 @@ config VIDEO_S5C73M3 tristate "Samsung S5C73M3 sensor support" depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - ---help--- + help This is a V4L2 sensor driver for Samsung S5C73M3 8 Mpixel camera. +comment "Lens drivers" + +config VIDEO_AD5820 + tristate "AD5820 lens voice coil support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + help + This is a driver for the AD5820 camera lens voice coil. + It is used for example in Nokia N900 (RX-51). + +config VIDEO_AK7375 + tristate "AK7375 lens voice coil support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on VIDEO_V4L2_SUBDEV_API + help + This is a driver for the AK7375 camera lens voice coil. + AK7375 is a 12 bit DAC with 120mA output current sink + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + +config VIDEO_DW9714 + tristate "DW9714 lens voice coil support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on VIDEO_V4L2_SUBDEV_API + help + This is a driver for the DW9714 camera lens voice coil. + DW9714 is a 10 bit DAC with 120mA output current sink + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + +config VIDEO_DW9807_VCM + tristate "DW9807 lens voice coil support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on VIDEO_V4L2_SUBDEV_API + help + This is a driver for the DW9807 camera lens voice coil. + DW9807 is a 10 bit DAC with 100mA output current sink + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + comment "Flash devices" config VIDEO_ADP1653 tristate "ADP1653 flash support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. @@ -1035,7 +1039,7 @@ config VIDEO_LM3560 depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C - ---help--- + help This is a driver for the lm3560 dual flash controllers. It controls flash, torch LEDs. @@ -1044,7 +1048,7 @@ config VIDEO_LM3646 depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C - ---help--- + help This is a driver for the lm3646 dual flash controllers. It controls flash, torch LEDs. @@ -1053,7 +1057,7 @@ comment "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the NEC Electronics uPD64031A Ghost Reduction video chip. It is most often found in NTSC TV cards made for Japan and is used to reduce the 'ghosting' effect that can @@ -1065,7 +1069,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the NEC Electronics uPD64083 3-Dimensional Y/C separation video chip. It is used to improve the quality of the colors of a composite signal. @@ -1079,7 +1083,7 @@ config VIDEO_SAA6752HS tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" depends on VIDEO_V4L2 && I2C select CRC32 - ---help--- + help Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 audio encoder with multiplexer. @@ -1091,7 +1095,7 @@ comment "SDR tuner chips" config SDR_MAX2175 tristate "Maxim 2175 RF to Bits tuner" depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C - ---help--- + help Support for Maxim 2175 tuner. It is an advanced analog/digital radio receiver with RF-to-Bits front-end designed for SDR solutions. @@ -1112,7 +1116,7 @@ config VIDEO_THS7303 config VIDEO_M52790 tristate "Mitsubishi M52790 A/V switch" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Mitsubishi M52790 A/V switch. To compile this driver as a module, choose M here: the @@ -1123,7 +1127,7 @@ config VIDEO_I2C depends on VIDEO_V4L2 && I2C select VIDEOBUF2_VMALLOC imply HWMON - ---help--- + help Enable the I2C transport video support which supports the following: * Panasonic AMG88xx Grid-Eye Sensors @@ -1132,6 +1136,19 @@ config VIDEO_I2C To compile this driver as a module, choose M here: the module will be called video-i2c +config VIDEO_ST_MIPID02 + tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE + help + Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. + It is used to allow usage of CSI-2 sensor with PARALLEL port + controller. + + To compile this driver as a module, choose M here: the + module will be called st-mipid02. + endmenu endif diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index a64fca82e0c4..d8ad9dad495d 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -113,5 +113,6 @@ obj-$(CONFIG_VIDEO_IMX258) += imx258.o obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o +obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/cx25840/Kconfig b/drivers/media/i2c/cx25840/Kconfig index 451133ad41ff..f4b31d7cb440 100644 --- a/drivers/media/i2c/cx25840/Kconfig +++ b/drivers/media/i2c/cx25840/Kconfig @@ -1,7 +1,7 @@ config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Conexant CX2584x audio/video decoders. To compile this driver as a module, choose M here: the diff --git a/drivers/media/i2c/et8ek8/Kconfig b/drivers/media/i2c/et8ek8/Kconfig index 9fe409e95666..ab23b41bf353 100644 --- a/drivers/media/i2c/et8ek8/Kconfig +++ b/drivers/media/i2c/et8ek8/Kconfig @@ -2,6 +2,6 @@ config VIDEO_ET8EK8 tristate "ET8EK8 camera sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - ---help--- + help This is a driver for the Toshiba ET8EK8 5 MP camera sensor. It is used for example in Nokia N900 (RX-51). diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 9857e151db46..83e9961b0505 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -588,12 +588,10 @@ static int imx214_set_format(struct v4l2_subdev *sd, __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which); - if (format) - mode = v4l2_find_nearest_size(imx214_modes, - ARRAY_SIZE(imx214_modes), width, height, - format->format.width, format->format.height); - else - mode = &imx214_modes[0]; + mode = v4l2_find_nearest_size(imx214_modes, + ARRAY_SIZE(imx214_modes), width, height, + format->format.width, + format->format.height); __crop->width = mode->width; __crop->height = mode->height; diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig index dc8c2505907e..be0bb3f1bc22 100644 --- a/drivers/media/i2c/m5mols/Kconfig +++ b/drivers/media/i2c/m5mols/Kconfig @@ -2,5 +2,5 @@ config VIDEO_M5MOLS tristate "Fujitsu M-5MOLS 8MP sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This driver supports Fujitsu M-5MOLS camera sensor with ISP diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 799acce803fe..5ed2413eac8a 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1117,8 +1117,10 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, if (ov2659_formats[index].code == mf->code) break; - if (index < 0) - return -EINVAL; + if (index < 0) { + index = 0; + mf->code = ov2659_formats[index].code; + } mf->colorspace = V4L2_COLORSPACE_SRGB; mf->field = V4L2_FIELD_NONE; @@ -1130,7 +1132,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; #else - return -ENOTTY; + ret = -ENOTTY; #endif } else { s64 val; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index c33fd584cb44..1b972e591b48 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -804,15 +804,25 @@ static int ov6650_prog_dflt(struct i2c_client *client) return ret; } -static int ov6650_video_probe(struct i2c_client *client) +static int ov6650_video_probe(struct v4l2_subdev *sd) { + struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); u8 pidh, pidl, midh, midl; int ret; - ret = ov6650_s_power(&priv->subdev, 1); - if (ret < 0) + priv->clk = v4l2_clk_get(&client->dev, NULL); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + dev_err(&client->dev, "v4l2_clk request err: %d\n", ret); return ret; + } + + ret = ov6650_s_power(sd, 1); + if (ret < 0) + goto eclkput; + + msleep(20); /* * check and show product ID and manufacturer ID @@ -846,7 +856,12 @@ static int ov6650_video_probe(struct i2c_client *client) ret = v4l2_ctrl_handler_setup(&priv->hdl); done: - ov6650_s_power(&priv->subdev, 0); + ov6650_s_power(sd, 0); + if (!ret) + return 0; +eclkput: + v4l2_clk_put(priv->clk); + return ret; } @@ -929,6 +944,10 @@ static const struct v4l2_subdev_ops ov6650_subdev_ops = { .pad = &ov6650_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov6650_internal_ops = { + .registered = ov6650_video_probe, +}; + /* * i2c_driver function */ @@ -989,18 +1008,12 @@ static int ov6650_probe(struct i2c_client *client, priv->code = MEDIA_BUS_FMT_YUYV8_2X8; priv->colorspace = V4L2_COLORSPACE_JPEG; - priv->clk = v4l2_clk_get(&client->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - goto eclkget; - } + priv->subdev.internal_ops = &ov6650_internal_ops; + priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ret = ov6650_video_probe(client); - if (ret) { - v4l2_clk_put(priv->clk); -eclkget: + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) v4l2_ctrl_handler_free(&priv->hdl); - } return ret; } @@ -1010,7 +1023,7 @@ static int ov6650_remove(struct i2c_client *client) struct ov6650 *priv = to_ov6650(client); v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); + v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; } diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index a7d26b294eb5..44c3eed8a858 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -864,7 +864,15 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd, /* Recalculate frame rate */ ov7675_get_framerate(sd, tpf); - return ov7675_apply_framerate(sd); + /* + * If the device is not powered up by the host driver do + * not apply any changes to H/W at this time. Instead + * the framerate will be restored right after power-up. + */ + if (info->on) + return ov7675_apply_framerate(sd); + + return 0; } static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd, @@ -895,7 +903,16 @@ static int ov7670_set_framerate_legacy(struct v4l2_subdev *sd, info->clkrc = (info->clkrc & 0x80) | div; tpf->numerator = 1; tpf->denominator = info->clock_speed / div; - return ov7670_write(sd, REG_CLKRC, info->clkrc); + + /* + * If the device is not powered up by the host driver do + * not apply any changes to H/W at this time. Instead + * the framerate will be restored right after power-up. + */ + if (info->on) + return ov7670_write(sd, REG_CLKRC, info->clkrc); + + return 0; } /* @@ -1105,9 +1122,13 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, if (ret) return ret; - ret = ov7670_apply_fmt(sd); - if (ret) - return ret; + /* + * If the device is not powered up by the host driver do + * not apply any changes to H/W at this time. Instead + * the frame format will be restored right after power-up. + */ + if (info->on) + return ov7670_apply_fmt(sd); return 0; } @@ -1664,6 +1685,7 @@ static int ov7670_s_power(struct v4l2_subdev *sd, int on) if (on) { ov7670_power_on (sd); + ov7670_init(sd, 0); ov7670_apply_fmt(sd); ov7675_apply_framerate(sd); v4l2_ctrl_handler_setup(&info->hdl); diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index dfece91ce96b..54e80a60aa57 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -448,6 +448,27 @@ static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) return 0; } +static int ov7740_get_exp(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) +{ + struct regmap *regmap = ov7740->regmap; + unsigned int value0, value1; + int ret; + + if (ctrl->val == V4L2_EXPOSURE_MANUAL) + return 0; + + ret = regmap_read(regmap, REG_AEC, &value0); + if (ret) + return ret; + ret = regmap_read(regmap, REG_HAEC, &value1); + if (ret) + return ret; + + ov7740->exposure->val = (value1 << 8) | (value0 & 0xff); + + return 0; +} + static int ov7740_set_exp(struct regmap *regmap, int value) { int ret; @@ -494,6 +515,9 @@ static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_AUTOGAIN: ret = ov7740_get_gain(ov7740, ctrl); break; + case V4L2_CID_EXPOSURE_AUTO: + ret = ov7740_get_exp(ov7740, ctrl); + break; default: ret = -EINVAL; break; @@ -991,8 +1015,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740) ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, V4L2_CID_EXPOSURE, 0, 65535, 1, 500); - if (ov7740->exposure) - ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr, &ov7740_ctrl_ops, @@ -1003,7 +1025,7 @@ static int ov7740_init_controls(struct ov7740 *ov7740) v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false); v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, - V4L2_EXPOSURE_MANUAL, false); + V4L2_EXPOSURE_MANUAL, true); v4l2_ctrl_cluster(2, &ov7740->hflip); if (ctrl_hdlr->error) { diff --git a/drivers/media/i2c/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig index f59718d8e51e..26b54f2aa95b 100644 --- a/drivers/media/i2c/smiapp/Kconfig +++ b/drivers/media/i2c/smiapp/Kconfig @@ -4,5 +4,5 @@ config VIDEO_SMIAPP depends on MEDIA_CAMERA_SUPPORT select VIDEO_SMIAPP_PLL select V4L2_FWNODE - ---help--- + help This is a generic driver for SMIA++/SMIA camera modules. diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c new file mode 100644 index 000000000000..9369f38dbf3d --- /dev/null +++ b/drivers/media/i2c/st-mipid02.c @@ -0,0 +1,1033 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for ST MIPID02 CSI-2 to PARALLEL bridge + * + * Copyright (C) STMicroelectronics SA 2019 + * Authors: Mickael Guene <mickael.guene@st.com> + * for STMicroelectronics. + * + * + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#define MIPID02_CLK_LANE_WR_REG1 0x01 +#define MIPID02_CLK_LANE_REG1 0x02 +#define MIPID02_CLK_LANE_REG3 0x04 +#define MIPID02_DATA_LANE0_REG1 0x05 +#define MIPID02_DATA_LANE0_REG2 0x06 +#define MIPID02_DATA_LANE1_REG1 0x09 +#define MIPID02_DATA_LANE1_REG2 0x0a +#define MIPID02_MODE_REG1 0x14 +#define MIPID02_MODE_REG2 0x15 +#define MIPID02_DATA_ID_RREG 0x17 +#define MIPID02_DATA_SELECTION_CTRL 0x19 +#define MIPID02_PIX_WIDTH_CTRL 0x1e +#define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f + +/* Bits definition for MIPID02_CLK_LANE_REG1 */ +#define CLK_ENABLE BIT(0) +/* Bits definition for MIPID02_CLK_LANE_REG3 */ +#define CLK_MIPI_CSI BIT(1) +/* Bits definition for MIPID02_DATA_LANE0_REG1 */ +#define DATA_ENABLE BIT(0) +/* Bits definition for MIPID02_DATA_LANEx_REG2 */ +#define DATA_MIPI_CSI BIT(0) +/* Bits definition for MIPID02_MODE_REG1 */ +#define MODE_DATA_SWAP BIT(2) +#define MODE_NO_BYPASS BIT(6) +/* Bits definition for MIPID02_MODE_REG2 */ +#define MODE_HSYNC_ACTIVE_HIGH BIT(1) +#define MODE_VSYNC_ACTIVE_HIGH BIT(2) +/* Bits definition for MIPID02_DATA_SELECTION_CTRL */ +#define SELECTION_MANUAL_DATA BIT(2) +#define SELECTION_MANUAL_WIDTH BIT(3) + +static const u32 mipid02_supported_fmt_codes[] = { + MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24 +}; + +/* regulator supplies */ +static const char * const mipid02_supply_name[] = { + "VDDE", /* 1.8V digital I/O supply */ + "VDDIN", /* 1V8 voltage regulator supply */ +}; + +#define MIPID02_NUM_SUPPLIES ARRAY_SIZE(mipid02_supply_name) + +#define MIPID02_SINK_0 0 +#define MIPID02_SINK_1 1 +#define MIPID02_SOURCE 2 +#define MIPID02_PAD_NB 3 + +struct mipid02_dev { + struct i2c_client *i2c_client; + struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; + struct v4l2_subdev sd; + struct media_pad pad[MIPID02_PAD_NB]; + struct clk *xclk; + struct gpio_desc *reset_gpio; + /* endpoints info */ + struct v4l2_fwnode_endpoint rx; + u64 link_frequency; + struct v4l2_fwnode_endpoint tx; + /* remote source */ + struct v4l2_async_subdev asd; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *s_subdev; + /* registers */ + struct { + u8 clk_lane_reg1; + u8 data_lane0_reg1; + u8 data_lane1_reg1; + u8 mode_reg1; + u8 mode_reg2; + u8 data_id_rreg; + u8 pix_width_ctrl; + u8 pix_width_ctrl_emb; + } r; + /* lock to protect all members below */ + struct mutex lock; + bool streaming; + struct v4l2_mbus_framefmt fmt; +}; + +static int bpp_from_code(__u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return 8; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return 10; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return 12; + case MEDIA_BUS_FMT_UYVY8_1X16: + return 16; + case MEDIA_BUS_FMT_BGR888_1X24: + return 24; + default: + return 0; + } +} + +static u8 data_type_from_code(__u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return 0x2a; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return 0x2b; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return 0x2c; + case MEDIA_BUS_FMT_UYVY8_1X16: + return 0x1e; + case MEDIA_BUS_FMT_BGR888_1X24: + return 0x24; + default: + return 0; + } +} + +static void init_format(struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); + fmt->width = 640; + fmt->height = 480; +} + +static __u32 get_fmt_code(__u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) { + if (code == mipid02_supported_fmt_codes[i]) + return code; + } + + return mipid02_supported_fmt_codes[0]; +} + +static __u32 serial_to_parallel_code(__u32 serial) +{ + if (serial == MEDIA_BUS_FMT_UYVY8_1X16) + return MEDIA_BUS_FMT_UYVY8_2X8; + if (serial == MEDIA_BUS_FMT_BGR888_1X24) + return MEDIA_BUS_FMT_BGR888_3X8; + + return serial; +} + +static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mipid02_dev, sd); +} + +static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val) +{ + struct i2c_client *client = bridge->i2c_client; + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].buf = val; + msg[1].len = 1; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) { + dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", + __func__, client->addr, reg, ret); + return ret; + } + + return 0; +} + +static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val) +{ + struct i2c_client *client = bridge->i2c_client; + struct i2c_msg msg; + u8 buf[3]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + buf[2] = val; + + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buf; + msg.len = sizeof(buf); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", + __func__, reg, ret); + return ret; + } + + return 0; +} + +static int mipid02_get_regulators(struct mipid02_dev *bridge) +{ + unsigned int i; + + for (i = 0; i < MIPID02_NUM_SUPPLIES; i++) + bridge->supplies[i].supply = mipid02_supply_name[i]; + + return devm_regulator_bulk_get(&bridge->i2c_client->dev, + MIPID02_NUM_SUPPLIES, + bridge->supplies); +} + +static void mipid02_apply_reset(struct mipid02_dev *bridge) +{ + gpiod_set_value_cansleep(bridge->reset_gpio, 0); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(bridge->reset_gpio, 1); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(bridge->reset_gpio, 0); + usleep_range(5000, 10000); +} + +static int mipid02_set_power_on(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + int ret; + + ret = clk_prepare_enable(bridge->xclk); + if (ret) { + dev_err(&client->dev, "%s: failed to enable clock\n", __func__); + return ret; + } + + ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES, + bridge->supplies); + if (ret) { + dev_err(&client->dev, "%s: failed to enable regulators\n", + __func__); + goto xclk_off; + } + + if (bridge->reset_gpio) { + dev_dbg(&client->dev, "apply reset"); + mipid02_apply_reset(bridge); + } else { + dev_dbg(&client->dev, "don't apply reset"); + usleep_range(5000, 10000); + } + + return 0; + +xclk_off: + clk_disable_unprepare(bridge->xclk); + return ret; +} + +static void mipid02_set_power_off(struct mipid02_dev *bridge) +{ + regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); + clk_disable_unprepare(bridge->xclk); +} + +static int mipid02_detect(struct mipid02_dev *bridge) +{ + u8 reg; + + /* + * There is no version registers. Just try to read register + * MIPID02_CLK_LANE_WR_REG1. + */ + return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); +} + +static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, + struct v4l2_subdev *subdev) +{ + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + struct v4l2_ctrl *ctrl; + u32 pixel_clock; + u32 bpp = bpp_from_code(bridge->fmt.code); + + ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) + return 0; + pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); + + return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes); +} + +/* + * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency + * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel + * and number of lanes. + */ +static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + struct v4l2_subdev *subdev = bridge->s_subdev; + u32 link_freq; + + link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, subdev); + if (!link_freq) { + dev_err(&client->dev, "Failed to detect link frequency"); + return -EINVAL; + } + + dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); + bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2; + + return 0; +} + +static int mipid02_configure_clk_lane(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + bool *polarities = ep->bus.mipi_csi2.lane_polarities; + + /* midid02 doesn't support clock lane remapping */ + if (ep->bus.mipi_csi2.clock_lane != 0) { + dev_err(&client->dev, "clk lane must be map to lane 0\n"); + return -EINVAL; + } + bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE; + + return 0; +} + +static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb, + bool are_lanes_swap, bool *polarities) +{ + bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1]; + + if (nb == 1 && are_lanes_swap) + return 0; + + /* + * data lane 0 as pin swap polarity reversed compared to clock and + * data lane 1 + */ + if (!are_pin_swap) + bridge->r.data_lane0_reg1 = 1 << 1; + bridge->r.data_lane0_reg1 |= DATA_ENABLE; + + return 0; +} + +static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, + bool are_lanes_swap, bool *polarities) +{ + bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2]; + + if (nb == 1 && !are_lanes_swap) + return 0; + + if (are_pin_swap) + bridge->r.data_lane1_reg1 = 1 << 1; + bridge->r.data_lane1_reg1 |= DATA_ENABLE; + + return 0; +} + +static int mipid02_configure_from_rx(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; + bool *polarities = ep->bus.mipi_csi2.lane_polarities; + int nb = ep->bus.mipi_csi2.num_data_lanes; + int ret; + + ret = mipid02_configure_clk_lane(bridge); + if (ret) + return ret; + + ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap, + polarities); + if (ret) + return ret; + + ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap, + polarities); + if (ret) + return ret; + + bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; + bridge->r.mode_reg1 |= (nb - 1) << 1; + + return mipid02_configure_from_rx_speed(bridge); +} + +static int mipid02_configure_from_tx(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint *ep = &bridge->tx; + + bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; + bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; + if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; + if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; + + return 0; +} + +static int mipid02_configure_from_code(struct mipid02_dev *bridge) +{ + u8 data_type; + + bridge->r.data_id_rreg = 0; + data_type = data_type_from_code(bridge->fmt.code); + if (!data_type) + return -EINVAL; + bridge->r.data_id_rreg = data_type; + + return 0; +} + +static int mipid02_stream_disable(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + int ret; + + /* Disable all lanes */ + ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0); + if (ret) + goto error; +error: + if (ret) + dev_err(&client->dev, "failed to stream off %d", ret); + + return ret; +} + +static int mipid02_stream_enable(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + int ret = -EINVAL; + + if (!bridge->s_subdev) + goto error; + + memset(&bridge->r, 0, sizeof(bridge->r)); + /* build registers content */ + ret = mipid02_configure_from_rx(bridge); + if (ret) + goto error; + ret = mipid02_configure_from_tx(bridge); + if (ret) + goto error; + ret = mipid02_configure_from_code(bridge); + if (ret) + goto error; + + /* write mipi registers */ + ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, + bridge->r.clk_lane_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, + bridge->r.data_lane0_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2, + DATA_MIPI_CSI); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, + bridge->r.data_lane1_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2, + DATA_MIPI_CSI); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1, + MODE_NO_BYPASS | bridge->r.mode_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2, + bridge->r.mode_reg2); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG, + bridge->r.data_id_rreg); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, + SELECTION_MANUAL_DATA | SELECTION_MANUAL_WIDTH); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, + bridge->r.pix_width_ctrl); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB, + bridge->r.pix_width_ctrl_emb); + if (ret) + goto error; + + return 0; + +error: + dev_err(&client->dev, "failed to stream on %d", ret); + mipid02_stream_disable(bridge); + + return ret; +} + +static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct i2c_client *client = bridge->i2c_client; + int ret = 0; + + dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__, + enable, bridge->streaming); + mutex_lock(&bridge->lock); + + if (bridge->streaming == enable) + goto out; + + ret = enable ? mipid02_stream_enable(bridge) : + mipid02_stream_disable(bridge); + if (!ret) + bridge->streaming = enable; + +out: + dev_dbg(&client->dev, "%s current now = %d / %d", __func__, + bridge->streaming, ret); + mutex_unlock(&bridge->lock); + + return ret; +} + +static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + int ret = 0; + + switch (code->pad) { + case MIPID02_SINK_0: + if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes)) + ret = -EINVAL; + else + code->code = mipid02_supported_fmt_codes[code->index]; + break; + case MIPID02_SOURCE: + if (code->index == 0) + code->code = serial_to_parallel_code(bridge->fmt.code); + else + ret = -EINVAL; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int mipid02_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mbus_fmt = &format->format; + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct i2c_client *client = bridge->i2c_client; + struct v4l2_mbus_framefmt *fmt; + + dev_dbg(&client->dev, "%s probe %d", __func__, format->pad); + + if (format->pad >= MIPID02_PAD_NB) + return -EINVAL; + /* second CSI-2 pad not yet supported */ + if (format->pad == MIPID02_SINK_1) + return -EINVAL; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + fmt = v4l2_subdev_get_try_format(&bridge->sd, cfg, format->pad); + else + fmt = &bridge->fmt; + + mutex_lock(&bridge->lock); + + *mbus_fmt = *fmt; + /* code may need to be converted for source */ + if (format->pad == MIPID02_SOURCE) + mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code); + + mutex_unlock(&bridge->lock); + + return 0; +} + +static void mipid02_set_fmt_source(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + + /* source pad mirror active sink pad */ + format->format = bridge->fmt; + /* but code may need to be converted */ + format->format.code = serial_to_parallel_code(format->format.code); + + /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */ + if (format->which != V4L2_SUBDEV_FORMAT_TRY) + return; + + *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format; +} + +static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct v4l2_mbus_framefmt *fmt; + + format->format.code = get_fmt_code(format->format.code); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + else + fmt = &bridge->fmt; + + *fmt = format->format; +} + +static int mipid02_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct i2c_client *client = bridge->i2c_client; + int ret = 0; + + dev_dbg(&client->dev, "%s for %d", __func__, format->pad); + + if (format->pad >= MIPID02_PAD_NB) + return -EINVAL; + /* second CSI-2 pad not yet supported */ + if (format->pad == MIPID02_SINK_1) + return -EINVAL; + + mutex_lock(&bridge->lock); + + if (bridge->streaming) { + ret = -EBUSY; + goto error; + } + + if (format->pad == MIPID02_SOURCE) + mipid02_set_fmt_source(sd, cfg, format); + else + mipid02_set_fmt_sink(sd, cfg, format); + +error: + mutex_unlock(&bridge->lock); + + return ret; +} + +static const struct v4l2_subdev_video_ops mipid02_video_ops = { + .s_stream = mipid02_s_stream, +}; + +static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { + .enum_mbus_code = mipid02_enum_mbus_code, + .get_fmt = mipid02_get_fmt, + .set_fmt = mipid02_set_fmt, +}; + +static const struct v4l2_subdev_ops mipid02_subdev_ops = { + .video = &mipid02_video_ops, + .pad = &mipid02_pad_ops, +}; + +static const struct media_entity_operations mipid02_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int mipid02_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *s_subdev, + struct v4l2_async_subdev *asd) +{ + struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); + struct i2c_client *client = bridge->i2c_client; + int source_pad; + int ret; + + dev_dbg(&client->dev, "sensor_async_bound call %p", s_subdev); + + source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, + s_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (source_pad < 0) { + dev_err(&client->dev, "Couldn't find output pad for subdev %s\n", + s_subdev->name); + return source_pad; + } + + ret = media_create_pad_link(&s_subdev->entity, source_pad, + &bridge->sd.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(&client->dev, "Couldn't create media link %d", ret); + return ret; + } + + bridge->s_subdev = s_subdev; + + return 0; +} + +static void mipid02_async_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *s_subdev, + struct v4l2_async_subdev *asd) +{ + struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); + + bridge->s_subdev = NULL; +} + +static const struct v4l2_async_notifier_operations mipid02_notifier_ops = { + .bound = mipid02_async_bound, + .unbind = mipid02_async_unbind, +}; + +static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct i2c_client *client = bridge->i2c_client; + struct device_node *ep_node; + int ret; + + /* parse rx (endpoint 0) */ + ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, + 0, 0); + if (!ep_node) { + dev_err(&client->dev, "unable to find port0 ep"); + ret = -EINVAL; + goto error; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); + if (ret) { + dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n", + ret); + goto error_of_node_put; + } + + /* do some sanity checks */ + if (ep.bus.mipi_csi2.num_data_lanes > 2) { + dev_err(&client->dev, "max supported data lanes is 2 / got %d", + ep.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto error_of_node_put; + } + + /* register it for later use */ + bridge->rx = ep; + + /* register async notifier so we get noticed when sensor is connected */ + bridge->asd.match.fwnode = + fwnode_graph_get_remote_port_parent(of_fwnode_handle(ep_node)); + bridge->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + of_node_put(ep_node); + + v4l2_async_notifier_init(&bridge->notifier); + ret = v4l2_async_notifier_add_subdev(&bridge->notifier, &bridge->asd); + if (ret) { + dev_err(&client->dev, "fail to register asd to notifier %d", + ret); + fwnode_handle_put(bridge->asd.match.fwnode); + return ret; + } + bridge->notifier.ops = &mipid02_notifier_ops; + + ret = v4l2_async_subdev_notifier_register(&bridge->sd, + &bridge->notifier); + if (ret) + v4l2_async_notifier_cleanup(&bridge->notifier); + + return ret; + +error_of_node_put: + of_node_put(ep_node); +error: + + return ret; +} + +static int mipid02_parse_tx_ep(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL }; + struct i2c_client *client = bridge->i2c_client; + struct device_node *ep_node; + int ret; + + /* parse tx (endpoint 2) */ + ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, + 2, 0); + if (!ep_node) { + dev_err(&client->dev, "unable to find port1 ep"); + ret = -EINVAL; + goto error; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); + if (ret) { + dev_err(&client->dev, "Could not parse v4l2 endpoint\n"); + goto error_of_node_put; + } + + of_node_put(ep_node); + bridge->tx = ep; + + return 0; + +error_of_node_put: + of_node_put(ep_node); +error: + + return -EINVAL; +} + +static int mipid02_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mipid02_dev *bridge; + u32 clk_freq; + int ret; + + bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); + if (!bridge) + return -ENOMEM; + + init_format(&bridge->fmt); + + bridge->i2c_client = client; + v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops); + + /* got and check clock */ + bridge->xclk = devm_clk_get(dev, "xclk"); + if (IS_ERR(bridge->xclk)) { + dev_err(dev, "failed to get xclk\n"); + return PTR_ERR(bridge->xclk); + } + + clk_freq = clk_get_rate(bridge->xclk); + if (clk_freq < 6000000 || clk_freq > 27000000) { + dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n", + clk_freq); + return -EINVAL; + } + + bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + + ret = mipid02_get_regulators(bridge); + if (ret) { + dev_err(dev, "failed to get regulators %d", ret); + return ret; + } + + mutex_init(&bridge->lock); + bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + bridge->sd.entity.ops = &mipid02_subdev_entity_ops; + bridge->pad[0].flags = MEDIA_PAD_FL_SINK; + bridge->pad[1].flags = MEDIA_PAD_FL_SINK; + bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&bridge->sd.entity, MIPID02_PAD_NB, + bridge->pad); + if (ret) { + dev_err(&client->dev, "pads init failed %d", ret); + goto mutex_cleanup; + } + + /* enable clock, power and reset device if available */ + ret = mipid02_set_power_on(bridge); + if (ret) + goto entity_cleanup; + + ret = mipid02_detect(bridge); + if (ret) { + dev_err(&client->dev, "failed to detect mipid02 %d", ret); + goto power_off; + } + + ret = mipid02_parse_tx_ep(bridge); + if (ret) { + dev_err(&client->dev, "failed to parse tx %d", ret); + goto power_off; + } + + ret = mipid02_parse_rx_ep(bridge); + if (ret) { + dev_err(&client->dev, "failed to parse rx %d", ret); + goto power_off; + } + + ret = v4l2_async_register_subdev(&bridge->sd); + if (ret < 0) { + dev_err(&client->dev, "v4l2_async_register_subdev failed %d", + ret); + goto unregister_notifier; + } + + dev_info(&client->dev, "mipid02 device probe successfully"); + + return 0; + +unregister_notifier: + v4l2_async_notifier_unregister(&bridge->notifier); + v4l2_async_notifier_cleanup(&bridge->notifier); +power_off: + mipid02_set_power_off(bridge); +entity_cleanup: + media_entity_cleanup(&bridge->sd.entity); +mutex_cleanup: + mutex_destroy(&bridge->lock); + + return ret; +} + +static int mipid02_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct mipid02_dev *bridge = to_mipid02_dev(sd); + + v4l2_async_notifier_unregister(&bridge->notifier); + v4l2_async_notifier_cleanup(&bridge->notifier); + v4l2_async_unregister_subdev(&bridge->sd); + mipid02_set_power_off(bridge); + media_entity_cleanup(&bridge->sd.entity); + mutex_destroy(&bridge->lock); + + return 0; +} + +static const struct of_device_id mipid02_dt_ids[] = { + { .compatible = "st,st-mipid02" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mipid02_dt_ids); + +static struct i2c_driver mipid02_i2c_driver = { + .driver = { + .name = "st-mipid02", + .of_match_table = mipid02_dt_ids, + }, + .probe_new = mipid02_probe, + .remove = mipid02_remove, +}; + +module_i2c_driver(mipid02_i2c_driver); + +MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c new file mode 100644 index 000000000000..ae17887dec59 --- /dev/null +++ b/drivers/media/media-dev-allocator.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * media-dev-allocator.c - Media Controller Device Allocator API + * + * Copyright (c) 2019 Shuah Khan <shuah@kernel.org> + * + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +/* + * This file adds a global refcounted Media Controller Device Instance API. + * A system wide global media device list is managed and each media device + * includes a kref count. The last put on the media device releases the media + * device instance. + * + */ + +#include <linux/kref.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <media/media-device.h> +#include <media/media-dev-allocator.h> + +static LIST_HEAD(media_device_list); +static DEFINE_MUTEX(media_device_lock); + +struct media_device_instance { + struct media_device mdev; + struct module *owner; + struct list_head list; + struct kref refcount; +}; + +static inline struct media_device_instance * +to_media_device_instance(struct media_device *mdev) +{ + return container_of(mdev, struct media_device_instance, mdev); +} + +static void media_device_instance_release(struct kref *kref) +{ + struct media_device_instance *mdi = + container_of(kref, struct media_device_instance, refcount); + + dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__); + + mutex_lock(&media_device_lock); + + media_device_unregister(&mdi->mdev); + media_device_cleanup(&mdi->mdev); + + list_del(&mdi->list); + mutex_unlock(&media_device_lock); + + kfree(mdi); +} + +/* Callers should hold media_device_lock when calling this function */ +static struct media_device *__media_device_get(struct device *dev, + const char *module_name, + struct module *owner) +{ + struct media_device_instance *mdi; + + list_for_each_entry(mdi, &media_device_list, list) { + if (mdi->mdev.dev != dev) + continue; + + kref_get(&mdi->refcount); + + /* get module reference for the media_device owner */ + if (owner != mdi->owner && !try_module_get(mdi->owner)) + dev_err(dev, + "%s: module %s get owner reference error\n", + __func__, module_name); + else + dev_dbg(dev, "%s: module %s got owner reference\n", + __func__, module_name); + return &mdi->mdev; + } + + mdi = kzalloc(sizeof(*mdi), GFP_KERNEL); + if (!mdi) + return NULL; + + mdi->owner = owner; + kref_init(&mdi->refcount); + list_add_tail(&mdi->list, &media_device_list); + + dev_dbg(dev, "%s: Allocated media device for owner %s\n", + __func__, module_name); + return &mdi->mdev; +} + +struct media_device *media_device_usb_allocate(struct usb_device *udev, + const char *module_name, + struct module *owner) +{ + struct media_device *mdev; + + mutex_lock(&media_device_lock); + mdev = __media_device_get(&udev->dev, module_name, owner); + if (!mdev) { + mutex_unlock(&media_device_lock); + return ERR_PTR(-ENOMEM); + } + + /* check if media device is already initialized */ + if (!mdev->dev) + __media_device_usb_init(mdev, udev, udev->product, + module_name); + mutex_unlock(&media_device_lock); + return mdev; +} +EXPORT_SYMBOL_GPL(media_device_usb_allocate); + +void media_device_delete(struct media_device *mdev, const char *module_name, + struct module *owner) +{ + struct media_device_instance *mdi = to_media_device_instance(mdev); + + mutex_lock(&media_device_lock); + /* put module reference for the media_device owner */ + if (mdi->owner != owner) { + module_put(mdi->owner); + dev_dbg(mdi->mdev.dev, + "%s: module %s put owner module reference\n", + __func__, module_name); + } + mutex_unlock(&media_device_lock); + kref_put(&mdi->refcount, media_device_instance_release); +} +EXPORT_SYMBOL_GPL(media_device_delete); diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 6b87a721dc49..d5aa30eeff4a 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -251,6 +251,7 @@ int __must_check media_devnode_register(struct media_device *mdev, /* Part 2: Initialize the character device */ cdev_init(&devnode->cdev, &media_devnode_fops); devnode->cdev.owner = owner; + kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); /* Part 3: Add the media and char device */ ret = cdev_device_add(&devnode->cdev, &devnode->dev); @@ -290,8 +291,9 @@ void media_devnode_unregister(struct media_devnode *devnode) mutex_lock(&media_devnode_lock); /* Delete the cdev on this minor as well */ cdev_device_del(&devnode->cdev, &devnode->dev); - mutex_unlock(&media_devnode_lock); devnode->media_dev = NULL; + mutex_unlock(&media_devnode_lock); + put_device(&devnode->dev); } diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 0b1cb3559140..a998a2e0ea1d 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -17,7 +17,6 @@ */ #include <linux/bitmap.h> -#include <linux/module.h> #include <linux/property.h> #include <linux/slab.h> #include <media/media-entity.h> @@ -436,7 +435,10 @@ __must_check int __media_pipeline_start(struct media_entity *entity, entity->stream_count++; - if (WARN_ON(entity->pipe && entity->pipe != pipe)) { + if (entity->pipe && entity->pipe != pipe) { + pr_err("Pipe active for %s. Can't start for %s\n", + entity->name, + entity_err->name); ret = -EBUSY; goto error; } @@ -588,33 +590,6 @@ void media_pipeline_stop(struct media_entity *entity) EXPORT_SYMBOL_GPL(media_pipeline_stop); /* ----------------------------------------------------------------------------- - * Module use count - */ - -struct media_entity *media_entity_get(struct media_entity *entity) -{ - if (entity == NULL) - return NULL; - - if (entity->graph_obj.mdev->dev && - !try_module_get(entity->graph_obj.mdev->dev->driver->owner)) - return NULL; - - return entity; -} -EXPORT_SYMBOL_GPL(media_entity_get); - -void media_entity_put(struct media_entity *entity) -{ - if (entity == NULL) - return; - - if (entity->graph_obj.mdev->dev) - module_put(entity->graph_obj.mdev->dev->driver->owner); -} -EXPORT_SYMBOL_GPL(media_entity_put); - -/* ----------------------------------------------------------------------------- * Links management */ diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c index 9e5fd2ac769e..e3fca436c75b 100644 --- a/drivers/media/media-request.c +++ b/drivers/media/media-request.c @@ -251,7 +251,7 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd) if (!mdev || !mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) - return ERR_PTR(-EACCES); + return ERR_PTR(-EBADR); f = fdget(request_fd); if (!f.file) @@ -407,7 +407,7 @@ int media_request_object_bind(struct media_request *req, int ret = -EBUSY; if (WARN_ON(!ops->release)) - return -EACCES; + return -EBADR; spin_lock_irqsave(&req->lock, flags); diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig index 7693487e2f63..3941ee8352bb 100644 --- a/drivers/media/mmc/siano/Kconfig +++ b/drivers/media/mmc/siano/Kconfig @@ -9,5 +9,5 @@ config SMS_SDIO_DRV depends on !RC_CORE || RC_CORE select MEDIA_COMMON_OPTIONS select SMS_SIANO_MDTV - ---help--- + help Choose if you would like to have Siano's support for SDIO interface diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index bc89e37608cd..0f46db7d5ffc 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -13,7 +13,7 @@ config VIDEO_BT848 select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT select RADIO_ADAPTERS select RADIO_TEA575X - ---help--- + help Support for BT848 based frame grabber/overlay boards. This includes the Miro, Hauppauge and STB boards. Please read the material in <file:Documentation/media/v4l-drivers/bttv.rst> for more information. diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index c94318c71a0c..e929797206f6 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -1100,7 +1100,8 @@ static int dst_get_device_id(struct dst_state *state) /* Card capabilities */ state->dst_hw_cap = p_dst_type->dst_feature; pr_err("Recognise [%s]\n", p_dst_type->device_id); - strncpy(&state->fw_name[0], p_dst_type->device_id, 6); + strscpy(state->fw_name, p_dst_type->device_id, + sizeof(state->fw_name)); /* Multiple tuners */ if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { switch (use_dst_type) { diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h index 6a2cfdd44e3e..79dec1b1722c 100644 --- a/drivers/media/pci/bt8xx/dst_common.h +++ b/drivers/media/pci/bt8xx/dst_common.h @@ -138,7 +138,7 @@ struct dst_state { u32 tuner_type; char *tuner_name; struct mutex dst_mutex; - u8 fw_name[8]; + char fw_name[8]; struct dvb_device *dst_ca; }; diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index aa35cbc0a904..9a544bab3178 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -11,7 +11,7 @@ config VIDEO_COBALT select VIDEO_ADV7511 select VIDEO_ADV7842 select VIDEOBUF2_DMA_SG - ---help--- + help This is a video4linux driver for the Cisco PCIe Cobalt card. This board is sadly not available outside of Cisco, but it is diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c index 04783e78cc12..a518927abae1 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.c +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -128,7 +128,7 @@ done: cb->vb.sequence = s->sequence++; vb2_buffer_done(&cb->vb.vb2_buf, (skip || s->unstable_frame) ? - VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE); + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); } irqreturn_t cobalt_irq_handler(int irq, void *dev_id) diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig index c675b83c43a9..96477bba0d5c 100644 --- a/drivers/media/pci/cx18/Kconfig +++ b/drivers/media/pci/cx18/Kconfig @@ -13,7 +13,7 @@ config VIDEO_CX18 select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Conexant cx23418 based PCI combo video recorder devices. @@ -27,7 +27,7 @@ config VIDEO_CX18_ALSA tristate "Conexant 23418 DMA audio support" depends on VIDEO_CX18 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio on Conexant 23418 based TV cards using ALSA. diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index f778965a2eb8..59e78fb17575 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -484,7 +484,7 @@ static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 3435bbaa3167..1bba9e497915 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -43,7 +43,7 @@ config VIDEO_CX23885 select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Conexant 23885 based TV cards. @@ -54,7 +54,7 @@ config MEDIA_ALTERA_CI tristate "Altera FPGA based CI module" depends on VIDEO_CX23885 && DVB_CORE select ALTERA_STAPL - ---help--- + help An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. To compile this driver as a module, choose M here: the diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 0d0929c54f93..e2e63f05645e 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1474,8 +1474,9 @@ static int dvb_register(struct cx23885_tsport *port) if (fe0->dvb.frontend != NULL) { struct i2c_adapter *tun_i2c; - fe0->dvb.frontend->sec_priv = kmalloc(sizeof(dib7000p_ops), GFP_KERNEL); - memcpy(fe0->dvb.frontend->sec_priv, &dib7000p_ops, sizeof(dib7000p_ops)); + fe0->dvb.frontend->sec_priv = kmemdup(&dib7000p_ops, sizeof(dib7000p_ops), GFP_KERNEL); + if (!fe0->dvb.frontend->sec_priv) + return -ENOMEM; tun_i2c = dib7000p_ops.get_i2c_master(fe0->dvb.frontend, DIBX000_I2C_INTERFACE_TUNER, 1); if (!dvb_attach(dib0070_attach, fe0->dvb.frontend, tun_i2c, &dib7070p_dib0070_config)) return -ENODEV; diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 1755d3d2feaa..a64fa9a6d5d5 100644 --- a/drivers/media/pci/cx25821/Kconfig +++ b/drivers/media/pci/cx25821/Kconfig @@ -3,7 +3,7 @@ config VIDEO_CX25821 depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select VIDEOBUF2_DMA_SG - ---help--- + help This is a video4linux driver for Conexant 25821 based TV cards. @@ -14,7 +14,7 @@ config VIDEO_CX25821_ALSA tristate "Conexant 25821 DMA audio support" depends on VIDEO_CX25821 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio on Conexant 25821 based capture cards using ALSA. diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig index 14b813d634a8..fbb17ddb6bc3 100644 --- a/drivers/media/pci/cx88/Kconfig +++ b/drivers/media/pci/cx88/Kconfig @@ -6,7 +6,7 @@ config VIDEO_CX88 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Conexant 2388x based TV cards. @@ -17,7 +17,7 @@ config VIDEO_CX88_ALSA tristate "Conexant 2388x DMA audio support" depends on VIDEO_CX88 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio on Conexant 2388x based TV cards using ALSA. @@ -33,7 +33,7 @@ config VIDEO_CX88_BLACKBIRD tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" depends on VIDEO_CX88 select VIDEO_CX2341X - ---help--- + help This adds support for MPEG encoder cards based on the Blackbird reference design, using the Conexant 2388x and 23416 chips. @@ -64,7 +64,7 @@ config VIDEO_CX88_DVB select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB/ATSC cards based on the Conexant 2388x chip. @@ -75,7 +75,7 @@ config VIDEO_CX88_ENABLE_VP3054 bool "VP-3054 Secondary I2C Bus Support" default y depends on VIDEO_CX88_DVB && DVB_MT352 - ---help--- + help This adds DVB-T support for cards based on the Conexant 2388x chip and the MT352 demodulator, which also require support for the VP-3054 diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index 16faef265e97..fc98b6d575d9 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -15,7 +15,7 @@ config DVB_DDBRIDGE select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT select DVB_DUMMY_FE if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge - Octopus mini PCIe Bridge @@ -36,7 +36,7 @@ config DVB_DDBRIDGE_MSIENABLE depends on DVB_DDBRIDGE depends on PCI_MSI default n - ---help--- + help Use PCI MSI (Message Signaled Interrupts) per default. Enabling this might lead to I2C errors originating from the bridge in conjunction with certain SATA controllers, requiring a reload of the ddbridge diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig index 858b0f2f15be..d770eec541d4 100644 --- a/drivers/media/pci/dt3155/Kconfig +++ b/drivers/media/pci/dt3155/Kconfig @@ -3,7 +3,7 @@ config VIDEO_DT3155 depends on PCI && VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG default n - ---help--- + help Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. Say Y here if you have this hardware. In doubt, say N. diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig index 715f77651482..bd518bdc9f5f 100644 --- a/drivers/media/pci/intel/ipu3/Kconfig +++ b/drivers/media/pci/intel/ipu3/Kconfig @@ -7,7 +7,7 @@ config VIDEO_IPU3_CIO2 select V4L2_FWNODE select VIDEOBUF2_DMA_SG - ---help--- + help This is the Intel IPU3 CIO2 CSI-2 receiver unit, found in Intel Skylake and Kaby Lake SoCs and used for capturing images and video from a camera sensor. diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index f8020ebe9f05..2a52a393fe74 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1601,6 +1601,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) subdev->owner = THIS_MODULE; snprintf(subdev->name, sizeof(subdev->name), CIO2_ENTITY_NAME " %td", q - cio2->queue); + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; v4l2_set_subdevdata(subdev, cio2); r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); if (r) { diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index 06ca4e23f9fb..e96b3c182a2f 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -18,7 +18,7 @@ config VIDEO_IVTV select VIDEO_VP27SMPX select VIDEO_UPD64031A select VIDEO_UPD64083 - ---help--- + help This is a video4linux driver for Conexant cx23416 or cx23415 based PCI personal video recorder devices. @@ -32,7 +32,7 @@ config VIDEO_IVTV_DEPRECATED_IOCTLS bool "enable the DVB ioctls abuse on ivtv driver" depends on VIDEO_IVTV default n - ---help--- + help Enable the usage of the a DVB set of ioctls that were abused by IVTV driver for a while. @@ -45,7 +45,7 @@ config VIDEO_IVTV_ALSA tristate "Conexant cx23415/cx23416 ALSA interface for PCM audio capture" depends on VIDEO_IVTV && SND select SND_PCM - ---help--- + help This driver provides an ALSA interface as another method for user applications to obtain PCM audio data from Conexant cx23415/cx23416 based PCI TV cards supported by the ivtv driver. @@ -63,7 +63,7 @@ config VIDEO_FB_IVTV select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - ---help--- + help This is a framebuffer driver for the Conexant cx23415 MPEG encoder/decoder. @@ -77,7 +77,7 @@ config VIDEO_FB_IVTV_FORCE_PAT bool "force cx23415 framebuffer init with x86 PAT enabled" depends on VIDEO_FB_IVTV && X86_PAT default n - ---help--- + help With PAT enabled, the cx23415 framebuffer driver does not utilize write-combined caching on the framebuffer memory. For this reason, the driver will by default disable itself diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index 6196daae4b3e..043ac0ae9ed0 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -420,7 +420,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index 6528a2180119..f8b503ef42bc 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -225,7 +225,7 @@ int mantis_i2c_init(struct mantis_pci *mantis) init_waitqueue_head(&mantis->i2c_wq); mutex_init(&mantis->i2c_lock); - strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); + strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); i2c_set_adapdata(i2c_adapter, mantis); i2c_adapter->owner = THIS_MODULE; diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig index 9a50f54231ad..ce0463c81886 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/media/pci/meye/Kconfig @@ -2,7 +2,7 @@ config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" depends on PCI && VIDEO_V4L2 depends on SONY_LAPTOP || COMPILE_TEST - ---help--- + help This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in <file:Documentation/media/v4l-drivers/meye.rst> for more information. diff --git a/drivers/media/pci/netup_unidvb/Kconfig b/drivers/media/pci/netup_unidvb/Kconfig index b663154d0cc4..60057585f04c 100644 --- a/drivers/media/pci/netup_unidvb/Kconfig +++ b/drivers/media/pci/netup_unidvb/Kconfig @@ -8,7 +8,7 @@ config DVB_NETUP_UNIDVB select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help Support for NetUP PCI express Universal DVB card. Say Y when you want to support NetUP Dual Universal DVB card. diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index e06d019996f3..8a80a5bab8e9 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -15,6 +15,6 @@ config DVB_NGENE select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index b44e0d70907e..8b28783b3fcd 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig @@ -7,7 +7,7 @@ config VIDEO_SAA7134 select CRC32 select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Philips SAA713x based TV cards. @@ -18,7 +18,7 @@ config VIDEO_SAA7134_ALSA tristate "Philips SAA7134 DMA audio support" depends on VIDEO_SAA7134 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio in Philips SAA713x based TV cards using ALSA @@ -31,7 +31,7 @@ config VIDEO_SAA7134_RC depends on VIDEO_SAA7134 depends on !(RC_CORE=m && VIDEO_SAA7134=y) default y - ---help--- + help Enables Remote Controller support on saa7134 driver. config VIDEO_SAA7134_DVB @@ -57,7 +57,7 @@ config VIDEO_SAA7134_DVB select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB cards based on the Philips saa7134 chip. @@ -68,6 +68,6 @@ config VIDEO_SAA7134_GO7007 tristate "go7007 support for saa7134 based TV cards" depends on VIDEO_SAA7134 depends on VIDEO_GO7007 - ---help--- + help Enables saa7134 driver support for boards with go7007 MPEG encoder (WIS Voyager or compatible). diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 275c5e151818..626e130a9770 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -444,7 +444,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) sd = &saa->sd; v4l2_subdev_init(sd, &saa7134_go7007_sd_ops); v4l2_set_subdevdata(sd, saa); - strncpy(sd->name, "saa7134-go7007", sizeof(sd->name)); + strscpy(sd->name, "saa7134-go7007", sizeof(sd->name)); /* Allocate a couple pages for receiving the compressed stream */ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig index da88b77a916c..60d9862580ff 100644 --- a/drivers/media/pci/saa7146/Kconfig +++ b/drivers/media/pci/saa7146/Kconfig @@ -2,7 +2,7 @@ config VIDEO_HEXIUM_GEMINI tristate "Hexium Gemini frame grabber" depends on PCI && VIDEO_V4L2 && I2C select VIDEO_SAA7146_VV - ---help--- + help This is a video4linux driver for the Hexium Gemini frame grabber card by Hexium. Please note that the Gemini Dual card is *not* fully supported. @@ -14,7 +14,7 @@ config VIDEO_HEXIUM_ORION tristate "Hexium HV-PCI6 and Orion frame grabber" depends on PCI && VIDEO_V4L2 && I2C select VIDEO_SAA7146_VV - ---help--- + help This is a video4linux driver for the Hexium HV-PCI6 and Orion frame grabber cards by Hexium. @@ -30,7 +30,7 @@ config VIDEO_MXB select VIDEO_TDA9840 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TEA6415C if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TEA6420 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for the 'Multimedia eXtension Board' TV card by Siemens-Nixdorf. diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 5817d9cde4d0..6d8e4afe9673 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -270,9 +270,8 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d /* enable i2c-port pins */ saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - hexium->i2c_adapter = (struct i2c_adapter) { - .name = "hexium gemini", - }; + strscpy(hexium->i2c_adapter.name, "hexium gemini", + sizeof(hexium->i2c_adapter.name)); saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { DEB_S("cannot register i2c-device. skipping.\n"); diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 0a05176c18ab..a794f9e5f990 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -231,9 +231,8 @@ static int hexium_probe(struct saa7146_dev *dev) saa7146_write(dev, DD1_STREAM_B, 0x00000000); saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - hexium->i2c_adapter = (struct i2c_adapter) { - .name = "hexium orion", - }; + strscpy(hexium->i2c_adapter.name, "hexium orion", + sizeof(hexium->i2c_adapter.name)); saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { DEB_S("cannot register i2c-device. skipping.\n"); diff --git a/drivers/media/pci/saa7164/Kconfig b/drivers/media/pci/saa7164/Kconfig index 9098ef5feca4..265c5a4fd823 100644 --- a/drivers/media/pci/saa7164/Kconfig +++ b/drivers/media/pci/saa7164/Kconfig @@ -8,7 +8,7 @@ config VIDEO_SAA7164 select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for NXP SAA7164 based TV cards. diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig index d9e06a6bf1eb..2061d02a82d0 100644 --- a/drivers/media/pci/solo6x10/Kconfig +++ b/drivers/media/pci/solo6x10/Kconfig @@ -8,7 +8,7 @@ config VIDEO_SOLO6X10 select VIDEOBUF2_DMA_CONTIG select SND_PCM select FONT_8x16 - ---help--- + help This driver supports the Bluecherry H.264 and MPEG-4 hardware compression capture cards and other Softlogic-based ones. diff --git a/drivers/media/pci/tw5864/Kconfig b/drivers/media/pci/tw5864/Kconfig index 760fb11dfeae..e5d52f076232 100644 --- a/drivers/media/pci/tw5864/Kconfig +++ b/drivers/media/pci/tw5864/Kconfig @@ -2,7 +2,7 @@ config VIDEO_TW5864 tristate "Techwell TW5864 video/audio grabber and encoder" depends on VIDEO_DEV && PCI && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG - ---help--- + help Support for boards based on Techwell TW5864 chip which provides multichannel video & audio grabbing and encoding (H.264, MJPEG, ADPCM G.726). diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 5a1f3aa4101a..434d313a3c15 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -1395,13 +1395,13 @@ static void tw5864_handle_frame(struct tw5864_h264_frame *frame) input->vb = NULL; spin_unlock_irqrestore(&input->slock, flags); - v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); - if (!vb) { /* Gone because of disabling */ dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n"); return; } + v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); + /* * Check for space. * Mind the overhead of startcode emulation prevention. diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig index 95d5d5202048..4bfc4fa416e5 100644 --- a/drivers/media/pci/tw68/Kconfig +++ b/drivers/media/pci/tw68/Kconfig @@ -2,7 +2,7 @@ config VIDEO_TW68 tristate "Techwell tw68x Video For Linux" depends on VIDEO_DEV && PCI && VIDEO_V4L2 select VIDEOBUF2_DMA_SG - ---help--- + help Support for Techwell tw68xx based frame grabber boards. To compile this driver as a module, choose M here: the diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 4acbed189644..011c1c2fcf19 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -6,7 +6,7 @@ menuconfig V4L_PLATFORM_DRIVERS bool "V4L platform devices" depends on MEDIA_CAMERA_SUPPORT default n - ---help--- + help Say Y here to enable support for platform-specific V4L drivers. if V4L_PLATFORM_DRIVERS @@ -55,7 +55,7 @@ config VIDEO_VIU depends on VIDEO_V4L2 && (PPC_MPC512x || COMPILE_TEST) && I2C select VIDEOBUF_DMA_CONTIG default y - ---help--- + help Support for Freescale VIU video driver. This device captures video data, or overlays video on DIU frame buffer. @@ -80,13 +80,13 @@ config VIDEO_OMAP3 select VIDEOBUF2_DMA_CONTIG select MFD_SYSCON select V4L2_FWNODE - ---help--- + help Driver for an OMAP 3 camera controller. config VIDEO_OMAP3_DEBUG bool "OMAP 3 Camera debug messages" depends on VIDEO_OMAP3 - ---help--- + help Enable debug messages on OMAP 3 camera controller driver. config VIDEO_PXA27x @@ -96,7 +96,7 @@ config VIDEO_PXA27x select VIDEOBUF2_DMA_SG select SG_SPLIT select V4L2_FWNODE - ---help--- + help This is a v4l2 driver for the PXA27x Quick Capture Interface config VIDEO_QCOM_CAMSS @@ -112,7 +112,7 @@ config VIDEO_S3C_CAMIF depends on PM depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG - ---help--- + help This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera host interface (CAMIF). @@ -125,7 +125,7 @@ config VIDEO_STM32_DCMI depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help This module makes the STM32 Digital Camera Memory Interface (DCMI) available as a v4l2 device. @@ -138,7 +138,7 @@ config VIDEO_RENESAS_CEU depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help This is a v4l2 driver for the Renesas CEU Interface source "drivers/media/platform/exynos4-is/Kconfig" @@ -155,7 +155,7 @@ config VIDEO_TI_CAL select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE default n - ---help--- + help Support for the TI CAL (Camera Adaptation Layer) block found on DRA72X SoC. In TI Technical Reference Manual this module is referred as @@ -168,7 +168,7 @@ menuconfig V4L_MEM2MEM_DRIVERS depends on VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT default n - ---help--- + help Say Y here to enable selecting drivers for V4L devices that use system memory for both source and destination buffers, as opposed to capture and output drivers, which use memory buffers for just @@ -184,7 +184,7 @@ config VIDEO_CODA select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select GENERIC_ALLOCATOR - ---help--- + help Coda is a range of video codec IPs that supports H.264, MPEG-4, and other video formats. @@ -207,7 +207,7 @@ config VIDEO_MEDIATEK_JPEG depends on ARCH_MEDIATEK || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help Mediatek jpeg codec driver provides HW capability to decode JPEG format @@ -218,7 +218,7 @@ config VIDEO_MEDIATEK_VPU tristate "Mediatek Video Processor Unit" depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_MEDIATEK || COMPILE_TEST - ---help--- + help This driver provides downloading VPU firmware and communicating with VPU. This driver for hw video codec embedded in Mediatek's MT8173 SOCs. It is able @@ -236,7 +236,7 @@ config VIDEO_MEDIATEK_MDP select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU default n - ---help--- + help It is a v4l2 driver and present in Mediatek MT8173 SoCs. The driver supports for scaling and color space conversion. @@ -252,7 +252,7 @@ config VIDEO_MEDIATEK_VCODEC select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU default n - ---help--- + help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats This driver rely on VPU driver to communicate with VPU. @@ -276,7 +276,7 @@ config VIDEO_SAMSUNG_S5P_G2D select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n - ---help--- + help This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D 2d graphics accelerator. @@ -286,7 +286,7 @@ config VIDEO_SAMSUNG_S5P_JPEG depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help This is a v4l2 driver for Samsung S5P, EXYNOS3250 and EXYNOS4 JPEG codec @@ -407,7 +407,7 @@ config VIDEO_RENESAS_FDP1 depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help This is a V4L2 driver for the Renesas Fine Display Processor providing colour space conversion, and de-interlacing features. @@ -420,7 +420,7 @@ config VIDEO_RENESAS_JPU depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help This is a V4L2 driver for the Renesas JPEG Processing Unit. To compile this driver as a module, choose M here: the module @@ -430,7 +430,7 @@ config VIDEO_RENESAS_FCP tristate "Renesas Frame Compression Processor" depends on ARCH_RENESAS || COMPILE_TEST depends on OF - ---help--- + help This is a driver for the Renesas Frame Compression Processor (FCP). The FCP is a companion module of video processing modules in the Renesas R-Car Gen3 SoCs. It handles memory access for the codec, @@ -446,7 +446,7 @@ config VIDEO_RENESAS_VSP1 depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC - ---help--- + help This is a V4L2 driver for the Renesas VSP1 video processing engine. To compile this driver as a module, choose M here: the module @@ -459,7 +459,7 @@ config VIDEO_ROCKCHIP_RGA select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV default n - ---help--- + help This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator. Rockchip RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D graphics operations, such as point/line drawing, @@ -477,14 +477,14 @@ config VIDEO_TI_VPE select VIDEO_TI_SC select VIDEO_TI_CSC default n - ---help--- + help Support for the TI VPE(Video Processing Engine) block found on DRA7XX SoC. config VIDEO_TI_VPE_DEBUG bool "VPE debug messages" depends on VIDEO_TI_VPE - ---help--- + help Enable debug messages on VPE driver. config VIDEO_QCOM_VENUS @@ -495,7 +495,7 @@ config VIDEO_QCOM_VENUS select QCOM_SCM if ARCH_QCOM select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV - ---help--- + help This is a V4L2 driver for Qualcomm Venus video accelerator hardware. It accelerates encoding and decoding operations on various Qualcomm SoCs. @@ -530,7 +530,7 @@ config VIDEO_VIM2M select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV default n - ---help--- + help This is a virtual test device for the memory-to-memory driver framework. @@ -542,7 +542,7 @@ menuconfig DVB_PLATFORM_DRIVERS bool "DVB platform devices" depends on MEDIA_DIGITAL_TV_SUPPORT default n - ---help--- + help Say Y here to enable support for platform-specific Digital TV drivers. if DVB_PLATFORM_DRIVERS @@ -562,7 +562,7 @@ config VIDEO_CROS_EC_CEC select CEC_NOTIFIER select CHROME_PLATFORMS select CROS_EC_PROTO - ---help--- + help If you say yes here you will get support for the ChromeOS Embedded Controller's CEC. The CEC bus is present in the HDMI connector and enables communication @@ -573,18 +573,34 @@ config VIDEO_MESON_AO_CEC depends on ARCH_MESON || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication +config VIDEO_MESON_G12A_AO_CEC + tristate "Amlogic Meson G12A AO CEC driver" + depends on ARCH_MESON || COMPILE_TEST + depends on COMMON_CLK && OF + select REGMAP + select REGMAP_MMIO + select CEC_CORE + select CEC_NOTIFIER + ---help--- + This is a driver for Amlogic Meson G12A SoCs AO CEC interface. + This driver if for the new AO-CEC module found in G12A SoCs, + usually named AO_CEC_B in documentation. + It uses the generic CEC framework interface. + CEC bus is present in the HDMI connector and enables communication + between compatible devices. + config CEC_GPIO tristate "Generic GPIO-based CEC driver" depends on PREEMPT || COMPILE_TEST select CEC_CORE select CEC_PIN select GPIOLIB - ---help--- + help This is a generic GPIO-based CEC driver. The CEC bus is present in the HDMI connector and enables communication between compatible devices. @@ -594,7 +610,7 @@ config VIDEO_SAMSUNG_S5P_CEC depends on ARCH_EXYNOS || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for Samsung S5P HDMI CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication @@ -605,7 +621,7 @@ config VIDEO_STI_HDMI_CEC depends on ARCH_STI || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for STIH4xx HDMI CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication @@ -617,7 +633,7 @@ config VIDEO_STM32_HDMI_CEC select REGMAP select REGMAP_MMIO select CEC_CORE - ---help--- + help This is a driver for STM32 interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication @@ -628,7 +644,7 @@ config VIDEO_TEGRA_HDMI_CEC depends on ARCH_TEGRA || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for the Tegra HDMI CEC interface. It uses the generic CEC framework interface. The CEC bus is present in the HDMI connector and enables communication @@ -649,7 +665,7 @@ config VIDEO_SECO_CEC config VIDEO_SECO_RC bool "SECO Boards IR RC5 support" depends on VIDEO_SECO_CEC - depends on RC_CORE + depends on RC_CORE=y || RC_CORE = VIDEO_SECO_CEC help If you say yes here you will get support for the SECO Boards Consumer-IR in seco-cec driver. @@ -662,7 +678,7 @@ menuconfig SDR_PLATFORM_DRIVERS bool "SDR platform devices" depends on MEDIA_SDR_SUPPORT default n - ---help--- + help Say Y here to enable support for platform-specific SDR Drivers. if SDR_PLATFORM_DRIVERS @@ -672,7 +688,7 @@ config VIDEO_RCAR_DRIF depends on VIDEO_V4L2 depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_VMALLOC - ---help--- + help Say Y if you want to enable R-Car Gen3 DRIF support. DRIF is Digital Radio Interface that interfaces with an RF front end chip. It is a receiver of digital data which uses DMA to transfer received data to diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 5c17624aaade..fe7b937eb5f2 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1540,7 +1540,7 @@ static int vpfe_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; f->type = vpfe->fmt.type; diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 692e08ef38c0..8144fe36ad48 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -14,7 +14,6 @@ #include <linux/of_irq.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> -#include <linux/reset.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -208,7 +207,6 @@ struct aspeed_video { void __iomem *base; struct clk *eclk; struct clk *vclk; - struct reset_control *rst; struct device *dev; struct v4l2_ctrl_handler ctrl_handler; @@ -483,19 +481,10 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video) aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET); } -static void aspeed_video_reset(struct aspeed_video *video) -{ - /* Reset the engine */ - reset_control_assert(video->rst); - - /* Don't usleep here; function may be called in interrupt context */ - udelay(100); - reset_control_deassert(video->rst); -} - static void aspeed_video_off(struct aspeed_video *video) { - aspeed_video_reset(video); + /* Disable interrupts */ + aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); /* Turn off the relevant clocks */ clk_disable_unprepare(video->vclk); @@ -507,8 +496,6 @@ static void aspeed_video_on(struct aspeed_video *video) /* Turn on the relevant clocks */ clk_prepare_enable(video->eclk); clk_prepare_enable(video->vclk); - - aspeed_video_reset(video); } static void aspeed_video_bufs_done(struct aspeed_video *video, @@ -1464,7 +1451,9 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q) * Need to force stop any DMA and try and get HW into a good * state for future calls to start streaming again. */ - aspeed_video_reset(video); + aspeed_video_off(video); + aspeed_video_on(video); + aspeed_video_init_regs(video); aspeed_video_get_resolution(video); @@ -1619,17 +1608,7 @@ static int aspeed_video_init(struct aspeed_video *video) return PTR_ERR(video->vclk); } - video->rst = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(video->rst)) { - dev_err(dev, "Unable to get VE reset\n"); - return PTR_ERR(video->rst); - } - - rc = of_reserved_mem_device_init(dev); - if (rc) { - dev_err(dev, "Unable to reserve memory\n"); - return rc; - } + of_reserved_mem_device_init(dev); rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (rc) { diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index a211ef20f77e..c3f6a47cdc0e 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig @@ -15,6 +15,6 @@ config VIDEO_ATMEL_ISI depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help This module makes the ATMEL Image Sensor Interface available as a v4l2 device. diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 2aadc19235ea..d730693f299c 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -24,6 +24,8 @@ #define ISC_PFE_CFG0_HPOL_LOW BIT(0) #define ISC_PFE_CFG0_VPOL_LOW BIT(1) #define ISC_PFE_CFG0_PPOL_LOW BIT(2) +#define ISC_PFE_CFG0_CCIR656 BIT(9) +#define ISC_PFE_CFG0_CCIR_CRC BIT(10) #define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4) #define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 50178968b8a6..4bba9da206e4 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -89,35 +89,25 @@ struct isc_subdev_entity { struct list_head list; }; -/* Indicate the format is generated by the sensor */ -#define FMT_FLAG_FROM_SENSOR BIT(0) -/* Indicate the format is produced by ISC itself */ -#define FMT_FLAG_FROM_CONTROLLER BIT(1) -/* Indicate a Raw Bayer format */ -#define FMT_FLAG_RAW_FORMAT BIT(2) - -#define FMT_FLAG_RAW_FROM_SENSOR (FMT_FLAG_FROM_SENSOR | \ - FMT_FLAG_RAW_FORMAT) - /* * struct isc_format - ISC media bus format information + This structure represents the interface between the ISC + and the sensor. It's the input format received by + the ISC. * @fourcc: Fourcc code for this format * @mbus_code: V4L2 media bus format code. - * flags: Indicate format from sensor or converted by controller - * @bpp: Bits per pixel (when stored in memory) - * (when transferred over a bus) - * @sd_support: Subdev supports this format - * @isc_support: ISC can convert raw format to this format + * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. + this is either BGBG, RGRG, etc. + * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC */ struct isc_format { u32 fourcc; u32 mbus_code; - u32 flags; - u8 bpp; + u32 cfa_baycfg; bool sd_support; - bool isc_support; + u32 pfe_cfg0_bps; }; /* Pipeline bitmap */ @@ -135,16 +125,31 @@ struct isc_format { #define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) +/* + * struct fmt_config - ISC format configuration and internal pipeline + This structure represents the internal configuration + of the ISC. + It also holds the format that ISC will present to v4l2. + * @sd_format: Pointer to an isc_format struct that holds the sensor + configuration. + * @fourcc: Fourcc code for this format. + * @bpp: Bytes per pixel in the current format. + * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) + * @dcfg_imode: Configuration of the input of the DMA module + * @dctrl_dview: Configuration of the output of the DMA module + * @bits_pipeline: Configuration of the pipeline, which modules are enabled + */ struct fmt_config { - u32 fourcc; + struct isc_format *sd_format; - u32 pfe_cfg0_bps; - u32 cfa_baycfg; - u32 rlp_cfg_mode; - u32 dcfg_imode; - u32 dctrl_dview; + u32 fourcc; + u8 bpp; - u32 bits_pipeline; + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; }; #define HIST_ENTRIES 512 @@ -196,8 +201,9 @@ struct isc_device { struct v4l2_format fmt; struct isc_format **user_formats; unsigned int num_user_formats; - const struct isc_format *current_fmt; - const struct isc_format *raw_fmt; + + struct fmt_config config; + struct fmt_config try_config; struct isc_ctrls ctrls; struct work_struct awb_work; @@ -210,319 +216,125 @@ struct isc_device { struct list_head subdev_entities; }; -static struct isc_format formats_list[] = { - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, +/* This is a list of the formats that the ISC can *output* */ +static struct isc_format controller_formats[] = { { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_ARGB444, }, { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_ARGB555, }, { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, }, { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_ABGR32, }, { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_XBGR32, }, { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_YUV420, }, { - .fourcc = V4L2_PIX_FMT_YUV420, - .mbus_code = 0x0, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 12, + .fourcc = V4L2_PIX_FMT_YUYV, }, { .fourcc = V4L2_PIX_FMT_YUV422P, - .mbus_code = 0x0, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, }, { .fourcc = V4L2_PIX_FMT_GREY, - .mbus_code = MEDIA_BUS_FMT_Y8_1X8, - .flags = FMT_FLAG_FROM_CONTROLLER | - FMT_FLAG_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB444, - .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555, - .mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB32, - .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 32, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .flags = FMT_FLAG_FROM_CONTROLLER | - FMT_FLAG_FROM_SENSOR, - .bpp = 16, }, }; -static struct fmt_config fmt_configs_list[] = { +/* This is a list of formats that the ISC can receive as *input* */ +static struct isc_format formats_list[] = { { .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_GBGB, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_GRGR, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_RGRG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, + .cfa_baycfg = ISC_BAY_CFG_RGRG, }, { .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, .cfa_baycfg = ISC_BAY_CFG_GBGB, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, .cfa_baycfg = ISC_BAY_CFG_GRGR, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, .cfa_baycfg = ISC_BAY_CFG_RGRG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_GBGB, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0 }, { .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_GRGR, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_RGRG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, - .dcfg_imode = ISC_DCFG_IMODE_YC420P, - .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, - .bits_pipeline = SUB420_ENABLE | SUB422_ENABLE | - CBC_ENABLE | CSC_ENABLE | - GAM_ENABLES | - CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_YUV422P, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, - .dcfg_imode = ISC_DCFG_IMODE_YC422P, - .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, - .bits_pipeline = SUB422_ENABLE | - CBC_ENABLE | CSC_ENABLE | - GAM_ENABLES | - CFA_ENABLE | WB_ENABLE, }, { .fourcc = V4L2_PIX_FMT_GREY, + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = CBC_ENABLE | CSC_ENABLE | - GAM_ENABLES | - CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB444, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, }, { - .fourcc = V4L2_PIX_FMT_ARGB555, + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, }, { .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB32, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32, - .dcfg_imode = ISC_DCFG_IMODE_PACKED32, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0 }, }; @@ -571,6 +383,13 @@ static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, }; +#define ISC_IS_FORMAT_RAW(mbus_code) \ + (((mbus_code) & 0xf000) == 0x3000) + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + static unsigned int sensor_preferred = 1; module_param(sensor_preferred, uint, 0644); MODULE_PARM_DESC(sensor_preferred, @@ -896,40 +715,17 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) return 0; } -static inline bool sensor_is_preferred(const struct isc_format *isc_fmt) -{ - return (sensor_preferred && isc_fmt->sd_support) || - !isc_fmt->isc_support; -} - -static struct fmt_config *get_fmt_config(u32 fourcc) -{ - struct fmt_config *config; - int i; - - config = &fmt_configs_list[0]; - for (i = 0; i < ARRAY_SIZE(fmt_configs_list); i++) { - if (config->fourcc == fourcc) - return config; - - config++; - } - return NULL; -} - static void isc_start_dma(struct isc_device *isc) { struct regmap *regmap = isc->regmap; - struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; - u32 sizeimage = pixfmt->sizeimage; - struct fmt_config *config = get_fmt_config(isc->current_fmt->fourcc); + u32 sizeimage = isc->fmt.fmt.pix.sizeimage; u32 dctrl_dview; dma_addr_t addr0; addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); regmap_write(regmap, ISC_DAD0, addr0); - switch (pixfmt->pixelformat) { + switch (isc->config.fourcc) { case V4L2_PIX_FMT_YUV420: regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); @@ -942,10 +738,7 @@ static void isc_start_dma(struct isc_device *isc) break; } - if (sensor_is_preferred(isc->current_fmt)) - dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - else - dctrl_dview = config->dctrl_dview; + dctrl_dview = isc->config.dctrl_dview; regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); @@ -955,7 +748,6 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; - struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); u32 val, bay_cfg; const u32 *gamma; unsigned int i; @@ -969,7 +761,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) if (!pipeline) return; - bay_cfg = config->cfa_baycfg; + bay_cfg = isc->config.sd_format->cfa_baycfg; regmap_write(regmap, ISC_WB_CFG, bay_cfg); regmap_write(regmap, ISC_WB_O_RGR, 0x0); @@ -1011,24 +803,24 @@ static int isc_update_profile(struct isc_device *isc) } if (counter < 0) { - v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n"); + v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n"); return -ETIMEDOUT; } return 0; } -static void isc_set_histogram(struct isc_device *isc) +static void isc_set_histogram(struct isc_device *isc, bool enable) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; - struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); - if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) { + if (enable) { regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R | - (config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) | - ISC_HIS_CFG_RAR); + (isc->config.sd_format->cfa_baycfg + << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); ctrls->hist_id = ISC_HIS_CFG_MODE_R; @@ -1036,7 +828,7 @@ static void isc_set_histogram(struct isc_device *isc) regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); ctrls->hist_stat = HIST_ENABLED; - } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) { + } else { regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); @@ -1044,58 +836,24 @@ static void isc_set_histogram(struct isc_device *isc) } } -static inline void isc_get_param(const struct isc_format *fmt, - u32 *rlp_mode, u32 *dcfg) -{ - struct fmt_config *config = get_fmt_config(fmt->fourcc); - - *dcfg = ISC_DCFG_YMBSIZE_BEATS8; - - switch (fmt->fourcc) { - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - *rlp_mode = config->rlp_cfg_mode; - *dcfg |= config->dcfg_imode; - break; - default: - *rlp_mode = ISC_RLP_CFG_MODE_DAT8; - *dcfg |= ISC_DCFG_IMODE_PACKED8; - break; - } -} - static int isc_configure(struct isc_device *isc) { struct regmap *regmap = isc->regmap; - const struct isc_format *current_fmt = isc->current_fmt; - struct fmt_config *curfmt_config = get_fmt_config(current_fmt->fourcc); - struct fmt_config *rawfmt_config = get_fmt_config(isc->raw_fmt->fourcc); - struct isc_subdev_entity *subdev = isc->current_subdev; u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; + struct isc_subdev_entity *subdev = isc->current_subdev; - if (sensor_is_preferred(current_fmt)) { - pfe_cfg0 = curfmt_config->pfe_cfg0_bps; - pipeline = 0x0; - isc_get_param(current_fmt, &rlp_mode, &dcfg); - isc->ctrls.hist_stat = HIST_INIT; - } else { - pfe_cfg0 = rawfmt_config->pfe_cfg0_bps; - pipeline = curfmt_config->bits_pipeline; - rlp_mode = curfmt_config->rlp_cfg_mode; - dcfg = curfmt_config->dcfg_imode | + pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; + rlp_mode = isc->config.rlp_cfg_mode; + pipeline = isc->config.bits_pipeline; + + dcfg = isc->config.dcfg_imode | ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; - } pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | - ISC_PFE_CFG0_MODE_MASK; + ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); @@ -1107,8 +865,15 @@ static int isc_configure(struct isc_device *isc) /* Set the pipeline */ isc_set_pipeline(isc, pipeline); - if (pipeline) - isc_set_histogram(isc); + /* + * The current implemented histogram is available for RAW R, B, GB + * channels. We need to check if sensor is outputting RAW BAYER + */ + if (isc->ctrls.awb && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + else + isc_set_histogram(isc, false); /* Update profile */ return isc_update_profile(isc); @@ -1125,7 +890,8 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) /* Enable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&isc->v4l2_dev, "stream on failed in subdev\n"); + v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", + ret); goto err_start_stream; } @@ -1223,6 +989,22 @@ static void isc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&isc->dma_queue_lock, flags); } +static struct isc_format *find_format_by_fourcc(struct isc_device *isc, + unsigned int fourcc) +{ + unsigned int num_formats = isc->num_user_formats; + struct isc_format *fmt; + unsigned int i; + + for (i = 0; i < num_formats; i++) { + fmt = isc->user_formats[i]; + if (fmt->fourcc == fourcc) + return fmt; + } + + return NULL; +} + static const struct vb2_ops isc_vb2_ops = { .queue_setup = isc_queue_setup, .wait_prepare = vb2_ops_wait_prepare, @@ -1249,15 +1031,31 @@ static int isc_querycap(struct file *file, void *priv, static int isc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct isc_device *isc = video_drvdata(file); u32 index = f->index; + u32 i, supported_index; - if (index >= isc->num_user_formats) - return -EINVAL; + if (index < ARRAY_SIZE(controller_formats)) { + f->pixelformat = controller_formats[index].fourcc; + return 0; + } - f->pixelformat = isc->user_formats[index]->fourcc; + index -= ARRAY_SIZE(controller_formats); - return 0; + i = 0; + supported_index = 0; + + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { + if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) || + !formats_list[i].sd_support) + continue; + if (supported_index == index) { + f->pixelformat = formats_list[i].fourcc; + return 0; + } + supported_index++; + } + + return -EINVAL; } static int isc_g_fmt_vid_cap(struct file *file, void *priv, @@ -1270,26 +1068,238 @@ static int isc_g_fmt_vid_cap(struct file *file, void *priv, return 0; } -static struct isc_format *find_format_by_fourcc(struct isc_device *isc, - unsigned int fourcc) +/* + * Checks the current configured format, if ISC can output it, + * considering which type of format the ISC receives from the sensor + */ +static int isc_try_validate_formats(struct isc_device *isc) { - unsigned int num_formats = isc->num_user_formats; - struct isc_format *fmt; - unsigned int i; + int ret; + bool bayer = false, yuv = false, rgb = false, grey = false; + + /* all formats supported by the RLP module are OK */ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + ret = 0; + bayer = true; + break; - for (i = 0; i < num_formats; i++) { - fmt = isc->user_formats[i]; - if (fmt->fourcc == fourcc) - return fmt; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + ret = 0; + yuv = true; + break; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ARGB555: + ret = 0; + rgb = true; + break; + case V4L2_PIX_FMT_GREY: + ret = 0; + grey = true; + break; + default: + /* any other different formats are not supported */ + ret = -EINVAL; } - return NULL; + /* we cannot output RAW/Grey if we do not receive RAW */ + if ((bayer || grey) && + !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) + return -EINVAL; + + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", + rgb, yuv, grey, bayer); + + return ret; +} + +/* + * Configures the RLP and DMA modules, depending on the output format + * configured for the ISC. + * If direct_dump == true, just dump raw data 8 bits. + */ +static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) +{ + if (direct_dump) { + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + return 0; + } + + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_RGB565: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB444: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB555: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 32; + break; + case V4L2_PIX_FMT_YUV420: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 12; + break; + case V4L2_PIX_FMT_YUV422P: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_YUYV: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_GREY: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Configuring pipeline modules, depending on which format the ISC outputs + * and considering which format it has as input from the sensor. + */ +static int isc_try_configure_pipeline(struct isc_device *isc) +{ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + WB_ENABLE | GAM_ENABLES; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV420: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV422P: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUYV: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_GREY: + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + /* if sensor format is RAW, we convert inside ISC */ + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + default: + isc->try_config.bits_pipeline = 0x0; + } + return 0; } static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, - struct isc_format **current_fmt, u32 *code) + u32 *code) { - struct isc_format *isc_fmt; + int i; + struct isc_format *sd_fmt = NULL, *direct_fmt = NULL; struct v4l2_pix_format *pixfmt = &f->fmt.pix; struct v4l2_subdev_pad_config pad_cfg; struct v4l2_subdev_format format = { @@ -1297,48 +1307,119 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, }; u32 mbus_code; int ret; + bool rlp_dma_direct_dump = false; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - isc_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); - if (!isc_fmt) { - v4l2_warn(&isc->v4l2_dev, "Format 0x%x not found\n", - pixfmt->pixelformat); - isc_fmt = isc->user_formats[isc->num_user_formats - 1]; - pixfmt->pixelformat = isc_fmt->fourcc; + /* Step 1: find a RAW format that is supported */ + for (i = 0; i < isc->num_user_formats; i++) { + if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) { + sd_fmt = isc->user_formats[i]; + break; + } + } + /* Step 2: We can continue with this RAW format, or we can look + * for better: maybe sensor supports directly what we need. + */ + direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); + + /* Step 3: We have both. We decide given the module parameter which + * one to use. + */ + if (direct_fmt && sd_fmt && sensor_preferred) + sd_fmt = direct_fmt; + + /* Step 4: we do not have RAW but we have a direct format. Use it. */ + if (direct_fmt && !sd_fmt) + sd_fmt = direct_fmt; + + /* Step 5: if we are using a direct format, we need to package + * everything as 8 bit data and just dump it + */ + if (sd_fmt == direct_fmt) + rlp_dma_direct_dump = true; + + /* Step 6: We have no format. This can happen if the userspace + * requests some weird/invalid format. + * In this case, default to whatever we have + */ + if (!sd_fmt && !direct_fmt) { + sd_fmt = isc->user_formats[isc->num_user_formats - 1]; + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Sensor not supporting %.4s, using %.4s\n", + (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc); + } + + if (!sd_fmt) { + ret = -EINVAL; + goto isc_try_fmt_err; } + /* Step 7: Print out what we decided for debugging */ + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Preferring to have sensor using format %.4s\n", + (char *)&sd_fmt->fourcc); + + /* Step 8: at this moment we decided which format the subdev will use */ + isc->try_config.sd_format = sd_fmt; + /* Limit to Atmel ISC hardware capabilities */ if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) pixfmt->width = ISC_MAX_SUPPORT_WIDTH; if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; - if (sensor_is_preferred(isc_fmt)) - mbus_code = isc_fmt->mbus_code; - else - mbus_code = isc->raw_fmt->mbus_code; + /* + * The mbus format is the one the subdev outputs. + * The pixels will be transferred in this format Sensor -> ISC + */ + mbus_code = sd_fmt->mbus_code; + + /* + * Validate formats. If the required format is not OK, default to raw. + */ + + isc->try_config.fourcc = pixfmt->pixelformat; + + if (isc_try_validate_formats(isc)) { + pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc; + /* Re-try to validate the new format */ + ret = isc_try_validate_formats(isc); + if (ret) + goto isc_try_fmt_err; + } + + ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump); + if (ret) + goto isc_try_fmt_err; + + ret = isc_try_configure_pipeline(isc); + if (ret) + goto isc_try_fmt_err; v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) - return ret; + goto isc_try_fmt_err; v4l2_fill_pix_format(pixfmt, &format.format); pixfmt->field = V4L2_FIELD_NONE; - pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3; + pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3; pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - if (current_fmt) - *current_fmt = isc_fmt; - if (code) *code = mbus_code; return 0; + +isc_try_fmt_err: + v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); + memset(&isc->try_config, 0, sizeof(isc->try_config)); + + return ret; } static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) @@ -1346,11 +1427,10 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - struct isc_format *current_fmt; - u32 mbus_code; + u32 mbus_code = 0; int ret; - ret = isc_try_fmt(isc, f, ¤t_fmt, &mbus_code); + ret = isc_try_fmt(isc, f, &mbus_code); if (ret) return ret; @@ -1361,7 +1441,10 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) return ret; isc->fmt = *f; - isc->current_fmt = current_fmt; + /* make the try configuration active */ + isc->config = isc->try_config; + + v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); return 0; } @@ -1382,7 +1465,7 @@ static int isc_try_fmt_vid_cap(struct file *file, void *priv, { struct isc_device *isc = video_drvdata(file); - return isc_try_fmt(isc, f, NULL, NULL); + return isc_try_fmt(isc, f, NULL); } static int isc_enum_input(struct file *file, void *priv, @@ -1431,27 +1514,31 @@ static int isc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { struct isc_device *isc = video_drvdata(file); - const struct isc_format *isc_fmt; struct v4l2_subdev_frame_size_enum fse = { .index = fsize->index, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - int ret; + int ret = -EINVAL; + int i; - isc_fmt = find_format_by_fourcc(isc, fsize->pixel_format); - if (!isc_fmt) - return -EINVAL; + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fsize->pixel_format) + ret = 0; - if (sensor_is_preferred(isc_fmt)) - fse.code = isc_fmt->mbus_code; - else - fse.code = isc->raw_fmt->mbus_code; + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fsize->pixel_format) + ret = 0; + + if (ret) + return ret; ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, NULL, &fse); if (ret) return ret; + fse.code = isc->config.sd_format->mbus_code; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->discrete.width = fse.max_width; fsize->discrete.height = fse.max_height; @@ -1463,29 +1550,32 @@ static int isc_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { struct isc_device *isc = video_drvdata(file); - const struct isc_format *isc_fmt; struct v4l2_subdev_frame_interval_enum fie = { .index = fival->index, .width = fival->width, .height = fival->height, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - int ret; + int ret = -EINVAL; + int i; - isc_fmt = find_format_by_fourcc(isc, fival->pixel_format); - if (!isc_fmt) - return -EINVAL; + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fival->pixel_format) + ret = 0; - if (sensor_is_preferred(isc_fmt)) - fie.code = isc_fmt->mbus_code; - else - fie.code = isc->raw_fmt->mbus_code; + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fival->pixel_format) + ret = 0; + + if (ret) + return ret; ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_interval, NULL, &fie); if (ret) return ret; + fie.code = isc->config.sd_format->mbus_code; fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->discrete = fie.interval; @@ -1668,7 +1758,6 @@ static void isc_awb_work(struct work_struct *w) struct isc_device *isc = container_of(w, struct isc_device, awb_work); struct regmap *regmap = isc->regmap; - struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); struct isc_ctrls *ctrls = &isc->ctrls; u32 hist_id = ctrls->hist_id; u32 baysel; @@ -1686,7 +1775,7 @@ static void isc_awb_work(struct work_struct *w) } ctrls->hist_id = hist_id; - baysel = config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; + baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; pm_runtime_get_sync(isc->dev); @@ -1754,7 +1843,6 @@ static int isc_ctrl_init(struct isc_device *isc) return 0; } - static int isc_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1812,35 +1900,20 @@ static int isc_formats_init(struct isc_device *isc) .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; + num_fmts = 0; while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &mbus_code)) { mbus_code.index++; fmt = find_format_by_code(mbus_code.code, &i); - if ((!fmt) || (!(fmt->flags & FMT_FLAG_FROM_SENSOR))) + if (!fmt) { + v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", + mbus_code.code); continue; + } fmt->sd_support = true; - - if (fmt->flags & FMT_FLAG_RAW_FORMAT) - isc->raw_fmt = fmt; - } - - fmt = &formats_list[0]; - for (i = 0; i < list_size; i++) { - if (fmt->flags & FMT_FLAG_FROM_CONTROLLER) - fmt->isc_support = true; - - fmt++; - } - - fmt = &formats_list[0]; - num_fmts = 0; - for (i = 0; i < list_size; i++) { - if (fmt->isc_support || fmt->sd_support) - num_fmts++; - - fmt++; + num_fmts++; } if (!num_fmts) @@ -1855,9 +1928,8 @@ static int isc_formats_init(struct isc_device *isc) fmt = &formats_list[0]; for (i = 0, j = 0; i < list_size; i++) { - if (fmt->isc_support || fmt->sd_support) + if (fmt->sd_support) isc->user_formats[j++] = fmt; - fmt++; } @@ -1877,13 +1949,11 @@ static int isc_set_default_fmt(struct isc_device *isc) }; int ret; - ret = isc_try_fmt(isc, &f, NULL, NULL); + ret = isc_try_fmt(isc, &f, NULL); if (ret) return ret; - isc->current_fmt = isc->user_formats[0]; isc->fmt = f; - return 0; } @@ -2084,6 +2154,10 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; + if (v4l2_epn.bus_type == V4L2_MBUS_BT656) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; subdev_entity->asd->match.fwnode = of_fwnode_handle(rem); diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b4f396c2e72c..eaa86737fa04 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2010,6 +2010,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx) /* Clear decode success flag */ coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); + /* Clear error return value */ + coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); + trace_coda_dec_pic_run(ctx, meta); coda_command_async(ctx, CODA_COMMAND_PIC_RUN); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index fa0b22fb7991..3ce58dee4422 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -764,6 +764,7 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, { struct coda_ctx *ctx = fh_to_ctx(priv); struct coda_q_data *q_data_src; + const struct coda_codec *codec; struct v4l2_rect r; int ret; @@ -784,6 +785,15 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, if (ctx->inst_type != CODA_INST_ENCODER) return 0; + /* Setting the coded format determines the selected codec */ + codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + f->fmt.pix.pixelformat); + if (!codec) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); + return -EINVAL; + } + ctx->codec = codec; + ctx->colorspace = f->fmt.pix.colorspace; ctx->xfer_func = f->fmt.pix.xfer_func; ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; @@ -796,6 +806,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_codec *codec; struct v4l2_format f_cap; struct vb2_queue *dst_vq; int ret; @@ -808,14 +819,23 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, if (ret) return ret; - if (ctx->inst_type != CODA_INST_DECODER) - return 0; - ctx->colorspace = f->fmt.pix.colorspace; ctx->xfer_func = f->fmt.pix.xfer_func; ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; ctx->quantization = f->fmt.pix.quantization; + if (ctx->inst_type != CODA_INST_DECODER) + return 0; + + /* Setting the coded format determines the selected codec */ + codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, + V4L2_PIX_FMT_YUV420); + if (!codec) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); + return -EINVAL; + } + ctx->codec = codec; + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); if (!dst_vq) return -EINVAL; @@ -980,6 +1000,11 @@ static int coda_s_selection(struct file *file, void *fh, static int coda_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { + struct coda_ctx *ctx = fh_to_ctx(fh); + + if (ctx->inst_type != CODA_INST_ENCODER) + return -ENOTTY; + if (ec->cmd != V4L2_ENC_CMD_STOP) return -EINVAL; @@ -1000,10 +1025,6 @@ static int coda_encoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; - /* Ignore encoder stop command silently in decoder context */ - if (ctx->inst_type != CODA_INST_ENCODER) - return 0; - /* Set the stream-end flag on this context */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; @@ -1021,6 +1042,11 @@ static int coda_encoder_cmd(struct file *file, void *fh, static int coda_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { + struct coda_ctx *ctx = fh_to_ctx(fh); + + if (ctx->inst_type != CODA_INST_DECODER) + return -ENOTTY; + if (dc->cmd != V4L2_DEC_CMD_STOP) return -EINVAL; @@ -1043,10 +1069,6 @@ static int coda_decoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; - /* Ignore decoder stop command silently in encoder context */ - if (ctx->inst_type != CODA_INST_DECODER) - return 0; - /* Set the stream-end flag on this context */ coda_bit_stream_end_flag(ctx); ctx->hold = false; @@ -1055,6 +1077,42 @@ static int coda_decoder_cmd(struct file *file, void *fh, return 0; } +static int coda_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data_dst; + const struct coda_codec *codec; + + if (ctx->inst_type != CODA_INST_ENCODER) + return -ENOTTY; + + if (fsize->index) + return -EINVAL; + + if (coda_format_normalize_yuv(fsize->pixel_format) == + V4L2_PIX_FMT_YUV420) { + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(ctx->dev, fsize->pixel_format, + q_data_dst->fourcc); + } else { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + fsize->pixel_format); + } + if (!codec) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.max_width = codec->max_w; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_height = codec->max_h; + fsize->stepwise.step_height = 1; + + return 0; +} + static int coda_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *f) { @@ -1233,6 +1291,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_g_parm = coda_g_parm, .vidioc_s_parm = coda_s_parm, + .vidioc_enum_framesizes = coda_enum_framesizes, .vidioc_enum_frameintervals = coda_enum_frameintervals, .vidioc_subscribe_event = coda_subscribe_event, @@ -1442,6 +1501,9 @@ static int coda_queue_setup(struct vb2_queue *vq, q_data = get_q_data(ctx, vq->type); size = q_data->sizeimage; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; sizes[0] = size; @@ -1680,14 +1742,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) ctx->gopcounter = ctx->params.gop_size - 1; - ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - q_data_dst->fourcc); - if (!ctx->codec) { - v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); - ret = -EINVAL; - goto err; - } - if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) ctx->params.gop_size = 1; ctx->gopcounter = ctx->params.gop_size - 1; @@ -2015,7 +2069,6 @@ static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) static void coda_decode_ctrls(struct coda_ctx *ctx) { - u64 mask; u8 max; ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, @@ -2029,27 +2082,14 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; if (ctx->dev->devtype->product == CODA_HX4 || - ctx->dev->devtype->product == CODA_7541) { + ctx->dev->devtype->product == CODA_7541) max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)); - } else if (ctx->dev->devtype->product == CODA_960) { + else if (ctx->dev->devtype->product == CODA_960) max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; - mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1)); - } else { + else return; - } ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, mask, - max); + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); if (ctx->h264_level_ctrl) ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; } @@ -2063,11 +2103,17 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); if (ctx->inst_type == CODA_INST_ENCODER) { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 1, 1, 1, 1); if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) coda_jpeg_encode_ctrls(ctx); else coda_encode_ctrls(ctx); } else { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 1, 1, 1, 1); if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264) coda_decode_ctrls(ctx); } diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c index 7bc4d8a9af28..068df9888dbf 100644 --- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c +++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c @@ -236,6 +236,7 @@ static int cros_ec_cec_get_notifier(struct device *dev, return -EPROBE_DEFER; *notify = cec_notifier_get_conn(d, m->conn); + put_device(d); return 0; } } diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 47cecd10eb9f..2dee9af6d413 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -884,9 +884,7 @@ static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) static int isif_config_ycbcr(void) { struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - struct vpss_pg_frame_size frame_size; u32 modeset = 0, ccdcfg = 0; - struct vpss_sync_pol sync; dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); @@ -974,13 +972,6 @@ static int isif_config_ycbcr(void) /* two fields are interleaved in memory */ regw(0x00000249, SDOFST); - /* Setup test pattern if enabled */ - if (isif_cfg.bayer.config_params.test_pat_gen) { - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - dm365_vpss_set_pg_frame_size(frame_size); - } return 0; } diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 26dadbba930f..1e3a13830544 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1759,7 +1759,7 @@ static int vpfe_probe(struct platform_device *pdev) mutex_lock(&ccdc_lock); - strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); + strscpy(ccdc_cfg->name, vpfe_cfg->ccdc, sizeof(ccdc_cfg->name)); /* Get VINT0 irq resource */ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res1) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 6216b7ac6875..b5aacb0fb96b 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1254,7 +1254,8 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } else { std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); } - strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); + strscpy(std_info->name, "Custom timings BT656/1120", + sizeof(std_info->name)); std_info->width = bt->width; std_info->height = bt->height; std_info->frm_fmt = bt->interlaced ? 0 : 1; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index f4b4f2a1dfc0..a69897c68a50 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -987,8 +987,8 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } else { std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); } - strncpy(std_info->name, "Custom timings BT656/1120", - VPIF_MAX_NAME); + strscpy(std_info->name, "Custom timings BT656/1120", + sizeof(std_info->name)); std_info->width = bt->width; std_info->height = bt->height; std_info->frm_fmt = bt->interlaced ? 0 : 1; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 3e9fcf4f8a13..de4af0357a3c 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -742,7 +742,7 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, f->index); if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8) f->flags |= V4L2_FMT_FLAG_COMPRESSED; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 61c8177409cf..1bea1ce4091e 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -252,7 +252,7 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 0bcfc5aa8f3d..8e7ef23b9a7e 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -1025,8 +1025,8 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id) static int pxp_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); - strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", MEM2MEM_NAME); return 0; diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index cf12e077203a..cd88e2eed749 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -5,7 +5,7 @@ config VIDEO_CAFE_CCIC select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG - ---help--- + help This is a video4linux2 driver for the Marvell 88ALP01 integrated CMOS camera controller. This is the controller found on first- generation OLPC systems. @@ -19,7 +19,7 @@ config VIDEO_MMP_CAMERA select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG - ---help--- + help This is a Video4Linux2 driver for the integrated camera controller found on Marvell Armada 610 application processors (and likely beyond). This is the controller found diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile index 597beb8f34d1..f611c23c3718 100644 --- a/drivers/media/platform/meson/Makefile +++ b/drivers/media/platform/meson/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o +obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c new file mode 100644 index 000000000000..3620a1e310f5 --- /dev/null +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -0,0 +1,779 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Amlogic Meson AO CEC G12A Controller + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/reset.h> +#include <linux/slab.h> +#include <linux/regmap.h> +#include <media/cec.h> +#include <media/cec-notifier.h> +#include <linux/clk-provider.h> + +/* CEC Registers */ + +#define CECB_CLK_CNTL_REG0 0x00 + +#define CECB_CLK_CNTL_N1 GENMASK(11, 0) +#define CECB_CLK_CNTL_N2 GENMASK(23, 12) +#define CECB_CLK_CNTL_DUAL_EN BIT(28) +#define CECB_CLK_CNTL_OUTPUT_EN BIT(30) +#define CECB_CLK_CNTL_INPUT_EN BIT(31) + +#define CECB_CLK_CNTL_REG1 0x04 + +#define CECB_CLK_CNTL_M1 GENMASK(11, 0) +#define CECB_CLK_CNTL_M2 GENMASK(23, 12) +#define CECB_CLK_CNTL_BYPASS_EN BIT(24) + +/* + * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal + * change pulse width < filter_del * T(filter_tick) * 3. + * [9:8] Filter_tick_sel: Select which periodical pulse for + * glitch-filtering CEC line signal. + * - 0=Use T(xtal)*3 = 125ns; + * - 1=Use once-per-1us pulse; + * - 2=Use once-per-10us pulse; + * - 3=Use once-per-100us pulse. + * [3] Sysclk_en. 0=Disable system clock; 1=Enable system clock. + * [2:1] cntl_clk + * - 0 = Disable clk (Power-off mode) + * - 1 = Enable gated clock (Normal mode) + * - 2 = Enable free-run clk (Debug mode) + * [0] SW_RESET 1=Apply reset; 0=No reset. + */ +#define CECB_GEN_CNTL_REG 0x08 + +#define CECB_GEN_CNTL_RESET BIT(0) +#define CECB_GEN_CNTL_CLK_DISABLE 0 +#define CECB_GEN_CNTL_CLK_ENABLE 1 +#define CECB_GEN_CNTL_CLK_ENABLE_DBG 2 +#define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) +#define CECB_GEN_CNTL_SYS_CLK_EN BIT(3) +#define CECB_GEN_CNTL_FILTER_TICK_125NS 0 +#define CECB_GEN_CNTL_FILTER_TICK_1US 1 +#define CECB_GEN_CNTL_FILTER_TICK_10US 2 +#define CECB_GEN_CNTL_FILTER_TICK_100US 3 +#define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8) +#define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12) + +/* + * [7:0] cec_reg_addr + * [15:8] cec_reg_wrdata + * [16] cec_reg_wr + * - 0 = Read + * - 1 = Write + * [31:24] cec_reg_rddata + */ +#define CECB_RW_REG 0x0c + +#define CECB_RW_ADDR GENMASK(7, 0) +#define CECB_RW_WR_DATA GENMASK(15, 8) +#define CECB_RW_WRITE_EN BIT(16) +#define CECB_RW_BUS_BUSY BIT(23) +#define CECB_RW_RD_DATA GENMASK(31, 24) + +/* + * [0] DONE Interrupt + * [1] End Of Message Interrupt + * [2] Not Acknowlegde Interrupt + * [3] Arbitration Loss Interrupt + * [4] Initiator Error Interrupt + * [5] Follower Error Interrupt + * [6] Wake-Up Interrupt + */ +#define CECB_INTR_MASKN_REG 0x10 +#define CECB_INTR_CLR_REG 0x14 +#define CECB_INTR_STAT_REG 0x18 + +#define CECB_INTR_DONE BIT(0) +#define CECB_INTR_EOM BIT(1) +#define CECB_INTR_NACK BIT(2) +#define CECB_INTR_ARB_LOSS BIT(3) +#define CECB_INTR_INITIATOR_ERR BIT(4) +#define CECB_INTR_FOLLOWER_ERR BIT(5) +#define CECB_INTR_WAKE_UP BIT(6) + +/* CEC Commands */ + +#define CECB_CTRL 0x00 + +#define CECB_CTRL_SEND BIT(0) +#define CECB_CTRL_TYPE GENMASK(2, 1) +#define CECB_CTRL_TYPE_RETRY 0 +#define CECB_CTRL_TYPE_NEW 1 +#define CECB_CTRL_TYPE_NEXT 2 + +#define CECB_CTRL2 0x01 +#define CECB_INTR_MASK 0x02 +#define CECB_LADD_LOW 0x05 +#define CECB_LADD_HIGH 0x06 +#define CECB_TX_CNT 0x07 +#define CECB_RX_CNT 0x08 +#define CECB_STAT0 0x09 +#define CECB_TX_DATA00 0x10 +#define CECB_TX_DATA01 0x11 +#define CECB_TX_DATA02 0x12 +#define CECB_TX_DATA03 0x13 +#define CECB_TX_DATA04 0x14 +#define CECB_TX_DATA05 0x15 +#define CECB_TX_DATA06 0x16 +#define CECB_TX_DATA07 0x17 +#define CECB_TX_DATA08 0x18 +#define CECB_TX_DATA09 0x19 +#define CECB_TX_DATA10 0x1A +#define CECB_TX_DATA11 0x1B +#define CECB_TX_DATA12 0x1C +#define CECB_TX_DATA13 0x1D +#define CECB_TX_DATA14 0x1E +#define CECB_TX_DATA15 0x1F +#define CECB_RX_DATA00 0x20 +#define CECB_RX_DATA01 0x21 +#define CECB_RX_DATA02 0x22 +#define CECB_RX_DATA03 0x23 +#define CECB_RX_DATA04 0x24 +#define CECB_RX_DATA05 0x25 +#define CECB_RX_DATA06 0x26 +#define CECB_RX_DATA07 0x27 +#define CECB_RX_DATA08 0x28 +#define CECB_RX_DATA09 0x29 +#define CECB_RX_DATA10 0x2A +#define CECB_RX_DATA11 0x2B +#define CECB_RX_DATA12 0x2C +#define CECB_RX_DATA13 0x2D +#define CECB_RX_DATA14 0x2E +#define CECB_RX_DATA15 0x2F +#define CECB_LOCK_BUF 0x30 + +#define CECB_LOCK_BUF_EN BIT(0) + +#define CECB_WAKEUPCTRL 0x31 + +struct meson_ao_cec_g12a_device { + struct platform_device *pdev; + struct regmap *regmap; + struct regmap *regmap_cec; + spinlock_t cec_reg_lock; + struct cec_notifier *notify; + struct cec_adapter *adap; + struct cec_msg rx_msg; + struct clk *oscin; + struct clk *core; +}; + +static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = CECB_INTR_STAT_REG, +}; + +/* + * The AO-CECB embeds a dual/divider to generate a more precise + * 32,768KHz clock for CEC core clock. + * ______ ______ + * | | | | + * ______ | Div1 |-| Cnt1 | ______ + * | | /|______| |______|\ | | + * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> + * |______| | \| | | |/ | |______| + * | | Div2 |-| Cnt2 | | + * | |______| |______| | + * |_______________________| + * + * The dividing can be switched to single or dual, with a counter + * for each divider to set when the switching is done. + * The entire dividing mechanism can be also bypassed. + */ + +struct meson_ao_cec_g12a_dualdiv_clk { + struct clk_hw hw; + struct regmap *regmap; +}; + +#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \ + container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \ + +static unsigned long +meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + unsigned long n1; + u32 reg0, reg1; + + regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0); + regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1); + + if (reg1 & CECB_CLK_CNTL_BYPASS_EN) + return parent_rate; + + if (reg0 & CECB_CLK_CNTL_DUAL_EN) { + unsigned long n2, m1, m2, f1, f2, p1, p2; + + n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; + n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1; + + m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; + m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; + + f1 = DIV_ROUND_CLOSEST(parent_rate, n1); + f2 = DIV_ROUND_CLOSEST(parent_rate, n2); + + p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); + p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); + + return DIV_ROUND_UP(100000000, p1 + p2); + } + + n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; + + return DIV_ROUND_CLOSEST(parent_rate, n1); +} + +static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + + + /* Disable Input & Output */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, + 0); + + /* Set N1 & N2 */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_N1, + FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1)); + + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_N2, + FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1)); + + /* Set M1 & M2 */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, + CECB_CLK_CNTL_M1, + FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1)); + + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, + CECB_CLK_CNTL_M2, + FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1)); + + /* Enable Dual divisor */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN); + + /* Disable divisor bypass */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, + CECB_CLK_CNTL_BYPASS_EN, 0); + + /* Enable Input & Output */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN); + + return 0; +} + +static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, + 0); +} + +static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + int val; + + regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val); + + return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN)); +} + +static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = { + .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate, + .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled, + .enable = meson_ao_cec_g12a_dualdiv_clk_enable, + .disable = meson_ao_cec_g12a_dualdiv_clk_disable, +}; + +static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk; + struct device *dev = &ao_cec->pdev->dev; + struct clk_init_data init; + const char *parent_name; + struct clk *clk; + char *name; + + dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL); + if (!dualdiv_clk) + return -ENOMEM; + + name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev)); + if (!name) + return -ENOMEM; + + parent_name = __clk_get_name(ao_cec->oscin); + + init.name = name; + init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + dualdiv_clk->regmap = ao_cec->regmap; + dualdiv_clk->hw.init = &init; + + clk = devm_clk_register(dev, &dualdiv_clk->hw); + kfree(name); + if (IS_ERR(clk)) { + dev_err(dev, "failed to register clock\n"); + return PTR_ERR(clk); + } + + ao_cec->core = clk; + + return 0; +} + +static int meson_ao_cec_g12a_read(void *context, unsigned int addr, + unsigned int *data) +{ + struct meson_ao_cec_g12a_device *ao_cec = context; + u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); + + ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); + if (ret) + goto read_out; + + ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, + !(reg & CECB_RW_BUS_BUSY), + 5, 1000); + if (ret) + goto read_out; + + ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); + + *data = FIELD_GET(CECB_RW_RD_DATA, reg); + +read_out: + spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); + + return ret; +} + +static int meson_ao_cec_g12a_write(void *context, unsigned int addr, + unsigned int data) +{ + struct meson_ao_cec_g12a_device *ao_cec = context; + unsigned long flags; + u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | + FIELD_PREP(CECB_RW_WR_DATA, data) | + CECB_RW_WRITE_EN; + int ret = 0; + + spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); + + ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); + + spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); + + return ret; +} + +static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .reg_read = meson_ao_cec_g12a_read, + .reg_write = meson_ao_cec_g12a_write, + .max_register = 0xffff, + .fast_io = true, +}; + +static inline void +meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec, + bool enable) +{ + u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK | + CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR | + CECB_INTR_FOLLOWER_ERR; + + regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, + enable ? cfg : 0); +} + +static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec) +{ + int i, ret = 0; + u32 val; + + ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); + + ao_cec->rx_msg.len = val; + if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) + ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; + + for (i = 0; i < ao_cec->rx_msg.len; i++) { + ret |= regmap_read(ao_cec->regmap_cec, + CECB_RX_DATA00 + i, &val); + + ao_cec->rx_msg.msg[i] = val & 0xff; + } + + ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); + if (ret) + return; + + cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); +} + +static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data) +{ + struct meson_ao_cec_g12a_device *ao_cec = data; + u32 stat; + + regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); + if (stat) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data) +{ + struct meson_ao_cec_g12a_device *ao_cec = data; + u32 stat; + + regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); + regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); + + if (stat & CECB_INTR_DONE) + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); + + if (stat & CECB_INTR_EOM) + meson_ao_cec_g12a_irq_rx(ao_cec); + + if (stat & CECB_INTR_NACK) + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); + + if (stat & CECB_INTR_ARB_LOSS) { + regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); + regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, + CECB_CTRL_SEND | CECB_CTRL_TYPE, 0); + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); + } + + /* Initiator reports an error on the CEC bus */ + if (stat & CECB_INTR_INITIATOR_ERR) + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); + + /* Follower reports a receive error, just reset RX buffer */ + if (stat & CECB_INTR_FOLLOWER_ERR) + regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); + + return IRQ_HANDLED; +} + +static int +meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct meson_ao_cec_g12a_device *ao_cec = adap->priv; + int ret = 0; + + if (logical_addr == CEC_LOG_ADDR_INVALID) { + /* Assume this will allways succeed */ + regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); + regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); + + return 0; + } else if (logical_addr < 8) { + ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, + BIT(logical_addr), + BIT(logical_addr)); + } else { + ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, + BIT(logical_addr - 8), + BIT(logical_addr - 8)); + } + + /* Always set Broadcast/Unregistered 15 address */ + ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, + BIT(CEC_LOG_ADDR_UNREGISTERED - 8), + BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); + + return ret ? -EIO : 0; +} + +static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct meson_ao_cec_g12a_device *ao_cec = adap->priv; + unsigned int type; + int ret = 0; + u32 val; + int i; + + /* Check if RX is in progress */ + ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); + if (ret) + return ret; + if (val & CECB_LOCK_BUF_EN) + return -EBUSY; + + /* Check if TX Busy */ + ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); + if (ret) + return ret; + if (val & CECB_CTRL_SEND) + return -EBUSY; + + switch (signal_free_time) { + case CEC_SIGNAL_FREE_TIME_RETRY: + type = CECB_CTRL_TYPE_RETRY; + break; + case CEC_SIGNAL_FREE_TIME_NEXT_XFER: + type = CECB_CTRL_TYPE_NEXT; + break; + case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: + default: + type = CECB_CTRL_TYPE_NEW; + break; + } + + for (i = 0; i < msg->len; i++) + ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, + msg->msg[i]); + + ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); + if (ret) + return -EIO; + + ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, + CECB_CTRL_SEND | + CECB_CTRL_TYPE, + CECB_CTRL_SEND | + FIELD_PREP(CECB_CTRL_TYPE, type)); + + return ret; +} + +static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct meson_ao_cec_g12a_device *ao_cec = adap->priv; + + meson_ao_cec_g12a_irq_setup(ao_cec, false); + + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET); + + if (!enable) + return 0; + + /* Setup Filter */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_FILTER_TICK_SEL | + CECB_GEN_CNTL_FILTER_DEL, + FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL, + CECB_GEN_CNTL_FILTER_TICK_1US) | + FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7)); + + /* Enable System Clock */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_SYS_CLK_EN, + CECB_GEN_CNTL_SYS_CLK_EN); + + /* Enable gated clock (Normal mode). */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_CLK_CTRL_MASK, + FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK, + CECB_GEN_CNTL_CLK_ENABLE)); + + /* Release Reset */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_RESET, 0); + + meson_ao_cec_g12a_irq_setup(ao_cec, true); + + return 0; +} + +static const struct cec_adap_ops meson_ao_cec_g12a_ops = { + .adap_enable = meson_ao_cec_g12a_adap_enable, + .adap_log_addr = meson_ao_cec_g12a_set_log_addr, + .adap_transmit = meson_ao_cec_g12a_transmit, +}; + +static int meson_ao_cec_g12a_probe(struct platform_device *pdev) +{ + struct meson_ao_cec_g12a_device *ao_cec; + struct device *hdmi_dev; + struct resource *res; + void __iomem *base; + int ret, irq; + + hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + + ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); + if (!ao_cec) + return -ENOMEM; + + spin_lock_init(&ao_cec->cec_reg_lock); + ao_cec->pdev = pdev; + + ao_cec->notify = cec_notifier_get(hdmi_dev); + if (!ao_cec->notify) + return -ENOMEM; + + ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, + "meson_g12a_ao_cec", + CEC_CAP_DEFAULTS, + CEC_MAX_LOG_ADDRS); + if (IS_ERR(ao_cec->adap)) { + ret = PTR_ERR(ao_cec->adap); + goto out_probe_notify; + } + + ao_cec->adap->owner = THIS_MODULE; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto out_probe_adapter; + } + + ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &meson_ao_cec_g12a_regmap_conf); + if (IS_ERR(ao_cec->regmap)) { + ret = PTR_ERR(ao_cec->regmap); + goto out_probe_adapter; + } + + ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, + &meson_ao_cec_g12a_cec_regmap_conf); + if (IS_ERR(ao_cec->regmap_cec)) { + ret = PTR_ERR(ao_cec->regmap_cec); + goto out_probe_adapter; + } + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, + meson_ao_cec_g12a_irq, + meson_ao_cec_g12a_irq_thread, + 0, NULL, ao_cec); + if (ret) { + dev_err(&pdev->dev, "irq request failed\n"); + goto out_probe_adapter; + } + + ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); + if (IS_ERR(ao_cec->oscin)) { + dev_err(&pdev->dev, "oscin clock request failed\n"); + ret = PTR_ERR(ao_cec->oscin); + goto out_probe_adapter; + } + + ret = meson_ao_cec_g12a_setup_clk(ao_cec); + if (ret) + goto out_probe_adapter; + + ret = clk_prepare_enable(ao_cec->core); + if (ret) { + dev_err(&pdev->dev, "core clock enable failed\n"); + goto out_probe_adapter; + } + + device_reset_optional(&pdev->dev); + + platform_set_drvdata(pdev, ao_cec); + + ret = cec_register_adapter(ao_cec->adap, &pdev->dev); + if (ret < 0) { + cec_notifier_put(ao_cec->notify); + goto out_probe_core_clk; + } + + /* Setup Hardware */ + regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); + + cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); + + return 0; + +out_probe_core_clk: + clk_disable_unprepare(ao_cec->core); + +out_probe_adapter: + cec_delete_adapter(ao_cec->adap); + +out_probe_notify: + cec_notifier_put(ao_cec->notify); + + dev_err(&pdev->dev, "CEC controller registration failed\n"); + + return ret; +} + +static int meson_ao_cec_g12a_remove(struct platform_device *pdev) +{ + struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(ao_cec->core); + + cec_unregister_adapter(ao_cec->adap); + + cec_notifier_put(ao_cec->notify); + + return 0; +} + +static const struct of_device_id meson_ao_cec_g12a_of_match[] = { + { .compatible = "amlogic,meson-g12a-ao-cec", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); + +static struct platform_driver meson_ao_cec_g12a_driver = { + .probe = meson_ao_cec_g12a_probe, + .remove = meson_ao_cec_g12a_remove, + .driver = { + .name = "meson-ao-cec-g12a", + .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), + }, +}; + +module_platform_driver(meson_ao_cec_g12a_driver); + +MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver"); +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c index cd4be38ab5ac..facf9b029e79 100644 --- a/drivers/media/platform/meson/ao-cec.c +++ b/drivers/media/platform/meson/ao-cec.c @@ -601,20 +601,14 @@ static const struct cec_adap_ops meson_ao_cec_ops = { static int meson_ao_cec_probe(struct platform_device *pdev) { struct meson_ao_cec_device *ao_cec; - struct platform_device *hdmi_dev; - struct device_node *np; + struct device *hdmi_dev; struct resource *res; int ret, irq; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node\n"); - return -ENODEV; - } + hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - hdmi_dev = of_find_device_by_node(np); - if (hdmi_dev == NULL) - return -EPROBE_DEFER; + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); if (!ao_cec) @@ -622,7 +616,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) spin_lock_init(&ao_cec->cec_reg_lock); - ao_cec->notify = cec_notifier_get(&hdmi_dev->dev); + ao_cec->notify = cec_notifier_get(hdmi_dev); if (!ao_cec->notify) return -ENOMEM; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index d022c65bb34c..851903867bc9 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -129,11 +129,9 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) mutex_lock(&ctx->lock); if (dstbuf->used) { vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, - ctx->picinfo.y_bs_sz); + ctx->picinfo.fb_sz[0]); vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, - ctx->picinfo.c_bs_sz); - - dstbuf->ready_to_display = true; + ctx->picinfo.fb_sz[1]); mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", @@ -278,6 +276,27 @@ static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) clean_free_buffer(ctx); } +static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, + unsigned int pixelformat) +{ + struct mtk_video_fmt *fmt; + struct mtk_q_data *dst_q_data; + unsigned int k; + + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &mtk_video_formats[k]; + if (fmt->fourcc == pixelformat) { + mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", + dst_q_data->fmt.fourcc, pixelformat); + dst_q_data->fmt = fmt; + return; + } + } + + mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat); +} + static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) { unsigned int dpbsize = 0; @@ -299,6 +318,10 @@ static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) return -EINVAL; } + if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc && + ctx->picinfo.cap_fourcc != 0) + mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc); + if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) return 0; @@ -352,11 +375,11 @@ static void mtk_vdec_worker(struct work_struct *work) pfb = &dst_buf_info->frame_buffer; pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz; + pfb->base_y.size = ctx->picinfo.fb_sz[0]; pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); - pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz; + pfb->base_c.size = ctx->picinfo.fb_sz[1]; pfb->status = 0; mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); @@ -388,7 +411,7 @@ static void mtk_vdec_worker(struct work_struct *work) } buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - buf.size = (size_t)src_buf->planes[0].bytesused; + buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; if (!buf.va) { v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", @@ -976,14 +999,13 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv, * So we just return picinfo yet, and update picinfo in * stop_streaming hook function */ - q_data->sizeimage[0] = ctx->picinfo.y_bs_sz + - ctx->picinfo.y_len_sz; - q_data->sizeimage[1] = ctx->picinfo.c_bs_sz + - ctx->picinfo.c_len_sz; + q_data->sizeimage[0] = ctx->picinfo.fb_sz[0]; + q_data->sizeimage[1] = ctx->picinfo.fb_sz[1]; q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w; q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w; q_data->coded_width = ctx->picinfo.buf_w; q_data->coded_height = ctx->picinfo.buf_h; + ctx->last_decoded_picinfo.cap_fourcc = q_data->fmt->fourcc; /* * Width and height are set to the dimensions @@ -1103,10 +1125,11 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) struct mtk_vcodec_mem src_mem; bool res_chg = false; int ret = 0; - unsigned int dpbsize = 1; + unsigned int dpbsize = 1, i = 0; struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2_v4l2 = NULL; struct mtk_video_dec_buf *buf = NULL; + struct mtk_q_data *dst_q_data; mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb->vb2_queue->type, @@ -1122,11 +1145,9 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); buf->queued_in_vb2 = true; buf->queued_in_v4l2 = true; - buf->ready_to_display = false; } else { buf->queued_in_vb2 = false; buf->queued_in_v4l2 = true; - buf->ready_to_display = false; } mutex_unlock(&ctx->lock); return; @@ -1155,10 +1176,10 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - src_mem.size = (size_t)src_buf->planes[0].bytesused; + src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; mtk_v4l2_debug(2, "[%d] buf id=%d va=%p dma=%pad size=%zx", - ctx->id, src_buf->index, + ctx->id, src_buf->vb2_buf.index, src_mem.va, &src_mem.dma_addr, src_mem.size); @@ -1182,7 +1203,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) } mtk_v4l2_debug(ret ? 0 : 1, "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", - ctx->id, src_buf->index, + ctx->id, src_buf->vb2_buf.index, src_mem.size, ret, res_chg); return; } @@ -1194,21 +1215,18 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) } ctx->last_decoded_picinfo = ctx->picinfo; - ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = - ctx->picinfo.y_bs_sz + - ctx->picinfo.y_len_sz; - ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = - ctx->picinfo.buf_w; - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] = - ctx->picinfo.c_bs_sz + - ctx->picinfo.c_len_sz; - ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = ctx->picinfo.buf_w; + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (i = 0; i < dst_q_data->fmt->num_planes; i++) { + dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i]; + dst_q_data->bytesperline[i] = ctx->picinfo.buf_w; + } + mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", ctx->id, ctx->picinfo.buf_w, ctx->picinfo.buf_h, ctx->picinfo.pic_w, ctx->picinfo.pic_h, - ctx->q_data[MTK_Q_DATA_DST].sizeimage[0], - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]); + dst_q_data->sizeimage[0], + dst_q_data->sizeimage[1]); ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); if (dpbsize == 0) @@ -1253,7 +1271,6 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { buf->used = false; - buf->ready_to_display = false; buf->queued_in_v4l2 = false; } else { buf->lastframe = false; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index dc4fc1df63c5..e4984edec4f8 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -45,7 +45,6 @@ struct vdec_fb { * @list: link list * @used: Capture buffer contain decoded frame data and keep in * codec data structure - * @ready_to_display: Capture buffer not display yet * @queued_in_vb2: Capture buffer is queue in vb2 * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 * queue yet @@ -60,7 +59,6 @@ struct mtk_video_dec_buf { struct list_head list; bool used; - bool ready_to_display; bool queued_in_vb2; bool queued_in_v4l2; bool lastframe; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index e7e2a108def9..662a84b822af 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -211,24 +211,20 @@ struct mtk_vcodec_pm { * @pic_h: picture height * @buf_w: picture buffer width (64 aligned up from pic_w) * @buf_h: picture buffer heiht (64 aligned up from pic_h) - * @y_bs_sz: Y bitstream size - * @c_bs_sz: CbCr bitstream size - * @y_len_sz: additional size required to store decompress information for y - * plane - * @c_len_sz: additional size required to store decompress information for cbcr - * plane + * @fb_sz: bitstream size of each plane * E.g. suppose picture size is 176x144, * buffer size will be aligned to 176x160. + * @cap_fourcc: fourcc number(may changed when resolution change) + * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os. */ struct vdec_pic_info { unsigned int pic_w; unsigned int pic_h; unsigned int buf_w; unsigned int buf_h; - unsigned int y_bs_sz; - unsigned int c_bs_sz; - unsigned int y_len_sz; - unsigned int c_len_sz; + unsigned int fb_sz[VIDEO_MAX_PLANES]; + unsigned int cap_fourcc; + unsigned int reserved; }; /** diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index c6b48b5925fb..50351adafc47 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -894,7 +894,7 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { - dst_buf->planes[0].bytesused = 0; + dst_buf->vb2_buf.planes[0].bytesused = 0; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } } else { @@ -947,7 +947,7 @@ static int mtk_venc_encode_header(void *priv) bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - bs_buf.size = (size_t)dst_buf->planes[0].length; + bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length; mtk_v4l2_debug(1, "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu", @@ -976,7 +976,7 @@ static int mtk_venc_encode_header(void *priv) } ctx->state = MTK_STATE_HEADER; - dst_buf->planes[0].bytesused = enc_result.bs_size; + dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); return 0; @@ -1107,12 +1107,12 @@ static void mtk_venc_worker(struct work_struct *work) if (ret) { v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - dst_buf->planes[0].bytesused = 0; + dst_buf->vb2_buf.planes[0].bytesused = 0; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); mtk_v4l2_err("venc_if_encode failed=%d", ret); } else { v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - dst_buf->planes[0].bytesused = enc_result.bs_size; + dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); mtk_v4l2_debug(2, "venc_if_encode bs size=%d", enc_result.bs_size); diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index 02c960c63ac0..cdbcd6909728 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -253,8 +253,8 @@ static void get_pic_info(struct vdec_h264_inst *inst, *pic = inst->vsi->pic; mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); - mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, - pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + pic->fb_sz[0], pic->fb_sz[1]); } static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr) diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index bac3723038de..ba79136421ef 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -294,8 +294,8 @@ static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic) mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); - mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, - pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + pic->fb_sz[0], pic->fb_sz[1]); } static void vp8_dec_finish(struct vdec_vp8_inst *inst) diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index bc8349bc2e80..939ea14bf6c5 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -481,15 +481,15 @@ static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst) */ if ((frm_to_show->fb != NULL) && (inst->cur_fb->base_y.size >= - frm_to_show->fb->base_y.size)) { + frm_to_show->fb->base_y.size) && + (inst->cur_fb->base_c.size >= + frm_to_show->fb->base_c.size)) { memcpy((void *)inst->cur_fb->base_y.va, (void *)frm_to_show->fb->base_y.va, - vsi->buf_w * - vsi->buf_h); + frm_to_show->fb->base_y.size); memcpy((void *)inst->cur_fb->base_c.va, (void *)frm_to_show->fb->base_c.va, - vsi->buf_w * - vsi->buf_h / 2); + frm_to_show->fb->base_c.size); } else { /* After resolution change case, current CAPTURE buffer * may have less buffer size than frm_to_show buffer @@ -702,10 +702,8 @@ static void init_all_fb_lists(struct vdec_vp9_inst *inst) static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic) { - pic->y_bs_sz = inst->vsi->buf_sz_y_bs; - pic->c_bs_sz = inst->vsi->buf_sz_c_bs; - pic->y_len_sz = inst->vsi->buf_len_sz_y; - pic->c_len_sz = inst->vsi->buf_len_sz_c; + pic->fb_sz[0] = inst->vsi->buf_sz_y_bs + inst->vsi->buf_len_sz_y; + pic->fb_sz[1] = inst->vsi->buf_sz_c_bs + inst->vsi->buf_len_sz_c; pic->pic_w = inst->vsi->pic_w; pic->pic_h = inst->vsi->pic_h; @@ -714,8 +712,9 @@ static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic) mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); - mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, - pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + pic->fb_sz[0], + pic->fb_sz[1]); } static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb) @@ -895,7 +894,7 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, if (vsi->resolution_changed) { if (!vp9_alloc_work_buf(inst)) { - ret = -EINVAL; + ret = -EIO; goto DECODE_ERROR; } } @@ -924,14 +923,12 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, if (vsi->show_existing_frame && (vsi->frm_to_show_idx < VP9_MAX_FRM_BUF_NUM)) { - mtk_vcodec_err(inst, + mtk_vcodec_debug(inst, "Skip Decode drv->new_fb_idx=%d, drv->frm_to_show_idx=%d", vsi->new_fb_idx, vsi->frm_to_show_idx); vp9_ref_cnt_fb(inst, &vsi->new_fb_idx, vsi->frm_to_show_idx); - ret = -EINVAL; - goto DECODE_ERROR; } /* VPU assign the buffer pointer in its address space, diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index b6602490a247..46c45f93c977 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -614,7 +614,7 @@ static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv) struct vpu_run *run = (struct vpu_run *)data; vpu->run.signaled = run->signaled; - strncpy(vpu->run.fw_ver, run->fw_ver, VPU_FW_VER_LEN); + strscpy(vpu->run.fw_ver, run->fw_ver, sizeof(vpu->run.fw_ver)); vpu->run.dec_capability = run->dec_capability; vpu->run.enc_capability = run->enc_capability; wake_up_interruptible(&vpu->run.wq); diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index f60f499c596b..e100b30bb6f5 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -385,8 +385,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 4b5e55d41ad4..30ce2ba120a1 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -14,5 +14,5 @@ config VIDEO_OMAP2_VOUT select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FRAME_VECTOR default n - ---help--- + help V4L2 Display driver support for OMAP2/3 based boards. diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 4fe228752a43..a632f06d9fff 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2350,7 +2350,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - remote = of_graph_get_remote_port(np); + remote = of_graph_get_remote_port_parent(np); if (remote) asd->match.fwnode = of_fwnode_handle(remote); else diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index 15804ad7e65d..34ea503a9842 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -569,7 +569,7 @@ struct hfi_capability { struct hfi_capabilities { u32 num_capabilities; - struct hfi_capability data[1]; + struct hfi_capability *data; }; #define HFI_DEBUG_MSG_LOW 0x01 @@ -726,7 +726,7 @@ struct hfi_profile_level { struct hfi_profile_level_supported { u32 profile_count; - struct hfi_profile_level profile_level[1]; + struct hfi_profile_level *profile_level; }; struct hfi_quality_vs_speed { diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig index e3eb8fee2536..240ac3f3c941 100644 --- a/drivers/media/platform/rcar-vin/Kconfig +++ b/drivers/media/platform/rcar-vin/Kconfig @@ -3,6 +3,7 @@ config VIDEO_RCAR_CSI2 tristate "R-Car MIPI CSI-2 Receiver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF depends on ARCH_RENESAS || COMPILE_TEST + select RESET_CONTROLLER select V4L2_FWNODE help Support for Renesas R-Car MIPI CSI-2 receiver. @@ -17,7 +18,7 @@ config VIDEO_RCAR_VIN depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help Support for Renesas R-Car Video Input (VIN) driver. Supports R-Car Gen2 and Gen3 SoCs. diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 594d80434004..64f9cf790445 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -546,7 +546,9 @@ static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name); + mutex_lock(&vin->lock); rvin_parallel_subdevice_detach(vin); + mutex_unlock(&vin->lock); } static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, @@ -556,7 +558,9 @@ static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); int ret; + mutex_lock(&vin->lock); ret = rvin_parallel_subdevice_attach(vin, subdev); + mutex_unlock(&vin->lock); if (ret) return ret; @@ -664,6 +668,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) } /* Create all media device links between VINs and CSI-2's. */ + mutex_lock(&vin->group->lock); for (route = vin->info->routes; route->mask; route++) { struct media_pad *source_pad, *sink_pad; struct media_entity *source, *sink; @@ -699,6 +704,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) break; } } + mutex_unlock(&vin->group->lock); return ret; } @@ -714,6 +720,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, if (vin->group->vin[i]) rvin_v4l2_unregister(vin->group->vin[i]); + mutex_lock(&vin->group->lock); + for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -721,6 +729,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); break; } + + mutex_unlock(&vin->group->lock); } static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, @@ -730,6 +740,8 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); unsigned int i; + mutex_lock(&vin->group->lock); + for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -738,6 +750,8 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, break; } + mutex_unlock(&vin->group->lock); + return 0; } @@ -752,6 +766,7 @@ static int rvin_mc_parse_of_endpoint(struct device *dev, struct v4l2_async_subdev *asd) { struct rvin_dev *vin = dev_get_drvdata(dev); + int ret = 0; if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX) return -EINVAL; @@ -762,38 +777,48 @@ static int rvin_mc_parse_of_endpoint(struct device *dev, return -ENOTCONN; } + mutex_lock(&vin->group->lock); + if (vin->group->csi[vep->base.id].fwnode) { vin_dbg(vin, "OF device %pOF already handled\n", to_of_node(asd->match.fwnode)); - return -ENOTCONN; + ret = -ENOTCONN; + goto out; } vin->group->csi[vep->base.id].fwnode = asd->match.fwnode; vin_dbg(vin, "Add group OF device %pOF to slot %u\n", to_of_node(asd->match.fwnode), vep->base.id); +out: + mutex_unlock(&vin->group->lock); - return 0; + return ret; } static int rvin_mc_parse_of_graph(struct rvin_dev *vin) { - unsigned int count = 0; + unsigned int count = 0, vin_mask = 0; unsigned int i; int ret; mutex_lock(&vin->group->lock); /* If not all VIN's are registered don't register the notifier. */ - for (i = 0; i < RCAR_VIN_NUM; i++) - if (vin->group->vin[i]) + for (i = 0; i < RCAR_VIN_NUM; i++) { + if (vin->group->vin[i]) { count++; + vin_mask |= BIT(i); + } + } if (vin->group->count != count) { mutex_unlock(&vin->group->lock); return 0; } + mutex_unlock(&vin->group->lock); + v4l2_async_notifier_init(&vin->group->notifier); /* @@ -802,21 +827,17 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) * will only be registered once with the group notifier. */ for (i = 0; i < RCAR_VIN_NUM; i++) { - if (!vin->group->vin[i]) + if (!(vin_mask & BIT(i))) continue; ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( vin->group->vin[i]->dev, &vin->group->notifier, sizeof(struct v4l2_async_subdev), 1, rvin_mc_parse_of_endpoint); - if (ret) { - mutex_unlock(&vin->group->lock); + if (ret) return ret; - } } - mutex_unlock(&vin->group->lock); - if (list_empty(&vin->group->notifier.asd_list)) return 0; @@ -1136,6 +1157,10 @@ static const struct rvin_info rcar_info_r8a77995 = { static const struct of_device_id rvin_of_id_table[] = { { + .compatible = "renesas,vin-r8a774a1", + .data = &rcar_info_r8a7796, + }, + { .compatible = "renesas,vin-r8a774c0", .data = &rcar_info_r8a77990, }, diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index f64528d2be3c..799e526fd3df 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -14,6 +14,7 @@ #include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/sys_soc.h> #include <media/v4l2-ctrls.h> @@ -350,6 +351,7 @@ struct rcar_csi2 { struct device *dev; void __iomem *base; const struct rcar_csi2_info *info; + struct reset_control *rstc; struct v4l2_subdev subdev; struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; @@ -387,11 +389,19 @@ static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) iowrite32(data, priv->base + reg); } -static void rcsi2_reset(struct rcar_csi2 *priv) +static void rcsi2_enter_standby(struct rcar_csi2 *priv) { - rcsi2_write(priv, SRST_REG, SRST_SRST); + rcsi2_write(priv, PHYCNT_REG, 0); + rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); + reset_control_assert(priv->rstc); usleep_range(100, 150); - rcsi2_write(priv, SRST_REG, 0); + pm_runtime_put(priv->dev); +} + +static void rcsi2_exit_standby(struct rcar_csi2 *priv) +{ + pm_runtime_get_sync(priv->dev); + reset_control_deassert(priv->rstc); } static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) @@ -462,7 +472,7 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) return mbps; } -static int rcsi2_start(struct rcar_csi2 *priv) +static int rcsi2_start_receiver(struct rcar_csi2 *priv) { const struct rcar_csi2_format *format; u32 phycnt, vcdt = 0, vcdt2 = 0; @@ -506,12 +516,9 @@ static int rcsi2_start(struct rcar_csi2 *priv) /* Init */ rcsi2_write(priv, TREF_REG, TREF_TREF); - rcsi2_reset(priv); rcsi2_write(priv, PHTC_REG, 0); /* Configure */ - rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 | - FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN); rcsi2_write(priv, VCDT_REG, vcdt); if (vcdt2) rcsi2_write(priv, VCDT2_REG, vcdt2); @@ -542,6 +549,8 @@ static int rcsi2_start(struct rcar_csi2 *priv) rcsi2_write(priv, PHYCNT_REG, phycnt); rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); + rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 | + FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN); rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); @@ -564,19 +573,36 @@ static int rcsi2_start(struct rcar_csi2 *priv) return 0; } -static void rcsi2_stop(struct rcar_csi2 *priv) +static int rcsi2_start(struct rcar_csi2 *priv) { - rcsi2_write(priv, PHYCNT_REG, 0); + int ret; - rcsi2_reset(priv); + rcsi2_exit_standby(priv); - rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); + ret = rcsi2_start_receiver(priv); + if (ret) { + rcsi2_enter_standby(priv); + return ret; + } + + ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); + if (ret) { + rcsi2_enter_standby(priv); + return ret; + } + + return 0; +} + +static void rcsi2_stop(struct rcar_csi2 *priv) +{ + rcsi2_enter_standby(priv); + v4l2_subdev_call(priv->remote, video, s_stream, 0); } static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) { struct rcar_csi2 *priv = sd_to_csi2(sd); - struct v4l2_subdev *nextsd; int ret = 0; mutex_lock(&priv->lock); @@ -586,27 +612,12 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) goto out; } - nextsd = priv->remote; - if (enable && priv->stream_count == 0) { - pm_runtime_get_sync(priv->dev); - ret = rcsi2_start(priv); - if (ret) { - pm_runtime_put(priv->dev); - goto out; - } - - ret = v4l2_subdev_call(nextsd, video, s_stream, 1); - if (ret) { - rcsi2_stop(priv); - pm_runtime_put(priv->dev); + if (ret) goto out; - } } else if (!enable && priv->stream_count == 1) { rcsi2_stop(priv); - v4l2_subdev_call(nextsd, video, s_stream, 0); - pm_runtime_put(priv->dev); } priv->stream_count += enable ? 1 : -1; @@ -854,7 +865,8 @@ static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, return rcsi2_phtw_write(priv, value->reg, code); } -static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) +static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, + unsigned int mbps) { static const struct phtw_value step1[] = { { .data = 0xcc, .code = 0xe2 }, @@ -880,7 +892,7 @@ static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) if (ret) return ret; - if (mbps <= 250) { + if (mbps != 0 && mbps <= 250) { ret = rcsi2_phtw_write(priv, 0x39, 0x05); if (ret) return ret; @@ -894,6 +906,16 @@ static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) return rcsi2_phtw_write_array(priv, step2); } +static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) +{ + return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); +} + +static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) +{ + return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0); +} + static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) { return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); @@ -902,11 +924,11 @@ static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) static int rcsi2_confirm_start_v3m_e3(struct rcar_csi2 *priv) { static const struct phtw_value step1[] = { - { .data = 0xed, .code = 0x34 }, - { .data = 0xed, .code = 0x44 }, - { .data = 0xed, .code = 0x54 }, - { .data = 0xed, .code = 0x84 }, - { .data = 0xed, .code = 0x94 }, + { .data = 0xee, .code = 0x34 }, + { .data = 0xee, .code = 0x44 }, + { .data = 0xee, .code = 0x54 }, + { .data = 0xee, .code = 0x84 }, + { .data = 0xee, .code = 0x94 }, { /* sentinel */ }, }; @@ -936,6 +958,10 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv, if (irq < 0) return irq; + priv->rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + return 0; } @@ -952,6 +978,14 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = { .num_channels = 4, }; +static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { + .init_phtw = rcsi2_init_phtw_h3es2, + .hsfreqrange = hsfreqrange_h3_v3h_m3n, + .csi0clkfreqrange = 0x20, + .num_channels = 4, + .clear_ulps = true, +}; + static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { .hsfreqrange = hsfreqrange_m3w_h3es1, .num_channels = 4, @@ -986,6 +1020,10 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { static const struct of_device_id rcar_csi2_of_table[] = { { + .compatible = "renesas,r8a774a1-csi2", + .data = &rcar_csi2_info_r8a7796, + }, + { .compatible = "renesas,r8a774c0-csi2", .data = &rcar_csi2_info_r8a77990, }, @@ -1017,11 +1055,15 @@ static const struct of_device_id rcar_csi2_of_table[] = { }; MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); -static const struct soc_device_attribute r8a7795es1[] = { +static const struct soc_device_attribute r8a7795[] = { { .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_csi2_info_r8a7795es1, }, + { + .soc_id = "r8a7795", .revision = "ES2.*", + .data = &rcar_csi2_info_r8a7795es2, + }, { /* sentinel */ }, }; @@ -1039,10 +1081,10 @@ static int rcsi2_probe(struct platform_device *pdev) priv->info = of_device_get_match_data(&pdev->dev); /* - * r8a7795 ES1.x behaves differently than the ES2.0+ but doesn't - * have it's own compatible string. + * The different ES versions of r8a7795 (H3) behave differently but + * share the same compatible string. */ - attr = soc_device_match(r8a7795es1); + attr = soc_device_match(r8a7795); if (attr) priv->info = attr->data; diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 2207a31d355e..91ab064404a1 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -486,7 +486,7 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) } /* Use previous value if its XS value is closer */ - if (p_prev_set && p_set && + if (p_prev_set && xs - p_prev_set->xs_value < p_set->xs_value - xs) p_set = p_prev_set; diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index c417ff8f6fe5..608e5217ccd5 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -1405,11 +1405,9 @@ static int rcar_drif_probe(struct platform_device *pdev) /* Register map */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ch->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ch->base)) { - ret = PTR_ERR(ch->base); - dev_err(&pdev->dev, "ioremap failed (%d)\n", ret); - return ret; - } + if (IS_ERR(ch->base)) + return PTR_ERR(ch->base); + ch->start = res->start; platform_set_drvdata(pdev, ch); diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 6bda1eee9170..6a90bc4c476e 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -945,7 +945,7 @@ static void fdp1_configure_wpf(struct fdp1_ctx *ctx, u32 rndctl; pstride = q_data->format.plane_fmt[0].bytesperline - << FD1_WPF_PSTRIDE_Y_SHIFT; + << FD1_WPF_PSTRIDE_Y_SHIFT; if (q_data->format.num_planes > 1) pstride |= q_data->format.plane_fmt[1].bytesperline @@ -1139,8 +1139,8 @@ static int fdp1_m2m_job_ready(void *priv) int dstbufs = 1; dprintk(ctx->fdp1, "+ Src: %d : Dst: %d\n", - v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), - v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)); + v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)); /* One output buffer is required for each field */ if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field)) @@ -1278,7 +1278,7 @@ static void fdp1_m2m_device_run(void *priv) fdp1_queue_field(ctx, fbuf); dprintk(fdp1, "Queued Buffer [%d] last_field:%d\n", - i, fbuf->last_field); + i, fbuf->last_field); } /* Queue as many jobs as our data provides for */ @@ -1337,7 +1337,7 @@ static void device_frame_end(struct fdp1_dev *fdp1, fdp1_job_free(fdp1, job); dprintk(fdp1, "curr_ctx->num_processed %d curr_ctx->translen %d\n", - ctx->num_processed, ctx->translen); + ctx->num_processed, ctx->translen); if (ctx->num_processed == ctx->translen || ctx->aborting) { @@ -1362,7 +1362,7 @@ static int fdp1_vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); strscpy(cap->card, DRIVER_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", DRIVER_NAME); + "platform:%s", DRIVER_NAME); return 0; } @@ -1993,13 +1993,13 @@ static void fdp1_stop_streaming(struct vb2_queue *q) /* Free smsk_data */ if (ctx->smsk_cpu) { dma_free_coherent(ctx->fdp1->dev, ctx->smsk_size, - ctx->smsk_cpu, ctx->smsk_addr[0]); + ctx->smsk_cpu, ctx->smsk_addr[0]); ctx->smsk_addr[0] = ctx->smsk_addr[1] = 0; ctx->smsk_cpu = NULL; } WARN(!list_empty(&ctx->fields_queue), - "Buffer queue not empty"); + "Buffer queue not empty"); } else { /* Empty Capture queues (Jobs) */ struct fdp1_job *job; @@ -2021,10 +2021,10 @@ static void fdp1_stop_streaming(struct vb2_queue *q) fdp1_field_complete(ctx, ctx->previous); WARN(!list_empty(&ctx->fdp1->queued_job_list), - "Queued Job List not empty"); + "Queued Job List not empty"); WARN(!list_empty(&ctx->fdp1->hw_job_list), - "HW Job list not empty"); + "HW Job list not empty"); } } @@ -2110,7 +2110,7 @@ static int fdp1_open(struct file *file) fdp1_ctrl_deint_menu); ctrl = v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1); + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1); if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; @@ -2347,8 +2347,8 @@ static int fdp1_probe(struct platform_device *pdev) goto release_m2m; } - v4l2_info(&fdp1->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); + v4l2_info(&fdp1->v4l2_dev, "Device registered as /dev/video%d\n", + vfd->num); /* Power up the cells to read HW */ pm_runtime_enable(&pdev->dev); @@ -2367,7 +2367,7 @@ static int fdp1_probe(struct platform_device *pdev) break; default: dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n", - hw_version); + hw_version); } /* Allow the hw to sleep until an open call puts it to use */ diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c index 8837e2678bde..7f62f5ef0086 100644 --- a/drivers/media/platform/s5p-cec/s5p_cec.c +++ b/drivers/media/platform/s5p-cec/s5p_cec.c @@ -178,22 +178,16 @@ static const struct cec_adap_ops s5p_cec_adap_ops = { static int s5p_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np; - struct platform_device *hdmi_dev; + struct device *hdmi_dev; struct resource *res; struct s5p_cec_dev *cec; bool needs_hpd = of_property_read_bool(pdev->dev.of_node, "needs-hpd"); int ret; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); - return -ENODEV; - } - hdmi_dev = of_find_device_by_node(np); - if (hdmi_dev == NULL) - return -EPROBE_DEFER; + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); if (!cec) @@ -224,7 +218,7 @@ static int s5p_cec_probe(struct platform_device *pdev) if (IS_ERR(cec->reg)) return PTR_ERR(cec->reg); - cec->notifier = cec_notifier_get(&hdmi_dev->dev); + cec->notifier = cec_notifier_get(hdmi_dev); if (cec->notifier == NULL) return -ENOMEM; diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 971c47165010..c8f394e1aff4 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -297,8 +297,8 @@ static int g2d_release(struct file *file) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, G2D_NAME, sizeof(cap->driver)); + strscpy(cap->card, G2D_NAME, sizeof(cap->card)); cap->bus_info[0] = 0; cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -312,7 +312,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return -EINVAL; fmt = &formats[f->index]; f->pixelformat = fmt->fourcc; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); return 0; } diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c index a425a10540c1..e5080d6f5b2d 100644 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ b/drivers/media/platform/seco-cec/seco-cec.c @@ -536,6 +536,7 @@ static int secocec_cec_get_notifier(struct cec_notifier **notify) return -EPROBE_DEFER; *notify = cec_notifier_get_conn(d, m->conn); + put_device(d); return 0; } diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index d277cc674349..5a9ba05c996e 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -493,9 +493,6 @@ static int sh_veu_try_fmt_vid_cap(struct file *file, void *priv, const struct sh_veu_format *fmt; fmt = sh_veu_find_fmt(f); - if (!fmt) - /* wrong buffer type */ - return -EINVAL; return sh_veu_try_fmt(f, fmt); } @@ -506,9 +503,6 @@ static int sh_veu_try_fmt_vid_out(struct file *file, void *priv, const struct sh_veu_format *fmt; fmt = sh_veu_find_fmt(f); - if (!fmt) - /* wrong buffer type */ - return -EINVAL; return sh_veu_try_fmt(f, fmt); } diff --git a/drivers/media/platform/sti/c8sectpfe/Kconfig b/drivers/media/platform/sti/c8sectpfe/Kconfig index 7420a50572d3..93eaabfd5437 100644 --- a/drivers/media/platform/sti/c8sectpfe/Kconfig +++ b/drivers/media/platform/sti/c8sectpfe/Kconfig @@ -12,7 +12,7 @@ config DVB_C8SECTPFE select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB front-end cards connected to TS inputs of STiH407/410 SoC. diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c index d34099f75990..fc37efe1d554 100644 --- a/drivers/media/platform/sti/cec/stih-cec.c +++ b/drivers/media/platform/sti/cec/stih-cec.c @@ -301,26 +301,19 @@ static int stih_cec_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; struct stih_cec *cec; - struct device_node *np; - struct platform_device *hdmi_dev; + struct device *hdmi_dev; int ret; + hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); + + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); if (!cec) return -ENOMEM; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); - - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); - return -ENODEV; - } - - hdmi_dev = of_find_device_by_node(np); - if (!hdmi_dev) - return -EPROBE_DEFER; - - cec->notifier = cec_notifier_get(&hdmi_dev->dev); + cec->notifier = cec_notifier_get(hdmi_dev); if (!cec->notifier) return -ENOMEM; diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c index a4603d573c34..186d88f02ecd 100644 --- a/drivers/media/platform/sti/delta/delta-ipc.c +++ b/drivers/media/platform/sti/delta/delta-ipc.c @@ -220,10 +220,8 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name, err: pctx->sys_errors++; - if (ctx->ipc_buf) { - hw_free(pctx, ctx->ipc_buf); - ctx->ipc_buf = NULL; - } + hw_free(pctx, ctx->ipc_buf); + ctx->ipc_buf = NULL; return ret; }; diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 7c496bc1cf38..8a86b2cc22fa 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -56,6 +56,13 @@ #define ALL_TX_IT (TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST) #define ALL_RX_IT (RXEND | RXBR | RXACKE | RXOVR) +/* + * 400 ms is the time it takes for one 16 byte message to be + * transferred and 5 is the maximum number of retries. Add + * another 100 ms as a margin. + */ +#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) + struct stm32_cec { struct cec_adapter *adap; struct device *dev; @@ -188,7 +195,11 @@ static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) { struct stm32_cec *cec = adap->priv; u32 oar = (1 << logical_addr) << 16; + u32 val; + /* Poll every 100µs the register CEC_CR to wait end of transmission */ + regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), + 100, CEC_XFER_TIMEOUT_MS * 1000); regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); if (logical_addr == CEC_LOG_ADDR_INVALID) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 5fe5b38fa901..b9dad0accd1b 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -97,6 +97,8 @@ enum state { #define TIMEOUT_MS 1000 +#define OVERRUN_ERROR_THRESHOLD 3 + struct dcmi_graph_entity { struct device_node *node; @@ -164,6 +166,9 @@ struct stm32_dcmi { int errors_count; int overrun_count; int buffers_count; + + /* Ensure DMA operations atomicity */ + struct mutex dma_lock; }; static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) @@ -314,6 +319,13 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, return ret; } + /* + * Avoid call of dmaengine_terminate_all() between + * dmaengine_prep_slave_single() and dmaengine_submit() + * by locking the whole DMA submission sequence + */ + mutex_lock(&dcmi->dma_lock); + /* Prepare a DMA transaction */ desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, buf->size, @@ -322,6 +334,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, if (!desc) { dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", __func__, &buf->paddr, buf->size); + mutex_unlock(&dcmi->dma_lock); return -EINVAL; } @@ -333,9 +346,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, dcmi->dma_cookie = dmaengine_submit(desc); if (dma_submit_error(dcmi->dma_cookie)) { dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__); + mutex_unlock(&dcmi->dma_lock); return -ENXIO; } + mutex_unlock(&dcmi->dma_lock); + dma_async_issue_pending(dcmi->dma_chan); return 0; @@ -432,11 +448,13 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) spin_lock_irq(&dcmi->irqlock); - if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { - dcmi->errors_count++; - if (dcmi->misr & IT_OVR) - dcmi->overrun_count++; + if (dcmi->misr & IT_OVR) { + dcmi->overrun_count++; + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && dcmi->misr & IT_FRAME) { @@ -570,9 +588,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) int ret; ret = pm_runtime_get_sync(dcmi->dev); - if (ret) { - dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n", - __func__); + if (ret < 0) { + dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", + __func__, ret); goto err_release_buffers; } @@ -720,7 +738,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&dcmi->irqlock); /* Stop all pending DMA operations */ + mutex_lock(&dcmi->dma_lock); dmaengine_terminate_all(dcmi->dma_chan); + mutex_unlock(&dcmi->dma_lock); pm_runtime_put(dcmi->dev); @@ -811,6 +831,9 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); if (!sd_fmt) { + if (!dcmi->num_of_sd_formats) + return -ENODATA; + sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1]; pix->pixelformat = sd_fmt->fourcc; } @@ -989,6 +1012,9 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); if (!sd_fmt) { + if (!dcmi->num_of_sd_formats) + return -ENODATA; + sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1]; pix->pixelformat = sd_fmt->fourcc; } @@ -1595,7 +1621,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) /* Parse the graph to extract a list of subdevice DT nodes. */ ret = dcmi_graph_parse(dcmi, dcmi->dev->of_node); if (ret < 0) { - dev_err(dcmi->dev, "Graph parsing failed\n"); + dev_err(dcmi->dev, "Failed to parse graph\n"); return ret; } @@ -1604,6 +1630,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) ret = v4l2_async_notifier_add_subdev(&dcmi->notifier, &dcmi->entity.asd); if (ret) { + dev_err(dcmi->dev, "Failed to add subdev notifier\n"); of_node_put(dcmi->entity.node); return ret; } @@ -1612,7 +1639,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); if (ret < 0) { - dev_err(dcmi->dev, "Notifier registration failed\n"); + dev_err(dcmi->dev, "Failed to register notifier\n"); v4l2_async_notifier_cleanup(&dcmi->notifier); return ret; } @@ -1645,7 +1672,7 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(dcmi->rstc)) { dev_err(&pdev->dev, "Could not get reset control\n"); - return -ENODEV; + return PTR_ERR(dcmi->rstc); } /* Get bus characteristics from devicetree */ @@ -1660,7 +1687,7 @@ static int dcmi_probe(struct platform_device *pdev) of_node_put(np); if (ret) { dev_err(&pdev->dev, "Could not parse the endpoint\n"); - return -ENODEV; + return ret; } if (ep.bus_type == V4L2_MBUS_CSI2_DPHY) { @@ -1673,8 +1700,9 @@ static int dcmi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(&pdev->dev, "Could not get irq\n"); - return -ENODEV; + if (irq != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get irq\n"); + return irq; } dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1694,12 +1722,13 @@ static int dcmi_probe(struct platform_device *pdev) dev_name(&pdev->dev), dcmi); if (ret) { dev_err(&pdev->dev, "Unable to request irq %d\n", irq); - return -ENODEV; + return ret; } mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(mclk)) { - dev_err(&pdev->dev, "Unable to get mclk\n"); + if (PTR_ERR(mclk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get mclk\n"); return PTR_ERR(mclk); } @@ -1711,6 +1740,7 @@ static int dcmi_probe(struct platform_device *pdev) spin_lock_init(&dcmi->irqlock); mutex_init(&dcmi->lock); + mutex_init(&dcmi->dma_lock); init_completion(&dcmi->complete); INIT_LIST_HEAD(&dcmi->buffers); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 1fd16861f111..f0dfe68486d1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -412,7 +412,7 @@ static int vidioc_enum_input(struct file *file, void *fh, if (inp->index != 0) return -EINVAL; - strlcpy(inp->name, "camera", sizeof(inp->name)); + strscpy(inp->name, "camera", sizeof(inp->name)); inp->type = V4L2_INPUT_TYPE_CAMERA; return 0; @@ -644,7 +644,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, } /* Register video device */ - strlcpy(vdev->name, name, sizeof(vdev->name)); + strscpy(vdev->name, name, sizeof(vdev->name)); vdev->release = video_device_release_empty; vdev->fops = &sun6i_video_fops; vdev->ioctl_ops = &sun6i_video_ioctl_ops; diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index aba488cd0e64..7fb3a4fa07c1 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -327,21 +327,15 @@ static const struct cec_adap_ops tegra_cec_ops = { static int tegra_cec_probe(struct platform_device *pdev) { - struct platform_device *hdmi_dev; - struct device_node *np; + struct device *hdmi_dev; struct tegra_cec *cec; struct resource *res; int ret = 0; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); + if (!hdmi_dev) return -ENODEV; - } - hdmi_dev = of_find_device_by_node(np); - if (hdmi_dev == NULL) - return -EPROBE_DEFER; cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL); @@ -400,7 +394,7 @@ static int tegra_cec_probe(struct platform_device *pdev) goto clk_error; } - cec->notifier = cec_notifier_get(&hdmi_dev->dev); + cec->notifier = cec_notifier_get(hdmi_dev); if (!cec->notifier) { ret = -ENOMEM; goto clk_error; diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index fc3c212b96e1..8d075683e448 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1643,8 +1643,7 @@ of_get_next_endpoint(const struct device_node *parent, static int of_cal_create_instance(struct cal_ctx *ctx, int inst) { struct platform_device *pdev = ctx->dev->pdev; - struct device_node *ep_node, *port, *remote_ep, - *sensor_node, *parent; + struct device_node *ep_node, *port, *sensor_node, *parent; struct v4l2_fwnode_endpoint *endpoint; struct v4l2_async_subdev *asd; u32 regval = 0; @@ -1657,7 +1656,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) ep_node = NULL; port = NULL; - remote_ep = NULL; sensor_node = NULL; ret = -EINVAL; @@ -1703,12 +1701,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) asd->match_type = V4L2_ASYNC_MATCH_FWNODE; asd->match.fwnode = of_fwnode_handle(sensor_node); - remote_ep = of_graph_get_remote_endpoint(ep_node); - if (!remote_ep) { - ctx_dbg(3, ctx, "can't get remote-endpoint\n"); - goto cleanup_exit; - } - v4l2_fwnode_endpoint_parse(of_fwnode_handle(remote_ep), endpoint); + v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) { ctx_err(ctx, "Port:%d sub-device %pOFn is not a CSI2 device\n", @@ -1759,7 +1752,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) sensor_node = NULL; cleanup_exit: - of_node_put(remote_ep); of_node_put(sensor_node); of_node_put(ep_node); of_node_put(port); diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 207e7e76c048..1e40eafec284 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1491,8 +1491,8 @@ handled: static int vpe_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", VPE_MODULE_NAME); cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; @@ -1519,7 +1519,7 @@ static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c index d1d6085da9f1..31faf319e508 100644 --- a/drivers/media/platform/vicodec/codec-fwht.c +++ b/drivers/media/platform/vicodec/codec-fwht.c @@ -46,8 +46,12 @@ static const uint8_t zigzag[64] = { 63, }; - -static int rlc(const s16 *in, __be16 *output, int blocktype) +/* + * noinline_for_stack to work around + * https://bugs.llvm.org/show_bug.cgi?id=38809 + */ +static int noinline_for_stack +rlc(const s16 *in, __be16 *output, int blocktype) { s16 block[8 * 8]; s16 *wp = block; @@ -106,8 +110,8 @@ static int rlc(const s16 *in, __be16 *output, int blocktype) * This function will worst-case increase rlc_in by 65*2 bytes: * one s16 value for the header and 8 * 8 coefficients of type s16. */ -static u16 derlc(const __be16 **rlc_in, s16 *dwht_out, - const __be16 *end_of_input) +static noinline_for_stack u16 +derlc(const __be16 **rlc_in, s16 *dwht_out, const __be16 *end_of_input) { /* header */ const __be16 *input = *rlc_in; @@ -240,8 +244,9 @@ static void dequantize_inter(s16 *coeff) *coeff <<= *quant; } -static void fwht(const u8 *block, s16 *output_block, unsigned int stride, - unsigned int input_step, bool intra) +static void noinline_for_stack fwht(const u8 *block, s16 *output_block, + unsigned int stride, + unsigned int input_step, bool intra) { /* we'll need more than 8 bits for the transformed coefficients */ s32 workspace1[8], workspace2[8]; @@ -373,7 +378,8 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride, * Furthermore values can be negative... This is just a version that * works with 16 signed data */ -static void fwht16(const s16 *block, s16 *output_block, int stride, int intra) +static void noinline_for_stack +fwht16(const s16 *block, s16 *output_block, int stride, int intra) { /* we'll need more than 8 bits for the transformed coefficients */ s32 workspace1[8], workspace2[8]; @@ -456,7 +462,8 @@ static void fwht16(const s16 *block, s16 *output_block, int stride, int intra) } } -static void ifwht(const s16 *block, s16 *output_block, int intra) +static noinline_for_stack void +ifwht(const s16 *block, s16 *output_block, int intra) { /* * we'll need more than 8 bits for the transformed coefficients @@ -604,9 +611,9 @@ static int var_inter(const s16 *old, const s16 *new) return ret; } -static int decide_blocktype(const u8 *cur, const u8 *reference, - s16 *deltablock, unsigned int stride, - unsigned int input_step) +static noinline_for_stack int +decide_blocktype(const u8 *cur, const u8 *reference, s16 *deltablock, + unsigned int stride, unsigned int input_step) { s16 tmp[64]; s16 old[64]; @@ -632,12 +639,13 @@ static int decide_blocktype(const u8 *cur, const u8 *reference, return vari <= vard ? IBLOCK : PBLOCK; } -static void fill_decoder_block(u8 *dst, const s16 *input, int stride) +static void fill_decoder_block(u8 *dst, const s16 *input, int stride, + unsigned int dst_step) { int i, j; for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++, input++, dst++) { + for (j = 0; j < 8; j++, input++, dst += dst_step) { if (*input < 0) *dst = 0; else if (*input > 255) @@ -645,17 +653,19 @@ static void fill_decoder_block(u8 *dst, const s16 *input, int stride) else *dst = *input; } - dst += stride - 8; + dst += stride - (8 * dst_step); } } -static void add_deltas(s16 *deltas, const u8 *ref, int stride) +static void add_deltas(s16 *deltas, const u8 *ref, int stride, + unsigned int ref_step) { int k, l; for (k = 0; k < 8; k++) { for (l = 0; l < 8; l++) { - *deltas += *ref++; + *deltas += *ref; + ref += ref_step; /* * Due to quantizing, it might possible that the * decoded coefficients are slightly out of range @@ -666,7 +676,7 @@ static void add_deltas(s16 *deltas, const u8 *ref, int stride) *deltas = 255; deltas++; } - ref += stride - 8; + ref += stride - (8 * ref_step); } } @@ -711,8 +721,8 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, ifwht(cf->de_coeffs, cf->de_fwht, blocktype); if (blocktype == PBLOCK) - add_deltas(cf->de_fwht, refp, 8); - fill_decoder_block(refp, cf->de_fwht, 8); + add_deltas(cf->de_fwht, refp, 8, 1); + fill_decoder_block(refp, cf->de_fwht, 8, 1); } input += 8 * input_step; @@ -821,23 +831,31 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, return encoding; } -static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, - u32 height, u32 width, u32 coded_width, +static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, + u32 height, u32 width, const u8 *ref, u32 ref_stride, + unsigned int ref_step, u8 *dst, + unsigned int dst_stride, unsigned int dst_step, bool uncompressed, const __be16 *end_of_rlco_buf) { unsigned int copies = 0; s16 copy[8 * 8]; u16 stat; unsigned int i, j; + bool is_intra = !ref; width = round_up(width, 8); height = round_up(height, 8); if (uncompressed) { + int i; + if (end_of_rlco_buf + 1 < *rlco + width * height / 2) return false; - memcpy(ref, *rlco, width * height); - *rlco += width * height / 2; + for (i = 0; i < height; i++) { + memcpy(dst, *rlco, width); + dst += dst_stride; + *rlco += width / 2; + } return true; } @@ -849,15 +867,17 @@ static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, */ for (j = 0; j < height / 8; j++) { for (i = 0; i < width / 8; i++) { - u8 *refp = ref + j * 8 * coded_width + i * 8; + const u8 *refp = ref + j * 8 * ref_stride + + i * 8 * ref_step; + u8 *dstp = dst + j * 8 * dst_stride + i * 8 * dst_step; if (copies) { memcpy(cf->de_fwht, copy, sizeof(copy)); - if (stat & PFRAME_BIT) + if ((stat & PFRAME_BIT) && !is_intra) add_deltas(cf->de_fwht, refp, - coded_width); - fill_decoder_block(refp, cf->de_fwht, - coded_width); + ref_stride, ref_step); + fill_decoder_block(dstp, cf->de_fwht, + dst_stride, dst_step); copies--; continue; } @@ -865,35 +885,41 @@ static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, stat = derlc(rlco, cf->coeffs, end_of_rlco_buf); if (stat & OVERFLOW_BIT) return false; - if (stat & PFRAME_BIT) + if ((stat & PFRAME_BIT) && !is_intra) dequantize_inter(cf->coeffs); else dequantize_intra(cf->coeffs); ifwht(cf->coeffs, cf->de_fwht, - (stat & PFRAME_BIT) ? 0 : 1); + ((stat & PFRAME_BIT) && !is_intra) ? 0 : 1); copies = (stat & DUPS_MASK) >> 1; if (copies) memcpy(copy, cf->de_fwht, sizeof(copy)); - if (stat & PFRAME_BIT) - add_deltas(cf->de_fwht, refp, coded_width); - fill_decoder_block(refp, cf->de_fwht, coded_width); + if ((stat & PFRAME_BIT) && !is_intra) + add_deltas(cf->de_fwht, refp, + ref_stride, ref_step); + fill_decoder_block(dstp, cf->de_fwht, dst_stride, + dst_step); } } return true; } -bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num, - unsigned int width, unsigned int height, - unsigned int coded_width) +bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, + unsigned int components_num, unsigned int width, + unsigned int height, const struct fwht_raw_frame *ref, + unsigned int ref_stride, unsigned int ref_chroma_stride, + struct fwht_raw_frame *dst, unsigned int dst_stride, + unsigned int dst_chroma_stride) { const __be16 *rlco = cf->rlc_data; const __be16 *end_of_rlco_buf = cf->rlc_data + (cf->size / sizeof(*rlco)) - 1; - if (!decode_plane(cf, &rlco, ref->luma, height, width, coded_width, + if (!decode_plane(cf, &rlco, height, width, ref->luma, ref_stride, + ref->luma_alpha_step, dst->luma, dst_stride, + dst->luma_alpha_step, hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; @@ -901,27 +927,30 @@ bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, if (components_num >= 3) { u32 h = height; u32 w = width; - u32 c = coded_width; if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) h /= 2; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) { + if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) w /= 2; - c /= 2; - } - if (!decode_plane(cf, &rlco, ref->cb, h, w, c, + + if (!decode_plane(cf, &rlco, h, w, ref->cb, ref_chroma_stride, + ref->chroma_step, dst->cb, dst_chroma_stride, + dst->chroma_step, hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; - if (!decode_plane(cf, &rlco, ref->cr, h, w, c, + if (!decode_plane(cf, &rlco, h, w, ref->cr, ref_chroma_stride, + ref->chroma_step, dst->cr, dst_chroma_stride, + dst->chroma_step, hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; } if (components_num == 4) - if (!decode_plane(cf, &rlco, ref->alpha, height, width, - coded_width, + if (!decode_plane(cf, &rlco, height, width, ref->alpha, ref_stride, + ref->luma_alpha_step, dst->alpha, dst_stride, + dst->luma_alpha_step, hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; diff --git a/drivers/media/platform/vicodec/codec-fwht.h b/drivers/media/platform/vicodec/codec-fwht.h index c410512d47c5..b6fec2b1cbca 100644 --- a/drivers/media/platform/vicodec/codec-fwht.h +++ b/drivers/media/platform/vicodec/codec-fwht.h @@ -124,6 +124,7 @@ struct fwht_raw_frame { unsigned int luma_alpha_step; unsigned int chroma_step; unsigned int components_num; + u8 *buf; u8 *luma, *cb, *cr, *alpha; }; @@ -140,9 +141,10 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, bool is_intra, bool next_is_intra, unsigned int width, unsigned int height, unsigned int stride, unsigned int chroma_stride); -bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num, - unsigned int width, unsigned int height, - unsigned int coded_width); - +bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, + unsigned int components_num, unsigned int width, + unsigned int height, const struct fwht_raw_frame *ref, + unsigned int ref_stride, unsigned int ref_chroma_stride, + struct fwht_raw_frame *dst, unsigned int dst_stride, + unsigned int dst_chroma_stride); #endif diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c index 6573a471c5ca..01e7f09efc4e 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c @@ -37,7 +37,19 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, }; -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, +bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, + u32 width_div, u32 height_div, u32 components_num, + u32 pixenc) +{ + if (info->width_div == width_div && + info->height_div == height_div && + (!pixenc || info->pixenc == pixenc) && + info->components_num == components_num) + return true; + return false; +} + +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, u32 height_div, u32 components_num, u32 pixenc, @@ -46,10 +58,10 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, unsigned int i; for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { - if (v4l2_fwht_pixfmts[i].width_div == width_div && - v4l2_fwht_pixfmts[i].height_div == height_div && - (!pixenc || v4l2_fwht_pixfmts[i].pixenc == pixenc) && - v4l2_fwht_pixfmts[i].components_num == components_num) { + bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i], + width_div, height_div, + components_num, pixenc); + if (is_valid) { if (start_idx == 0) return v4l2_fwht_pixfmts + i; start_idx--; @@ -75,117 +87,141 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) return v4l2_fwht_pixfmts + idx; } -int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) +static int prepare_raw_frame(struct fwht_raw_frame *rf, + const struct v4l2_fwht_pixfmt_info *info, u8 *buf, + unsigned int size) { - unsigned int size = state->stride * state->coded_height; - unsigned int chroma_stride = state->stride; - const struct v4l2_fwht_pixfmt_info *info = state->info; - struct fwht_cframe_hdr *p_hdr; - struct fwht_cframe cf; - struct fwht_raw_frame rf; - u32 encoding; - u32 flags = 0; - - if (!info) - return -EINVAL; - - rf.luma = p_in; - rf.width_div = info->width_div; - rf.height_div = info->height_div; - rf.luma_alpha_step = info->luma_alpha_step; - rf.chroma_step = info->chroma_step; - rf.alpha = NULL; - rf.components_num = info->components_num; + rf->luma = buf; + rf->width_div = info->width_div; + rf->height_div = info->height_div; + rf->luma_alpha_step = info->luma_alpha_step; + rf->chroma_step = info->chroma_step; + rf->alpha = NULL; + rf->components_num = info->components_num; + /* + * The buffer is NULL if it is the reference + * frame of an I-frame in the stateless decoder + */ + if (!buf) { + rf->luma = NULL; + rf->cb = NULL; + rf->cr = NULL; + rf->alpha = NULL; + return 0; + } switch (info->id) { case V4L2_PIX_FMT_GREY: - rf.cb = NULL; - rf.cr = NULL; + rf->cb = NULL; + rf->cr = NULL; break; case V4L2_PIX_FMT_YUV420: - rf.cb = rf.luma + size; - rf.cr = rf.cb + size / 4; - chroma_stride /= 2; + rf->cb = rf->luma + size; + rf->cr = rf->cb + size / 4; break; case V4L2_PIX_FMT_YVU420: - rf.cr = rf.luma + size; - rf.cb = rf.cr + size / 4; - chroma_stride /= 2; + rf->cr = rf->luma + size; + rf->cb = rf->cr + size / 4; break; case V4L2_PIX_FMT_YUV422P: - rf.cb = rf.luma + size; - rf.cr = rf.cb + size / 2; - chroma_stride /= 2; + rf->cb = rf->luma + size; + rf->cr = rf->cb + size / 2; break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV24: - rf.cb = rf.luma + size; - rf.cr = rf.cb + 1; + rf->cb = rf->luma + size; + rf->cr = rf->cb + 1; break; case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV42: - rf.cr = rf.luma + size; - rf.cb = rf.cr + 1; + rf->cr = rf->luma + size; + rf->cb = rf->cr + 1; break; case V4L2_PIX_FMT_YUYV: - rf.cb = rf.luma + 1; - rf.cr = rf.cb + 2; + rf->cb = rf->luma + 1; + rf->cr = rf->cb + 2; break; case V4L2_PIX_FMT_YVYU: - rf.cr = rf.luma + 1; - rf.cb = rf.cr + 2; + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; break; case V4L2_PIX_FMT_UYVY: - rf.cb = rf.luma; - rf.cr = rf.cb + 2; - rf.luma++; + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; break; case V4L2_PIX_FMT_VYUY: - rf.cr = rf.luma; - rf.cb = rf.cr + 2; - rf.luma++; + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_HSV24: - rf.cr = rf.luma; - rf.cb = rf.cr + 2; - rf.luma++; + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; break; case V4L2_PIX_FMT_BGR24: - rf.cb = rf.luma; - rf.cr = rf.cb + 2; - rf.luma++; + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_HSV32: - rf.cr = rf.luma + 1; - rf.cb = rf.cr + 2; - rf.luma += 2; + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; + rf->luma += 2; break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XBGR32: - rf.cb = rf.luma; - rf.cr = rf.cb + 2; - rf.luma++; + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; break; case V4L2_PIX_FMT_ARGB32: - rf.alpha = rf.luma; - rf.cr = rf.luma + 1; - rf.cb = rf.cr + 2; - rf.luma += 2; + rf->alpha = rf->luma; + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; + rf->luma += 2; break; case V4L2_PIX_FMT_ABGR32: - rf.cb = rf.luma; - rf.cr = rf.cb + 2; - rf.luma++; - rf.alpha = rf.cr + 1; + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; + rf->alpha = rf->cr + 1; break; default: return -EINVAL; } + return 0; +} + +int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) +{ + unsigned int size = state->stride * state->coded_height; + unsigned int chroma_stride = state->stride; + const struct v4l2_fwht_pixfmt_info *info = state->info; + struct fwht_cframe_hdr *p_hdr; + struct fwht_cframe cf; + struct fwht_raw_frame rf; + u32 encoding; + u32 flags = 0; + + if (!info) + return -EINVAL; + + if (prepare_raw_frame(&rf, info, p_in, size)) + return -EINVAL; + + if (info->planes_num == 3) + chroma_stride /= 2; + + if (info->id == V4L2_PIX_FMT_NV24 || + info->id == V4L2_PIX_FMT_NV42) + chroma_stride *= 2; cf.i_frame_qp = state->i_frame_qp; cf.p_frame_qp = state->p_frame_qp; @@ -235,14 +271,17 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) { - unsigned int i, j, k; u32 flags; struct fwht_cframe cf; - u8 *p, *ref_p; unsigned int components_num = 3; unsigned int version; const struct v4l2_fwht_pixfmt_info *info; unsigned int hdr_width_div, hdr_height_div; + struct fwht_raw_frame dst_rf; + unsigned int dst_chroma_stride = state->stride; + unsigned int ref_chroma_stride = state->ref_stride; + unsigned int dst_size = state->stride * state->coded_height; + unsigned int ref_size; if (!state->info) return -EINVAL; @@ -290,241 +329,29 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) hdr_height_div != info->height_div) return -EINVAL; - if (!fwht_decode_frame(&cf, &state->ref_frame, flags, components_num, - state->visible_width, state->visible_height, - state->coded_width)) + if (prepare_raw_frame(&dst_rf, info, p_out, dst_size)) return -EINVAL; + if (info->planes_num == 3) { + dst_chroma_stride /= 2; + ref_chroma_stride /= 2; + } + if (info->id == V4L2_PIX_FMT_NV24 || + info->id == V4L2_PIX_FMT_NV42) { + dst_chroma_stride *= 2; + ref_chroma_stride *= 2; + } - /* - * TODO - handle the case where the compressed stream encodes a - * different format than the requested decoded format. - */ - switch (state->info->id) { - case V4L2_PIX_FMT_GREY: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } - break; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YUV422P: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } - ref_p = state->ref_frame.cb; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - ref_p = state->ref_frame.cr; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - break; - case V4L2_PIX_FMT_YVU420: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } - - ref_p = state->ref_frame.cr; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - ref_p = state->ref_frame.cb; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV24: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } + ref_size = state->ref_stride * state->coded_height; - k = 0; - for (i = 0; i < state->coded_height / 2; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.cr[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_NV42: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } + if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf, + ref_size)) + return -EINVAL; - k = 0; - for (i = 0; i < state->coded_height / 2; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_YUYV: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - *p++ = state->ref_frame.cr[k / 2]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_YVYU: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - *p++ = state->ref_frame.cb[k / 2]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_UYVY: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cb[k / 2]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_VYUY: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cr[k / 2]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_HSV24: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_BGR24: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_XRGB32: - case V4L2_PIX_FMT_HSV32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = 0; - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_XBGR32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k]; - *p++ = 0; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_ARGB32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.alpha[k]; - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_ABGR32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.alpha[k]; - k++; - } - p_out += state->stride; - } - break; - default: + if (!fwht_decode_frame(&cf, flags, components_num, + state->visible_width, state->visible_height, + &state->ref_frame, state->ref_stride, ref_chroma_stride, + &dst_rf, state->stride, dst_chroma_stride)) return -EINVAL; - } return 0; } diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.h b/drivers/media/platform/vicodec/codec-v4l2-fwht.h index aa6fa90a48be..1a0d2a9f931a 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.h +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.h @@ -30,6 +30,7 @@ struct v4l2_fwht_state { unsigned int coded_width; unsigned int coded_height; unsigned int stride; + unsigned int ref_stride; unsigned int gop_size; unsigned int gop_cnt; u16 i_frame_qp; @@ -43,11 +44,15 @@ struct v4l2_fwht_state { struct fwht_raw_frame ref_frame; struct fwht_cframe_hdr header; u8 *compressed_frame; + u64 ref_frame_ts; }; const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat); const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx); -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, +bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, + u32 width_div, u32 height_div, u32 components_num, + u32 pixenc); +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, u32 height_div, u32 components_num, u32 pixenc, diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index d7636fe9e174..bd01a9206aa6 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -64,6 +64,10 @@ static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 }; +static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = { + V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1 +}; + static void vicodec_dev_release(struct device *dev) { } @@ -89,27 +93,29 @@ enum { V4L2_M2M_DST = 1, }; +struct vicodec_dev_instance { + struct video_device vfd; + struct mutex mutex; + spinlock_t lock; + struct v4l2_m2m_dev *m2m_dev; +}; + struct vicodec_dev { struct v4l2_device v4l2_dev; - struct video_device enc_vfd; - struct video_device dec_vfd; + struct vicodec_dev_instance stateful_enc; + struct vicodec_dev_instance stateful_dec; + struct vicodec_dev_instance stateless_dec; #ifdef CONFIG_MEDIA_CONTROLLER struct media_device mdev; #endif - struct mutex enc_mutex; - struct mutex dec_mutex; - spinlock_t enc_lock; - spinlock_t dec_lock; - - struct v4l2_m2m_dev *enc_dev; - struct v4l2_m2m_dev *dec_dev; }; struct vicodec_ctx { struct v4l2_fh fh; struct vicodec_dev *dev; bool is_enc; + bool is_stateless; spinlock_t *lock; struct v4l2_ctrl_handler hdl; @@ -148,27 +154,149 @@ static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: return &ctx->q_data[V4L2_M2M_DST]; default: - WARN_ON(1); break; } return NULL; } +static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info, + struct v4l2_fwht_state *state) +{ + int plane_idx; + u8 *p_ref = state->ref_frame.buf; + unsigned int cap_stride = state->stride; + unsigned int ref_stride = state->ref_stride; + + for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) { + int i; + unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ? + info->height_div : 1; + const u8 *row_cap = cap; + u8 *row_ref = p_ref; + + if (info->planes_num == 3 && plane_idx == 1) { + cap_stride /= 2; + ref_stride /= 2; + } + + if (plane_idx == 1 && + (info->id == V4L2_PIX_FMT_NV24 || + info->id == V4L2_PIX_FMT_NV42)) { + cap_stride *= 2; + ref_stride *= 2; + } + + for (i = 0; i < state->visible_height / h_div; i++) { + memcpy(row_ref, row_cap, ref_stride); + row_ref += ref_stride; + row_cap += cap_stride; + } + cap += cap_stride * (state->coded_height / h_div); + p_ref += ref_stride * (state->coded_height / h_div); + } +} + +static bool validate_by_version(unsigned int flags, unsigned int version) +{ + if (!version || version > FWHT_VERSION) + return false; + + if (version >= 2) { + unsigned int components_num = 1 + + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK; + + if (components_num == 0 || components_num > 4 || !pixenc) + return false; + } + return true; +} + +static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params, + const struct v4l2_fwht_pixfmt_info *cur_info) +{ + unsigned int width_div = + (params->flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int height_div = + (params->flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + unsigned int components_num = 3; + unsigned int pixenc = 0; + + if (params->version < 3) + return false; + + components_num = 1 + ((params->flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + pixenc = (params->flags & FWHT_FL_PIXENC_MSK); + if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div, + components_num, pixenc)) + return true; + return false; +} + + +static void update_state_from_header(struct vicodec_ctx *ctx) +{ + const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; + + ctx->state.visible_width = ntohl(p_hdr->width); + ctx->state.visible_height = ntohl(p_hdr->height); + ctx->state.colorspace = ntohl(p_hdr->colorspace); + ctx->state.xfer_func = ntohl(p_hdr->xfer_func); + ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); + ctx->state.quantization = ntohl(p_hdr->quantization); +} + static int device_process(struct vicodec_ctx *ctx, struct vb2_v4l2_buffer *src_vb, struct vb2_v4l2_buffer *dst_vb) { struct vicodec_dev *dev = ctx->dev; - struct vicodec_q_data *q_dst; struct v4l2_fwht_state *state = &ctx->state; u8 *p_src, *p_dst; - int ret; + int ret = 0; - q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (ctx->is_enc) + if (ctx->is_enc || ctx->is_stateless) p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0); else p_src = state->compressed_frame; + + if (ctx->is_stateless) { + struct media_request *src_req = src_vb->vb2_buf.req_obj.req; + + ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl); + if (ret) + return ret; + update_state_from_header(ctx); + + ctx->state.header.size = + htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0)); + /* + * set the reference buffer from the reference timestamp + * only if this is a P-frame + */ + if (!(ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)) { + struct vb2_buffer *ref_vb2_buf; + int ref_buf_idx; + struct vb2_queue *vq_cap = + v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + + ref_buf_idx = vb2_find_timestamp(vq_cap, + ctx->state.ref_frame_ts, 0); + if (ref_buf_idx < 0) + return -EINVAL; + + ref_vb2_buf = vq_cap->bufs[ref_buf_idx]; + if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR) + ret = -EINVAL; + ctx->state.ref_frame.buf = + vb2_plane_vaddr(ref_vb2_buf, 0); + } else { + ctx->state.ref_frame.buf = NULL; + } + } p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0); if (!p_src || !p_dst) { v4l2_err(&dev->v4l2_dev, @@ -178,30 +306,31 @@ static int device_process(struct vicodec_ctx *ctx, if (ctx->is_enc) { struct vicodec_q_data *q_src; + int comp_sz_or_errcode; q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); state->info = q_src->info; - ret = v4l2_fwht_encode(state, p_src, p_dst); - if (ret < 0) - return ret; - vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret); + comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst); + if (comp_sz_or_errcode < 0) + return comp_sz_or_errcode; + vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode); } else { + struct vicodec_q_data *q_dst; unsigned int comp_frame_size = ntohl(ctx->state.header.size); + q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); if (comp_frame_size > ctx->comp_max_size) return -EINVAL; state->info = q_dst->info; ret = v4l2_fwht_decode(state, p_src, p_dst); if (ret < 0) return ret; + if (!ctx->is_stateless) + copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); + vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); } - - dst_vb->sequence = q_dst->sequence++; - dst_vb->flags &= ~V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, !ctx->is_enc); - - return 0; + return ret; } /* @@ -274,16 +403,26 @@ static void device_run(void *priv) struct vicodec_ctx *ctx = priv; struct vicodec_dev *dev = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct vicodec_q_data *q_src; + struct vicodec_q_data *q_src, *q_dst; u32 state; + struct media_request *src_req; + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + src_req = src_buf->vb2_buf.req_obj.req; + q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); state = VB2_BUF_STATE_DONE; if (device_process(ctx, src_buf, dst_buf)) state = VB2_BUF_STATE_ERROR; + else + dst_buf->sequence = q_dst->sequence++; + dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); + ctx->last_dst_buf = dst_buf; spin_lock(ctx->lock); @@ -291,7 +430,7 @@ static void device_run(void *priv) dst_buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_event_queue_fh(&ctx->fh, &eos_event); } - if (ctx->is_enc) { + if (ctx->is_enc || ctx->is_stateless) { src_buf->sequence = q_src->sequence++; src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, state); @@ -303,6 +442,9 @@ static void device_run(void *priv) ctx->comp_has_next_frame = false; } v4l2_m2m_buf_done(dst_buf, state); + if (ctx->is_stateless && src_req) + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + ctx->comp_size = 0; ctx->header_size = 0; ctx->comp_magic_cnt = 0; @@ -310,9 +452,12 @@ static void device_run(void *priv) spin_unlock(ctx->lock); if (ctx->is_enc) - v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx); + v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); + else if (ctx->is_stateless) + v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev, + ctx->fh.m2m_ctx); else - v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx); + v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx); } static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state) @@ -344,7 +489,7 @@ info_from_header(const struct fwht_cframe_hdr *p_hdr) FWHT_FL_COMPONENTS_NUM_OFFSET); pixenc = (flags & FWHT_FL_PIXENC_MSK); } - return v4l2_fwht_default_fmt(width_div, height_div, + return v4l2_fwht_find_nth_fmt(width_div, height_div, components_num, pixenc, 0); } @@ -356,21 +501,11 @@ static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr) unsigned int version = ntohl(p_hdr->version); unsigned int flags = ntohl(p_hdr->flags); - if (!version || version > FWHT_VERSION) - return false; - if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT) return false; - if (version >= 2) { - unsigned int components_num = 1 + - ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK; - - if (components_num == 0 || components_num > 4 || !pixenc) - return false; - } + if (!validate_by_version(flags, version)) + return false; info = info_from_header(p_hdr); if (!info) @@ -388,6 +523,12 @@ static void update_capture_data_from_header(struct vicodec_ctx *ctx) unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + /* + * This function should not be used by a stateless codec since + * it changes values in q_data that are not request specific + */ + WARN_ON(ctx->is_stateless); + q_dst->info = info; q_dst->visible_width = ntohl(p_hdr->width); q_dst->visible_height = ntohl(p_hdr->height); @@ -440,7 +581,7 @@ static int job_ready(void *priv) if (ctx->source_changed) return 0; - if (ctx->is_enc || ctx->comp_has_frame) + if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) return 1; restart: @@ -551,8 +692,8 @@ static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver)); + strscpy(cap->card, VICODEC_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", VICODEC_NAME); return 0; @@ -575,7 +716,7 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, if (!info || ctx->is_enc) info = v4l2_fwht_get_pixfmt(f->index); else - info = v4l2_fwht_default_fmt(info->width_div, + info = v4l2_fwht_find_nth_fmt(info->width_div, info->height_div, info->components_num, info->pixenc, @@ -586,7 +727,8 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, } else { if (f->index) return -EINVAL; - f->pixelformat = V4L2_PIX_FMT_FWHT; + f->pixelformat = ctx->is_stateless ? + V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT; } return 0; } @@ -688,13 +830,15 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) struct v4l2_pix_format_mplane *pix_mp; struct v4l2_pix_format *pix; struct v4l2_plane_pix_format *plane; - const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht; + const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? + &pixfmt_stateless_fwht : &pixfmt_fwht; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: pix = &f->fmt.pix; - if (pix->pixelformat != V4L2_PIX_FMT_FWHT) + if (pix->pixelformat != V4L2_PIX_FMT_FWHT && + pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) info = find_fmt(pix->pixelformat); pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); @@ -715,7 +859,8 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: pix_mp = &f->fmt.pix_mp; plane = pix_mp->plane_fmt; - if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT) + if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT && + pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) info = find_fmt(pix_mp->pixelformat); pix_mp->num_planes = 1; @@ -792,8 +937,12 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, if (multiplanar) return -EINVAL; pix = &f->fmt.pix; - pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(pix->pixelformat)->id; + if (ctx->is_enc) + pix->pixelformat = find_fmt(pix->pixelformat)->id; + else if (ctx->is_stateless) + pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; + else + pix->pixelformat = V4L2_PIX_FMT_FWHT; if (!pix->colorspace) pix->colorspace = V4L2_COLORSPACE_REC709; break; @@ -801,8 +950,12 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, if (!multiplanar) return -EINVAL; pix_mp = &f->fmt.pix_mp; - pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(pix_mp->pixelformat)->id; + if (ctx->is_enc) + pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id; + else if (ctx->is_stateless) + pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; + else + pix_mp->pixelformat = V4L2_PIX_FMT_FWHT; if (!pix_mp->colorspace) pix_mp->colorspace = V4L2_COLORSPACE_REC709; break; @@ -845,6 +998,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (pix->pixelformat == V4L2_PIX_FMT_FWHT) q_data->info = &pixfmt_fwht; + else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) + q_data->info = &pixfmt_stateless_fwht; else q_data->info = find_fmt(pix->pixelformat); q_data->coded_width = pix->width; @@ -866,6 +1021,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) q_data->info = &pixfmt_fwht; + else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) + q_data->info = &pixfmt_stateless_fwht; else q_data->info = find_fmt(pix_mp->pixelformat); q_data->coded_width = pix_mp->width; @@ -945,16 +1102,6 @@ static int vidioc_g_selection(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); struct vicodec_q_data *q_data; - enum v4l2_buf_type valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - enum v4l2_buf_type valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - if (multiplanar) { - valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - } - - if (s->type != valid_cap_type && s->type != valid_out_type) - return -EINVAL; q_data = get_q_data(ctx, s->type); if (!q_data) @@ -963,18 +1110,14 @@ static int vidioc_g_selection(struct file *file, void *priv, * encoder supports only cropping on the OUTPUT buffer * decoder supports only composing on the CAPTURE buffer */ - if ((ctx->is_enc && s->type == valid_out_type) || - (!ctx->is_enc && s->type == valid_cap_type)) { + if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_CROP: s->r.left = 0; s->r.top = 0; s->r.width = q_data->visible_width; s->r.height = q_data->visible_height; return 0; - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: s->r.left = 0; @@ -983,6 +1126,22 @@ static int vidioc_g_selection(struct file *file, void *priv, s->r.height = q_data->coded_height; return 0; } + } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + return 0; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + return 0; + } } return -EINVAL; } @@ -992,12 +1151,8 @@ static int vidioc_s_selection(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); struct vicodec_q_data *q_data; - enum v4l2_buf_type out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - if (multiplanar) - out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - if (s->type != out_type) + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; q_data = get_q_data(ctx, s->type); @@ -1092,6 +1247,8 @@ static int vicodec_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { switch (fsize->pixel_format) { + case V4L2_PIX_FMT_FWHT_STATELESS: + break; case V4L2_PIX_FMT_FWHT: break; default: @@ -1200,6 +1357,14 @@ static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, return 0; } +static int vicodec_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + static int vicodec_buf_prepare(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -1263,10 +1428,11 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) } /* - * source change event is relevant only for the decoder + * source change event is relevant only for the stateful decoder * in the compressed stream */ - if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (ctx->is_stateless || ctx->is_enc || + !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); return; } @@ -1314,12 +1480,33 @@ static void vicodec_return_bufs(struct vb2_queue *q, u32 state) vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); if (vbuf == NULL) return; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, + &ctx->hdl); spin_lock(ctx->lock); v4l2_m2m_buf_done(vbuf, state); spin_unlock(ctx->lock); } } +static unsigned int total_frame_size(struct vicodec_q_data *q_data) +{ + unsigned int size; + unsigned int chroma_div; + + if (!q_data->info) { + WARN_ON(1); + return 0; + } + size = q_data->coded_width * q_data->coded_height; + chroma_div = q_data->info->width_div * q_data->info->height_div; + + if (q_data->info->components_num == 4) + return 2 * size + 2 * (size / chroma_div); + else if (q_data->info->components_num == 3) + return size + 2 * (size / chroma_div); + return size; +} + static int vicodec_start_streaming(struct vb2_queue *q, unsigned int count) { @@ -1330,7 +1517,7 @@ static int vicodec_start_streaming(struct vb2_queue *q, unsigned int size = q_data->coded_width * q_data->coded_height; unsigned int chroma_div; unsigned int total_planes_size; - u8 *new_comp_frame; + u8 *new_comp_frame = NULL; if (!info) return -EINVAL; @@ -1338,24 +1525,24 @@ static int vicodec_start_streaming(struct vb2_queue *q, chroma_div = info->width_div * info->height_div; q_data->sequence = 0; - ctx->last_src_buf = NULL; - ctx->last_dst_buf = NULL; + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->last_src_buf = NULL; + else + ctx->last_dst_buf = NULL; + state->gop_cnt = 0; if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) return 0; - if (info->id == V4L2_PIX_FMT_FWHT) { + if (info->id == V4L2_PIX_FMT_FWHT || + info->id == V4L2_PIX_FMT_FWHT_STATELESS) { vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); return -EINVAL; } - if (info->components_num == 4) - total_planes_size = 2 * size + 2 * (size / chroma_div); - else if (info->components_num == 3) - total_planes_size = size + 2 * (size / chroma_div); - else - total_planes_size = size; + total_planes_size = total_frame_size(q_data); + ctx->comp_max_size = total_planes_size; state->visible_width = q_data->visible_width; state->visible_height = q_data->visible_height; @@ -1364,8 +1551,14 @@ static int vicodec_start_streaming(struct vb2_queue *q, state->stride = q_data->coded_width * info->bytesperline_mult; - state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL); - ctx->comp_max_size = total_planes_size; + if (ctx->is_stateless) { + state->ref_stride = state->stride; + return 0; + } + state->ref_stride = q_data->coded_width * info->luma_alpha_step; + + state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL); + state->ref_frame.luma = state->ref_frame.buf; new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); if (!state->ref_frame.luma || !new_comp_frame) { @@ -1413,7 +1606,10 @@ static void vicodec_stop_streaming(struct vb2_queue *q) if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { - kvfree(ctx->state.ref_frame.luma); + if (!ctx->is_stateless) + kvfree(ctx->state.ref_frame.buf); + ctx->state.ref_frame.buf = NULL; + ctx->state.ref_frame.luma = NULL; ctx->comp_max_size = 0; ctx->source_changed = false; } @@ -1427,14 +1623,24 @@ static void vicodec_stop_streaming(struct vb2_queue *q) } } +static void vicodec_buf_request_complete(struct vb2_buffer *vb) +{ + struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); +} + + static const struct vb2_ops vicodec_qops = { - .queue_setup = vicodec_queue_setup, - .buf_prepare = vicodec_buf_prepare, - .buf_queue = vicodec_buf_queue, - .start_streaming = vicodec_start_streaming, - .stop_streaming = vicodec_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, + .queue_setup = vicodec_queue_setup, + .buf_out_validate = vicodec_buf_out_validate, + .buf_prepare = vicodec_buf_prepare, + .buf_queue = vicodec_buf_queue, + .buf_request_complete = vicodec_buf_request_complete, + .start_streaming = vicodec_start_streaming, + .stop_streaming = vicodec_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -1452,9 +1658,14 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &vicodec_qops; src_vq->mem_ops = &vb2_vmalloc_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex : - &ctx->dev->dec_mutex; - + if (ctx->is_enc) + src_vq->lock = &ctx->dev->stateful_enc.mutex; + else if (ctx->is_stateless) + src_vq->lock = &ctx->dev->stateless_dec.mutex; + else + src_vq->lock = &ctx->dev->stateful_dec.mutex; + src_vq->supports_requests = ctx->is_stateless; + src_vq->requires_requests = ctx->is_stateless; ret = vb2_queue_init(src_vq); if (ret) return ret; @@ -1473,53 +1684,86 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return vb2_queue_init(dst_vq); } -#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000) -#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0) -#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1) +static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vicodec_ctx *ctx = container_of(ctrl->handler, + struct vicodec_ctx, hdl); + const struct v4l2_ctrl_fwht_params *params; + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + if (!q_dst->info) + return -EINVAL; + params = ctrl->p_new.p_fwht_params; + if (params->width > q_dst->coded_width || + params->width < MIN_WIDTH || + params->height > q_dst->coded_height || + params->height < MIN_HEIGHT) + return -EINVAL; + if (!validate_by_version(params->flags, params->version)) + return -EINVAL; + if (!validate_stateless_params_flags(params, q_dst->info)) + return -EINVAL; + return 0; + default: + return 0; + } + return 0; +} + +static void update_header_from_stateless_params(struct vicodec_ctx *ctx, + const struct v4l2_ctrl_fwht_params *params) +{ + struct fwht_cframe_hdr *p_hdr = &ctx->state.header; + + p_hdr->magic1 = FWHT_MAGIC1; + p_hdr->magic2 = FWHT_MAGIC2; + p_hdr->version = htonl(params->version); + p_hdr->width = htonl(params->width); + p_hdr->height = htonl(params->height); + p_hdr->flags = htonl(params->flags); + p_hdr->colorspace = htonl(params->colorspace); + p_hdr->xfer_func = htonl(params->xfer_func); + p_hdr->ycbcr_enc = htonl(params->ycbcr_enc); + p_hdr->quantization = htonl(params->quantization); +} static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl) { struct vicodec_ctx *ctx = container_of(ctrl->handler, struct vicodec_ctx, hdl); + const struct v4l2_ctrl_fwht_params *params; switch (ctrl->id) { case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ctx->state.gop_size = ctrl->val; return 0; - case VICODEC_CID_I_FRAME_QP: + case V4L2_CID_FWHT_I_FRAME_QP: ctx->state.i_frame_qp = ctrl->val; return 0; - case VICODEC_CID_P_FRAME_QP: + case V4L2_CID_FWHT_P_FRAME_QP: ctx->state.p_frame_qp = ctrl->val; return 0; + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + params = ctrl->p_new.p_fwht_params; + update_header_from_stateless_params(ctx, params); + ctx->state.ref_frame_ts = params->backward_ref_ts; + return 0; } return -EINVAL; } static const struct v4l2_ctrl_ops vicodec_ctrl_ops = { .s_ctrl = vicodec_s_ctrl, + .try_ctrl = vicodec_try_ctrl, }; -static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = { - .ops = &vicodec_ctrl_ops, - .id = VICODEC_CID_I_FRAME_QP, - .name = "FWHT I-Frame QP Value", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 31, - .def = 20, - .step = 1, -}; - -static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = { - .ops = &vicodec_ctrl_ops, - .id = VICODEC_CID_P_FRAME_QP, - .name = "FWHT P-Frame QP Value", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 31, - .def = 20, - .step = 1, +static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { + .ops = &vicodec_ctrl_ops, + .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS, + .elem_size = sizeof(struct v4l2_ctrl_fwht_params), }; /* @@ -1542,8 +1786,10 @@ static int vicodec_open(struct file *file) goto open_unlock; } - if (vfd == &dev->enc_vfd) + if (vfd == &dev->stateful_enc.vfd) ctx->is_enc = true; + else if (vfd == &dev->stateless_dec.vfd) + ctx->is_stateless = true; v4l2_fh_init(&ctx->fh, video_devdata(file)); file->private_data = &ctx->fh; @@ -1552,8 +1798,12 @@ static int vicodec_open(struct file *file) v4l2_ctrl_handler_init(hdl, 4); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 16, 1, 10); - v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL); - v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL); + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP, + 1, 31, 1, 20); + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, + 1, 31, 1, 20); + if (ctx->is_stateless) + v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); if (hdl->error) { rc = hdl->error; v4l2_ctrl_handler_free(hdl); @@ -1563,15 +1813,19 @@ static int vicodec_open(struct file *file) ctx->fh.ctrl_handler = hdl; v4l2_ctrl_handler_setup(hdl); - ctx->q_data[V4L2_M2M_SRC].info = - ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht; + if (ctx->is_enc) + ctx->q_data[V4L2_M2M_SRC].info = v4l2_fwht_get_pixfmt(0); + else if (ctx->is_stateless) + ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht; + else + ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht; ctx->q_data[V4L2_M2M_SRC].coded_width = 1280; ctx->q_data[V4L2_M2M_SRC].coded_height = 720; ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; ctx->q_data[V4L2_M2M_SRC].visible_height = 720; size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult / ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div; - if (ctx->is_enc) + if (ctx->is_enc || ctx->is_stateless) ctx->q_data[V4L2_M2M_SRC].sizeimage = size; else ctx->q_data[V4L2_M2M_SRC].sizeimage = @@ -1590,13 +1844,17 @@ static int vicodec_open(struct file *file) ctx->state.colorspace = V4L2_COLORSPACE_REC709; if (ctx->is_enc) { - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx, - &queue_init); - ctx->lock = &dev->enc_lock; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev, + ctx, &queue_init); + ctx->lock = &dev->stateful_enc.lock; + } else if (ctx->is_stateless) { + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev, + ctx, &queue_init); + ctx->lock = &dev->stateless_dec.lock; } else { - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx, - &queue_init); - ctx->lock = &dev->dec_lock; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev, + ctx, &queue_init); + ctx->lock = &dev->stateful_dec.lock; } if (IS_ERR(ctx->fh.m2m_ctx)) { @@ -1620,17 +1878,71 @@ static int vicodec_release(struct file *file) struct video_device *vfd = video_devdata(file); struct vicodec_ctx *ctx = file2ctx(file); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(vfd->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(vfd->lock); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); + kvfree(ctx->state.compressed_frame); kfree(ctx); return 0; } +static int vicodec_request_validate(struct media_request *req) +{ + struct media_request_object *obj; + struct v4l2_ctrl_handler *parent_hdl, *hdl; + struct vicodec_ctx *ctx = NULL; + struct v4l2_ctrl *ctrl; + unsigned int count; + + list_for_each_entry(obj, &req->objects, list) { + struct vb2_buffer *vb; + + if (vb2_request_object_is_buffer(obj)) { + vb = container_of(obj, struct vb2_buffer, req_obj); + ctx = vb2_get_drv_priv(vb->vb2_queue); + + break; + } + } + + if (!ctx) { + pr_err("No buffer was provided with the request\n"); + return -ENOENT; + } + + count = vb2_request_buffer_cnt(req); + if (!count) { + v4l2_info(&ctx->dev->v4l2_dev, + "No buffer was provided with the request\n"); + return -ENOENT; + } else if (count > 1) { + v4l2_info(&ctx->dev->v4l2_dev, + "More than one buffer was provided with the request\n"); + return -EINVAL; + } + + parent_hdl = &ctx->hdl; + + hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); + if (!hdl) { + v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n"); + return -ENOENT; + } + ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, + vicodec_ctrl_stateless_state.id); + if (!ctrl) { + v4l2_info(&ctx->dev->v4l2_dev, + "Missing required codec control\n"); + return -ENOENT; + } + + return vb2_request_validate(req); +} + static const struct v4l2_file_operations vicodec_fops = { .owner = THIS_MODULE, .open = vicodec_open, @@ -1649,24 +1961,67 @@ static const struct video_device vicodec_videodev = { .release = video_device_release_empty, }; +static const struct media_device_ops vicodec_m2m_media_ops = { + .req_validate = vicodec_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + static const struct v4l2_m2m_ops m2m_ops = { .device_run = device_run, .job_ready = job_ready, }; +static int register_instance(struct vicodec_dev *dev, + struct vicodec_dev_instance *dev_instance, + const char *name, bool is_enc) +{ + struct video_device *vfd; + int ret; + + spin_lock_init(&dev_instance->lock); + mutex_init(&dev_instance->mutex); + dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(dev_instance->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n"); + return PTR_ERR(dev_instance->m2m_dev); + } + + dev_instance->vfd = vicodec_videodev; + vfd = &dev_instance->vfd; + vfd->lock = &dev_instance->mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + strscpy(vfd->name, name, sizeof(vfd->name)); + vfd->device_caps = V4L2_CAP_STREAMING | + (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); + if (is_enc) { + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + } else { + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + } + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name); + v4l2_m2m_release(dev_instance->m2m_dev); + return ret; + } + v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n", + name, vfd->num); + return 0; +} + static int vicodec_probe(struct platform_device *pdev) { struct vicodec_dev *dev; - struct video_device *vfd; int ret; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - spin_lock_init(&dev->enc_lock); - spin_lock_init(&dev->dec_lock); - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) return ret; @@ -1677,103 +2032,74 @@ static int vicodec_probe(struct platform_device *pdev) strscpy(dev->mdev.bus_info, "platform:vicodec", sizeof(dev->mdev.bus_info)); media_device_init(&dev->mdev); + dev->mdev.ops = &vicodec_m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; #endif - mutex_init(&dev->enc_mutex); - mutex_init(&dev->dec_mutex); - platform_set_drvdata(pdev, dev); - dev->enc_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->enc_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n"); - ret = PTR_ERR(dev->enc_dev); + if (register_instance(dev, &dev->stateful_enc, + "stateful-encoder", true)) goto unreg_dev; - } - dev->dec_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->dec_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n"); - ret = PTR_ERR(dev->dec_dev); - goto err_enc_m2m; - } + if (register_instance(dev, &dev->stateful_dec, + "stateful-decoder", false)) + goto unreg_sf_enc; - dev->enc_vfd = vicodec_videodev; - vfd = &dev->enc_vfd; - vfd->lock = &dev->enc_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name)); - vfd->device_caps = V4L2_CAP_STREAMING | - (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto err_dec_m2m; - } - v4l2_info(&dev->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); + if (register_instance(dev, &dev->stateless_dec, + "stateless-decoder", false)) + goto unreg_sf_dec; - dev->dec_vfd = vicodec_videodev; - vfd = &dev->dec_vfd; - vfd->lock = &dev->dec_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->device_caps = V4L2_CAP_STREAMING | - (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); - strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name)); - v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); +#ifdef CONFIG_MEDIA_CONTROLLER + ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev, + &dev->stateful_enc.vfd, + MEDIA_ENT_F_PROC_VIDEO_ENCODER); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto unreg_enc; + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n"); + goto unreg_m2m; } - v4l2_info(&dev->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); -#ifdef CONFIG_MEDIA_CONTROLLER - ret = v4l2_m2m_register_media_controller(dev->enc_dev, - &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER); + ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev, + &dev->stateful_dec.vfd, + MEDIA_ENT_F_PROC_VIDEO_DECODER); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto unreg_m2m; + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n"); + goto unreg_m2m_sf_enc_mc; } - ret = v4l2_m2m_register_media_controller(dev->dec_dev, - &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER); + ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev, + &dev->stateless_dec.vfd, + MEDIA_ENT_F_PROC_VIDEO_DECODER); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto unreg_m2m_enc_mc; + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n"); + goto unreg_m2m_sf_dec_mc; } ret = media_device_register(&dev->mdev); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); - goto unreg_m2m_dec_mc; + goto unreg_m2m_sl_dec_mc; } #endif return 0; #ifdef CONFIG_MEDIA_CONTROLLER -unreg_m2m_dec_mc: - v4l2_m2m_unregister_media_controller(dev->dec_dev); -unreg_m2m_enc_mc: - v4l2_m2m_unregister_media_controller(dev->enc_dev); +unreg_m2m_sl_dec_mc: + v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); +unreg_m2m_sf_dec_mc: + v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); +unreg_m2m_sf_enc_mc: + v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); unreg_m2m: - video_unregister_device(&dev->dec_vfd); + video_unregister_device(&dev->stateless_dec.vfd); + v4l2_m2m_release(dev->stateless_dec.m2m_dev); #endif -unreg_enc: - video_unregister_device(&dev->enc_vfd); -err_dec_m2m: - v4l2_m2m_release(dev->dec_dev); -err_enc_m2m: - v4l2_m2m_release(dev->enc_dev); +unreg_sf_dec: + video_unregister_device(&dev->stateful_dec.vfd); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); +unreg_sf_enc: + video_unregister_device(&dev->stateful_enc.vfd); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); @@ -1788,15 +2114,17 @@ static int vicodec_remove(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); - v4l2_m2m_unregister_media_controller(dev->enc_dev); - v4l2_m2m_unregister_media_controller(dev->dec_dev); + v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); + v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); + v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); media_device_cleanup(&dev->mdev); #endif - v4l2_m2m_release(dev->enc_dev); - v4l2_m2m_release(dev->dec_dev); - video_unregister_device(&dev->enc_vfd); - video_unregister_device(&dev->dec_vfd); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); + video_unregister_device(&dev->stateful_enc.vfd); + video_unregister_device(&dev->stateful_dec.vfd); + video_unregister_device(&dev->stateless_dec.vfd); v4l2_device_unregister(&dev->v4l2_dev); return 0; diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 0ba30756e1e4..d8cd5f5cb10d 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -419,9 +419,14 @@ static int video_mux_probe(struct platform_device *pdev) vmux->active = -1; vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads), GFP_KERNEL); + if (!vmux->pads) + return -ENOMEM; + vmux->format_mbus = devm_kcalloc(dev, num_pads, sizeof(*vmux->format_mbus), GFP_KERNEL); + if (!vmux->format_mbus) + return -ENOMEM; for (i = 0; i < num_pads; i++) { vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 34dcaca45d8b..243c82b5d537 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -302,7 +302,7 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in, switch (in->fourcc) { case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ for (i = 0; i < 2; i++) { - u16 pix = *(u16 *)(src[i]); + u16 pix = le16_to_cpu(*(__le16 *)(src[i])); *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; @@ -311,12 +311,11 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in, break; case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ for (i = 0; i < 2; i++) { - u16 pix = *(u16 *)(src[i]); + u16 pix = be16_to_cpu(*(__be16 *)(src[i])); - *r++ = (u8)(((0x00f8 & pix) >> 3) << 3) | 0x07; - *g++ = (u8)(((pix & 0x7) << 2) | - ((pix & 0xe000) >> 5)) | 0x03; - *b++ = (u8)(((pix & 0x1f00) >> 8) << 3) | 0x07; + *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; + *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; + *b++ = (u8)((pix & 0x1f) << 3) | 0x07; } break; default: @@ -345,21 +344,26 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in, switch (out->fourcc) { case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ for (i = 0; i < 2; i++) { - u16 *pix = (u16 *)*dst; + u16 pix; + __le16 *dst_pix = (__le16 *)*dst; + + pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); - *pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | - (*b >> 3); + *dst_pix = cpu_to_le16(pix); *dst += 2; } return; case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ for (i = 0; i < 2; i++) { - u16 *pix = (u16 *)*dst; - u8 green = *g++ >> 2; + u16 pix; + __be16 *dst_pix = (__be16 *)*dst; - *pix = ((green << 8) & 0xe000) | (green & 0x07) | - ((*b++ << 5) & 0x1f00) | ((*r++ & 0xf8)); + pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); + + *dst_pix = cpu_to_be16(pix); *dst += 2; } @@ -655,8 +659,8 @@ static void device_work(struct work_struct *w) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", MEM2MEM_NAME); return 0; @@ -1262,6 +1266,15 @@ static int vim2m_release(struct file *file) return 0; } +static void vim2m_device_release(struct video_device *vdev) +{ + struct vim2m_dev *dev = container_of(vdev, struct vim2m_dev, vfd); + + v4l2_device_unregister(&dev->v4l2_dev); + v4l2_m2m_release(dev->m2m_dev); + kfree(dev); +} + static const struct v4l2_file_operations vim2m_fops = { .owner = THIS_MODULE, .open = vim2m_open, @@ -1277,7 +1290,7 @@ static const struct video_device vim2m_videodev = { .fops = &vim2m_fops, .ioctl_ops = &vim2m_ioctl_ops, .minor = -1, - .release = video_device_release_empty, + .release = vim2m_device_release, .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; @@ -1298,13 +1311,13 @@ static int vim2m_probe(struct platform_device *pdev) struct video_device *vfd; int ret; - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - return ret; + goto error_free; atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); @@ -1317,7 +1330,7 @@ static int vim2m_probe(struct platform_device *pdev) ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto unreg_v4l2; + goto error_v4l2; } video_set_drvdata(vfd, dev); @@ -1330,7 +1343,7 @@ static int vim2m_probe(struct platform_device *pdev) if (IS_ERR(dev->m2m_dev)) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); ret = PTR_ERR(dev->m2m_dev); - goto unreg_dev; + goto error_dev; } #ifdef CONFIG_MEDIA_CONTROLLER @@ -1346,27 +1359,29 @@ static int vim2m_probe(struct platform_device *pdev) MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto unreg_m2m; + goto error_m2m; } ret = media_device_register(&dev->mdev); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); - goto unreg_m2m_mc; + goto error_m2m_mc; } #endif return 0; #ifdef CONFIG_MEDIA_CONTROLLER -unreg_m2m_mc: +error_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); -unreg_m2m: +error_m2m: v4l2_m2m_release(dev->m2m_dev); #endif -unreg_dev: +error_dev: video_unregister_device(&dev->vfd); -unreg_v4l2: +error_v4l2: v4l2_device_unregister(&dev->v4l2_dev); +error_free: + kfree(dev); return ret; } @@ -1382,9 +1397,7 @@ static int vim2m_remove(struct platform_device *pdev) v4l2_m2m_unregister_media_controller(dev->m2m_dev); media_device_cleanup(&dev->mdev); #endif - v4l2_m2m_release(dev->m2m_dev); video_unregister_device(&dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); return 0; } diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig index 71c9fe7d3370..1de9bc9aa49b 100644 --- a/drivers/media/platform/vimc/Kconfig +++ b/drivers/media/platform/vimc/Kconfig @@ -4,7 +4,7 @@ config VIDEO_VIMC select VIDEOBUF2_VMALLOC select VIDEO_V4L2_TPG default n - ---help--- + help Skeleton driver for Virtual Media Controller This driver can be compared to the vivid driver for emulating diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index ea869631a3f6..e7d0fc2228a6 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -28,6 +28,32 @@ #define VIMC_CAP_DRV_NAME "vimc-capture" +static const u32 vimc_cap_supported_pixfmt[] = { + V4L2_PIX_FMT_BGR24, + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_ARGB32, + V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_SGBRG8, + V4L2_PIX_FMT_SGRBG8, + V4L2_PIX_FMT_SRGGB8, + V4L2_PIX_FMT_SBGGR10, + V4L2_PIX_FMT_SGBRG10, + V4L2_PIX_FMT_SGRBG10, + V4L2_PIX_FMT_SRGGB10, + V4L2_PIX_FMT_SBGGR10ALAW8, + V4L2_PIX_FMT_SGBRG10ALAW8, + V4L2_PIX_FMT_SGRBG10ALAW8, + V4L2_PIX_FMT_SRGGB10ALAW8, + V4L2_PIX_FMT_SBGGR10DPCM8, + V4L2_PIX_FMT_SGBRG10DPCM8, + V4L2_PIX_FMT_SGRBG10DPCM8, + V4L2_PIX_FMT_SRGGB10DPCM8, + V4L2_PIX_FMT_SBGGR12, + V4L2_PIX_FMT_SGBRG12, + V4L2_PIX_FMT_SGRBG12, + V4L2_PIX_FMT_SRGGB12, +}; + struct vimc_cap_device { struct vimc_ent_device ved; struct video_device vdev; @@ -101,29 +127,25 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *format = &f->fmt.pix; - const struct vimc_pix_map *vpix; format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; format->height = clamp_t(u32, format->height, VIMC_FRAME_MIN_HEIGHT, VIMC_FRAME_MAX_HEIGHT) & ~1; - /* Don't accept a pixelformat that is not on the table */ - vpix = vimc_pix_map_by_pixelformat(format->pixelformat); - if (!vpix) { - format->pixelformat = fmt_default.pixelformat; - vpix = vimc_pix_map_by_pixelformat(format->pixelformat); - } - /* TODO: Add support for custom bytesperline values */ - format->bytesperline = format->width * vpix->bpp; - format->sizeimage = format->bytesperline * format->height; + vimc_colorimetry_clamp(format); if (format->field == V4L2_FIELD_ANY) format->field = fmt_default.field; - vimc_colorimetry_clamp(format); + /* TODO: Add support for custom bytesperline values */ - return 0; + /* Don't accept a pixelformat that is not on the table */ + if (!v4l2_format_info(format->pixelformat)) + format->pixelformat = fmt_default.pixelformat; + + return v4l2_fill_pixfmt(format, format->pixelformat, + format->width, format->height); } static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, @@ -159,27 +181,31 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index); - - if (!vpix) + if (f->index >= ARRAY_SIZE(vimc_cap_supported_pixfmt)) return -EINVAL; - f->pixelformat = vpix->pixelformat; + f->pixelformat = vimc_cap_supported_pixfmt[f->index]; return 0; } +static bool vimc_cap_is_pixfmt_supported(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_cap_supported_pixfmt); i++) + if (vimc_cap_supported_pixfmt[i] == pixelformat) + return true; + return false; +} + static int vimc_cap_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { - const struct vimc_pix_map *vpix; - if (fsize->index) return -EINVAL; - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fsize->pixel_format); - if (!vpix) + if (!vimc_cap_is_pixfmt_supported(fsize->pixel_format)) return -EINVAL; fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; @@ -187,8 +213,8 @@ static int vimc_cap_enum_framesizes(struct file *file, void *fh, fsize->stepwise.max_width = VIMC_FRAME_MAX_WIDTH; fsize->stepwise.min_height = VIMC_FRAME_MIN_HEIGHT; fsize->stepwise.max_height = VIMC_FRAME_MAX_HEIGHT; - fsize->stepwise.step_width = 2; - fsize->stepwise.step_height = 2; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; return 0; } @@ -253,6 +279,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } + vcap->stream.producer_pixfmt = vcap->format.pixelformat; ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); if (ret) { media_pipeline_stop(entity); @@ -338,6 +365,15 @@ static const struct media_entity_operations vimc_cap_mops = { .link_validate = vimc_link_validate, }; +static void vimc_cap_release(struct video_device *vdev) +{ + struct vimc_cap_device *vcap = + container_of(vdev, struct vimc_cap_device, vdev); + + vimc_pads_cleanup(vcap->ved.pads); + kfree(vcap); +} + static void vimc_cap_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -348,8 +384,6 @@ static void vimc_cap_comp_unbind(struct device *comp, struct device *master, vb2_queue_release(&vcap->queue); media_entity_cleanup(ved->ent); video_unregister_device(&vcap->vdev); - vimc_pads_cleanup(vcap->ved.pads); - kfree(vcap); } static void *vimc_cap_process_frame(struct vimc_ent_device *ved, @@ -396,7 +430,6 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, { struct v4l2_device *v4l2_dev = master_data; struct vimc_platform_data *pdata = comp->platform_data; - const struct vimc_pix_map *vpix; struct vimc_cap_device *vcap; struct video_device *vdev; struct vb2_queue *q; @@ -451,10 +484,8 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, /* 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; + v4l2_fill_pixfmt(&vcap->format, vcap->format.pixelformat, + vcap->format.width, vcap->format.height); /* Fill the vimc_ent_device struct */ vcap->ved.ent = &vcap->vdev.entity; @@ -467,7 +498,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, vdev = &vcap->vdev; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; vdev->entity.ops = &vimc_cap_mops; - vdev->release = video_device_release_empty; + vdev->release = vimc_cap_release; vdev->fops = &vimc_cap_fops; vdev->ioctl_ops = &vimc_cap_ioctl_ops; vdev->lock = &vcap->lock; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index c1a74bb2df58..fad7c7c6de93 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -20,192 +20,139 @@ #include "vimc-common.h" -/* - * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code - * in the scaler) - */ -static const struct vimc_pix_map vimc_pix_map_list[] = { - /* TODO: add all missing formats */ - - /* RGB formats */ - { - .code = MEDIA_BUS_FMT_BGR888_1X24, - .pixelformat = V4L2_PIX_FMT_BGR24, - .bpp = 3, - .bayer = false, - }, - { - .code = MEDIA_BUS_FMT_RGB888_1X24, - .pixelformat = V4L2_PIX_FMT_RGB24, - .bpp = 3, - .bayer = false, - }, - { - .code = MEDIA_BUS_FMT_ARGB8888_1X32, - .pixelformat = V4L2_PIX_FMT_ARGB32, - .bpp = 4, - .bayer = false, - }, - - /* Bayer formats */ - { - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pixelformat = V4L2_PIX_FMT_SGBRG8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pixelformat = V4L2_PIX_FMT_SGRBG8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pixelformat = V4L2_PIX_FMT_SRGGB8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pixelformat = V4L2_PIX_FMT_SBGGR10, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pixelformat = V4L2_PIX_FMT_SGBRG10, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pixelformat = V4L2_PIX_FMT_SGRBG10, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pixelformat = V4L2_PIX_FMT_SRGGB10, - .bpp = 2, - .bayer = true, - }, - - /* 10bit raw bayer a-law compressed to 8 bits */ - { - .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, - .bpp = 1, - .bayer = true, - }, - - /* 10bit raw bayer DPCM compressed to 8 bits */ - { - .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pixelformat = V4L2_PIX_FMT_SBGGR12, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pixelformat = V4L2_PIX_FMT_SGBRG12, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pixelformat = V4L2_PIX_FMT_SGRBG12, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pixelformat = V4L2_PIX_FMT_SRGGB12, - .bpp = 2, - .bayer = true, - }, +static const __u32 vimc_mbus_list[] = { + MEDIA_BUS_FMT_FIXED, + MEDIA_BUS_FMT_RGB444_1X12, + MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, + MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, + MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + MEDIA_BUS_FMT_RGB565_1X16, + MEDIA_BUS_FMT_BGR565_2X8_BE, + MEDIA_BUS_FMT_BGR565_2X8_LE, + MEDIA_BUS_FMT_RGB565_2X8_BE, + MEDIA_BUS_FMT_RGB565_2X8_LE, + MEDIA_BUS_FMT_RGB666_1X18, + MEDIA_BUS_FMT_RBG888_1X24, + MEDIA_BUS_FMT_RGB666_1X24_CPADHI, + MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + MEDIA_BUS_FMT_BGR888_1X24, + MEDIA_BUS_FMT_GBR888_1X24, + MEDIA_BUS_FMT_RGB888_1X24, + MEDIA_BUS_FMT_RGB888_2X12_BE, + MEDIA_BUS_FMT_RGB888_2X12_LE, + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_RGB888_1X32_PADHI, + MEDIA_BUS_FMT_RGB101010_1X30, + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_RGB161616_1X48, + MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_UV8_1X8, + MEDIA_BUS_FMT_UYVY8_1_5X8, + MEDIA_BUS_FMT_VYUY8_1_5X8, + MEDIA_BUS_FMT_YUYV8_1_5X8, + MEDIA_BUS_FMT_YVYU8_1_5X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, + MEDIA_BUS_FMT_UYVY10_2X10, + MEDIA_BUS_FMT_VYUY10_2X10, + MEDIA_BUS_FMT_YUYV10_2X10, + MEDIA_BUS_FMT_YVYU10_2X10, + MEDIA_BUS_FMT_Y12_1X12, + MEDIA_BUS_FMT_UYVY12_2X12, + MEDIA_BUS_FMT_VYUY12_2X12, + MEDIA_BUS_FMT_YUYV12_2X12, + MEDIA_BUS_FMT_YVYU12_2X12, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_YDYUYDYV8_1X16, + MEDIA_BUS_FMT_UYVY10_1X20, + MEDIA_BUS_FMT_VYUY10_1X20, + MEDIA_BUS_FMT_YUYV10_1X20, + MEDIA_BUS_FMT_YVYU10_1X20, + MEDIA_BUS_FMT_VUY8_1X24, + MEDIA_BUS_FMT_YUV8_1X24, + MEDIA_BUS_FMT_UYYVYY8_0_5X24, + MEDIA_BUS_FMT_UYVY12_1X24, + MEDIA_BUS_FMT_VYUY12_1X24, + MEDIA_BUS_FMT_YUYV12_1X24, + MEDIA_BUS_FMT_YVYU12_1X24, + MEDIA_BUS_FMT_YUV10_1X30, + MEDIA_BUS_FMT_UYYVYY10_0_5X30, + MEDIA_BUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_UYYVYY12_0_5X36, + MEDIA_BUS_FMT_YUV12_1X36, + MEDIA_BUS_FMT_YUV16_1X48, + MEDIA_BUS_FMT_UYYVYY16_0_5X48, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, + MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, + MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, + MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, + MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, + MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SBGGR14_1X14, + MEDIA_BUS_FMT_SGBRG14_1X14, + MEDIA_BUS_FMT_SGRBG14_1X14, + MEDIA_BUS_FMT_SRGGB14_1X14, + MEDIA_BUS_FMT_SBGGR16_1X16, + MEDIA_BUS_FMT_SGBRG16_1X16, + MEDIA_BUS_FMT_SGRBG16_1X16, + MEDIA_BUS_FMT_SRGGB16_1X16, + MEDIA_BUS_FMT_JPEG_1X8, + MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, + MEDIA_BUS_FMT_AHSV8888_1X32, }; -const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) -{ - if (i >= ARRAY_SIZE(vimc_pix_map_list)) - return NULL; - - return &vimc_pix_map_list[i]; -} -EXPORT_SYMBOL_GPL(vimc_pix_map_by_index); - -const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) +/* Helper function to check mbus codes */ +bool vimc_mbus_code_supported(__u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { - if (vimc_pix_map_list[i].code == code) - return &vimc_pix_map_list[i]; - } - return NULL; + for (i = 0; i < ARRAY_SIZE(vimc_mbus_list); i++) + if (code == vimc_mbus_list[i]) + return true; + return false; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_code); +EXPORT_SYMBOL_GPL(vimc_mbus_code_supported); -const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) +/* Helper function to enumerate mbus codes */ +int vimc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - unsigned int i; + if (code->index >= ARRAY_SIZE(vimc_mbus_list)) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { - if (vimc_pix_map_list[i].pixelformat == pixelformat) - return &vimc_pix_map_list[i]; - } - return NULL; + code->code = vimc_mbus_list[code->index]; + return 0; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); +EXPORT_SYMBOL_GPL(vimc_enum_mbus_code); /* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) @@ -277,15 +224,13 @@ static int vimc_get_mbus_format(struct media_pad *pad, struct video_device, entity); struct vimc_ent_device *ved = video_get_drvdata(vdev); - const struct vimc_pix_map *vpix; struct v4l2_pix_format vdev_fmt; if (!ved->vdev_get_format) return -ENOIOCTLCMD; ved->vdev_get_format(ved, &vdev_fmt); - vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); - v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); + v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, 0); } else { return -EINVAL; } @@ -325,8 +270,12 @@ int vimc_link_validate(struct media_link *link) /* The width, height and code must match. */ if (source_fmt.format.width != sink_fmt.format.width || source_fmt.format.height != sink_fmt.format.height - || source_fmt.format.code != sink_fmt.format.code) + || (source_fmt.format.code && sink_fmt.format.code && + source_fmt.format.code != sink_fmt.format.code)) { + pr_err("vimc: format doesn't match in link %s->%s\n", + link->source->entity->name, link->sink->entity->name); return -EPIPE; + } /* * The field order must match, or the sink field order must be NONE @@ -380,6 +329,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, const unsigned long *pads_flag, + const struct v4l2_subdev_internal_ops *sd_int_ops, const struct v4l2_subdev_ops *sd_ops) { int ret; @@ -394,6 +344,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, /* Initialize the subdev */ v4l2_subdev_init(sd, sd_ops); + sd->internal_ops = sd_int_ops; sd->entity.function = function; sd->entity.ops = &vimc_ent_sd_mops; sd->owner = THIS_MODULE; @@ -431,9 +382,9 @@ EXPORT_SYMBOL_GPL(vimc_ent_sd_register); void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) { - v4l2_device_unregister_subdev(sd); media_entity_cleanup(ved->ent); vimc_pads_cleanup(ved->pads); + v4l2_device_unregister_subdev(sd); } EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister); diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 84539430b5e7..142ddfa69b3d 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h @@ -22,6 +22,8 @@ #include <media/media-device.h> #include <media/v4l2-device.h> +#include "vimc-streamer.h" + #define VIMC_PDEV_NAME "vimc" /* VIMC-specific controls */ @@ -78,23 +80,6 @@ struct vimc_platform_data { }; /** - * struct vimc_pix_map - maps media bus code with v4l2 pixel format - * - * @code: media bus format code defined by MEDIA_BUS_FMT_* macros - * @bbp: number of bytes each pixel occupies - * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros - * - * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding - * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp) - */ -struct vimc_pix_map { - unsigned int code; - unsigned int bpp; - u32 pixelformat; - bool bayer; -}; - -/** * struct vimc_ent_device - core struct that represents a node in the topology * * @ent: the pointer to struct media_entity for the node @@ -115,6 +100,7 @@ struct vimc_pix_map { struct vimc_ent_device { struct media_entity *ent; struct media_pad *pads; + struct vimc_stream *stream; void * (*process_frame)(struct vimc_ent_device *ved, const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved, @@ -122,6 +108,23 @@ struct vimc_ent_device { }; /** + * vimc_mbus_code_supported - helper to check supported mbus codes + * + * Helper function to check if mbus code is enumerated by vimc_enum_mbus_code() + */ +bool vimc_mbus_code_supported(__u32 code); + +/** + * vimc_enum_mbus_code - enumerate mbus codes + * + * Helper function to be pluged in .enum_mbus_code from + * struct v4l2_subdev_pad_ops. + */ +int vimc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code); + +/** * vimc_pads_init - initialize pads * * @num_pads: number of pads to initialize @@ -156,27 +159,6 @@ static inline void vimc_pads_cleanup(struct media_pad *pads) int vimc_pipeline_s_stream(struct media_entity *ent, int enable); /** - * vimc_pix_map_by_index - get vimc_pix_map struct by its index - * - * @i: index of the vimc_pix_map struct in vimc_pix_map_list - */ -const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i); - -/** - * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code - * - * @code: media bus format code defined by MEDIA_BUS_FMT_* macros - */ -const struct vimc_pix_map *vimc_pix_map_by_code(u32 code); - -/** - * vimc_pix_map_by_pixelformat - get vimc_pix_map struct by v4l2 pixel format - * - * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros - */ -const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); - -/** * vimc_ent_sd_register - initialize and register a subdev node * * @ved: the vimc_ent_device struct to be initialize @@ -187,6 +169,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); * @function: media entity function defined by MEDIA_ENT_F_* macros * @num_pads: number of pads to initialize * @pads_flag: flags to use in each pad + * @sd_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 @@ -199,6 +182,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, const unsigned long *pads_flag, + const struct v4l2_subdev_internal_ops *sd_int_ops, const struct v4l2_subdev_ops *sd_ops); /** diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 0fbb7914098f..3aa62d7e3d0e 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -304,6 +304,8 @@ static int vimc_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "probe"); + memset(&vimc->mdev, 0, sizeof(vimc->mdev)); + /* Create platform_device for each entity in the topology*/ vimc->subdevs = devm_kcalloc(&vimc->pdev.dev, vimc->pipe_cfg->num_ents, sizeof(*vimc->subdevs), GFP_KERNEL); diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 7d77c63b99d2..281f9c1a7249 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -26,6 +26,9 @@ #include "vimc-common.h" #define VIMC_DEB_DRV_NAME "vimc-debayer" +/* This module only supports tranforming a bayer format to V4L2_PIX_FMT_RGB24 */ +#define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24 +#define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24 static unsigned int deb_mean_win_size = 3; module_param(deb_mean_win_size, uint, 0000); @@ -44,6 +47,7 @@ enum vimc_deb_rgb_colors { }; struct vimc_deb_pix_map { + u32 pixelformat; u32 code; enum vimc_deb_rgb_colors order[2][2]; }; @@ -66,68 +70,80 @@ struct vimc_deb_device { static const struct v4l2_mbus_framefmt sink_fmt_default = { .width = 640, .height = 480, - .code = MEDIA_BUS_FMT_RGB888_1X24, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_DEFAULT, }; static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { { + .pixelformat = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { + .pixelformat = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } }, { + .pixelformat = V4L2_PIX_FMT_SBGGR10, .code = MEDIA_BUS_FMT_SBGGR10_1X10, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { + .pixelformat = V4L2_PIX_FMT_SGBRG10, .code = MEDIA_BUS_FMT_SGBRG10_1X10, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SGRBG10, .code = MEDIA_BUS_FMT_SGRBG10_1X10, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SRGGB10, .code = MEDIA_BUS_FMT_SRGGB10_1X10, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } }, { + .pixelformat = V4L2_PIX_FMT_SBGGR12, .code = MEDIA_BUS_FMT_SBGGR12_1X12, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { + .pixelformat = V4L2_PIX_FMT_SGBRG12, .code = MEDIA_BUS_FMT_SGBRG12_1X12, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SGRBG12, .code = MEDIA_BUS_FMT_SGRBG12_1X12, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SRGGB12, .code = MEDIA_BUS_FMT_SRGGB12_1X12, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } @@ -168,41 +184,32 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { - /* We only support one format for source pads */ - if (IS_SRC(code->pad)) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - if (code->index) - return -EINVAL; - - code->code = vdeb->src_code; - } else { + /* For the sink pad we only support codes in the map_list */ + if (IS_SINK(code->pad)) { if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) return -EINVAL; code->code = vimc_deb_pix_map_list[code->index].code; + return 0; } - return 0; + return vimc_enum_mbus_code(sd, cfg, code); } static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - if (fse->index) return -EINVAL; + /* For the sink pad we only support codes in the map_list */ if (IS_SINK(fse->pad)) { const struct vimc_deb_pix_map *vpix = vimc_deb_pix_map_by_code(fse->code); if (!vpix) return -EINVAL; - } else if (fse->code != vdeb->src_code) { - return -EINVAL; } fse->min_width = VIMC_FRAME_MIN_WIDTH; @@ -258,6 +265,9 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; + if (!vimc_mbus_code_supported(fmt->format.code)) + fmt->format.code = sink_fmt_default.code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ if (vdeb->src_frame) @@ -270,11 +280,11 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, /* * Do not change the format of the source pad, - * it is propagated from the sink + * it is propagated from the sink (except for the code) */ if (IS_SRC(fmt->pad)) { + vdeb->src_code = fmt->format.code; fmt->format = *sink_fmt; - /* TODO: Add support for other formats */ fmt->format.code = vdeb->src_code; } else { /* Set the new format in the sink pad */ @@ -306,7 +316,7 @@ static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { .set_fmt = vimc_deb_set_fmt, }; -static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb, +static void vimc_deb_set_rgb_pix_rgb24(struct vimc_deb_device *vdeb, unsigned int lin, unsigned int col, unsigned int rgb[3]) @@ -323,25 +333,38 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); if (enable) { - const struct vimc_pix_map *vpix; + u32 src_pixelformat = vdeb->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; unsigned int frame_size; if (vdeb->src_frame) return 0; - /* 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; - - /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code); - vdeb->sink_bpp = vpix->bpp; + /* We only support translating bayer to RGB24 */ + if (src_pixelformat != V4L2_PIX_FMT_RGB24) { + dev_err(vdeb->dev, + "translating to pixfmt (0x%08x) is not supported\n", + src_pixelformat); + return -EINVAL; + } /* Get the corresponding pixel map from the table */ vdeb->sink_pix_map = vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); + /* Request bayer format from the pipeline for the sink pad */ + vdeb->ved.stream->producer_pixfmt = + vdeb->sink_pix_map->pixelformat; + + /* Calculate frame_size of the source */ + pix_info = v4l2_format_info(src_pixelformat); + frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * + pix_info->bpp[0]; + + /* Get bpp from the sink */ + pix_info = v4l2_format_info(vdeb->sink_pix_map->pixelformat); + vdeb->sink_bpp = pix_info->bpp[0]; + /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory @@ -489,6 +512,18 @@ static void *vimc_deb_process_frame(struct vimc_ent_device *ved, } +static void vimc_deb_release(struct v4l2_subdev *sd) +{ + struct vimc_deb_device *vdeb = + container_of(sd, struct vimc_deb_device, sd); + + kfree(vdeb); +} + +static const struct v4l2_subdev_internal_ops vimc_deb_int_ops = { + .release = vimc_deb_release, +}; + static void vimc_deb_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -497,7 +532,6 @@ static void vimc_deb_comp_unbind(struct device *comp, struct device *master, ved); vimc_ent_sd_unregister(ved, &vdeb->sd); - kfree(vdeb); } static int vimc_deb_comp_bind(struct device *comp, struct device *master, @@ -519,7 +553,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, - &vimc_deb_ops); + &vimc_deb_int_ops, &vimc_deb_ops); if (ret) { kfree(vdeb); return ret; @@ -531,14 +565,14 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, /* Initialize the frame format */ vdeb->sink_fmt = sink_fmt_default; + vdeb->src_code = VIMC_DEB_SRC_MBUS_FMT_DEFAULT; /* * TODO: Add support for more output formats, we only support - * RGB888 for now + * RGB24 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_set_rgb_mbus_fmt_rgb888_1x24; + vdeb->set_rgb_src = vimc_deb_set_rgb_pix_rgb24; return 0; } diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index 39b2a73dfcc1..8aecf8e92031 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -35,6 +35,12 @@ MODULE_PARM_DESC(sca_mult, " the image size multiplier"); #define IS_SRC(pad) (pad) #define MAX_ZOOM 8 +static const u32 vimc_sca_supported_pixfmt[] = { + V4L2_PIX_FMT_BGR24, + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_ARGB32, +}; + struct vimc_sca_device { struct vimc_ent_device ved; struct v4l2_subdev sd; @@ -57,6 +63,16 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = { .colorspace = V4L2_COLORSPACE_DEFAULT, }; +static bool vimc_sca_is_pixfmt_supported(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_sca_supported_pixfmt); i++) + if (vimc_sca_supported_pixfmt[i] == pixelformat) + return true; + return false; +} + static int vimc_sca_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg) { @@ -76,35 +92,13 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd, return 0; } -static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); - - /* We don't support bayer format */ - if (!vpix || vpix->bayer) - return -EINVAL; - - code->code = vpix->code; - - return 0; -} - static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - const struct vimc_pix_map *vpix; - if (fse->index) return -EINVAL; - /* Only accept code in the pix map table in non bayer format */ - vpix = vimc_pix_map_by_code(fse->code); - if (!vpix || vpix->bayer) - return -EINVAL; - fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; @@ -141,13 +135,6 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd, static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) { - 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; - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, @@ -166,6 +153,9 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; + if (!vimc_mbus_code_supported(fmt->format.code)) + fmt->format.code = sink_fmt_default.code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ if (vsca->src_frame) @@ -208,7 +198,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, 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_mbus_code = vimc_enum_mbus_code, .enum_frame_size = vimc_sca_enum_frame_size, .get_fmt = vimc_sca_get_fmt, .set_fmt = vimc_sca_set_fmt, @@ -219,15 +209,22 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); if (enable) { - const struct vimc_pix_map *vpix; + u32 pixelformat = vsca->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; unsigned int frame_size; if (vsca->src_frame) return 0; + if (!vimc_sca_is_pixfmt_supported(pixelformat)) { + dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n", + pixelformat); + return -EINVAL; + } + /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); - vsca->bpp = vpix->bpp; + pix_info = v4l2_format_info(pixelformat); + vsca->bpp = pix_info->bpp[0]; /* Calculate the width in bytes of the src frame */ vsca->src_line_size = vsca->sink_fmt.width * @@ -348,6 +345,18 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved, return vsca->src_frame; }; +static void vimc_sca_release(struct v4l2_subdev *sd) +{ + struct vimc_sca_device *vsca = + container_of(sd, struct vimc_sca_device, sd); + + kfree(vsca); +} + +static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = { + .release = vimc_sca_release, +}; + static void vimc_sca_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -356,7 +365,6 @@ static void vimc_sca_comp_unbind(struct device *comp, struct device *master, ved); vimc_ent_sd_unregister(ved, &vsca->sd); - kfree(vsca); } @@ -379,7 +387,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master, MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, - &vimc_sca_ops); + &vimc_sca_int_ops, &vimc_sca_ops); if (ret) { kfree(vsca); return ret; diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 59195f262623..081e54204c9f 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -65,34 +65,13 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd, return 0; } -static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); - - if (!vpix) - return -EINVAL; - - code->code = vpix->code; - - return 0; -} - static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - const struct vimc_pix_map *vpix; - if (fse->index) return -EINVAL; - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fse->code); - if (!vpix) - return -EINVAL; - fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->max_width = VIMC_FRAME_MAX_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; @@ -117,14 +96,17 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd, 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); + u32 pixelformat = vsen->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; + + pix_info = v4l2_format_info(pixelformat); 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_bytesperline(&vsen->tpg, 0, + vsen->mbus_format.width * pix_info->bpp[0]); tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); - tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); + tpg_s_fourcc(&vsen->tpg, 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); @@ -135,13 +117,6 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) { - const struct vimc_pix_map *vpix; - - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fmt->code); - if (!vpix) - fmt->code = fmt_default.code; - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, @@ -161,6 +136,9 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; + if (!vimc_mbus_code_supported(fmt->format.code)) + fmt->format.code = fmt_default.code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ if (vsen->frame) @@ -193,7 +171,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, 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_mbus_code = vimc_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size, .get_fmt = vimc_sen_get_fmt, .set_fmt = vimc_sen_set_fmt, @@ -215,7 +193,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) container_of(sd, struct vimc_sen_device, sd); if (enable) { - const struct vimc_pix_map *vpix; + u32 pixelformat = vsen->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; unsigned int frame_size; if (vsen->kthread_sen) @@ -223,8 +202,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) return 0; /* Calculate the frame size */ - vpix = vimc_pix_map_by_code(vsen->mbus_format.code); - frame_size = vsen->mbus_format.width * vpix->bpp * + pix_info = v4l2_format_info(pixelformat); + frame_size = vsen->mbus_format.width * pix_info->bpp[0] * vsen->mbus_format.height; /* @@ -301,6 +280,20 @@ static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { .s_ctrl = vimc_sen_s_ctrl, }; +static void vimc_sen_release(struct v4l2_subdev *sd) +{ + struct vimc_sen_device *vsen = + container_of(sd, struct vimc_sen_device, sd); + + v4l2_ctrl_handler_free(&vsen->hdl); + tpg_free(&vsen->tpg); + kfree(vsen); +} + +static const struct v4l2_subdev_internal_ops vimc_sen_int_ops = { + .release = vimc_sen_release, +}; + static void vimc_sen_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -309,9 +302,6 @@ static void vimc_sen_comp_unbind(struct device *comp, struct device *master, container_of(ved, struct vimc_sen_device, ved); vimc_ent_sd_unregister(ved, &vsen->sd); - v4l2_ctrl_handler_free(&vsen->hdl); - tpg_free(&vsen->tpg); - kfree(vsen); } /* Image Processing Controls */ @@ -371,7 +361,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, pdata->entity_name, MEDIA_ENT_F_CAM_SENSOR, 1, (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, - &vimc_sen_ops); + &vimc_sen_int_ops, &vimc_sen_ops); if (ret) goto err_free_hdl; diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index fcc897fb247b..26b674259489 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -46,19 +46,19 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent) */ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) { - struct media_entity *entity; + struct vimc_ent_device *ved; struct v4l2_subdev *sd; while (stream->pipe_size) { stream->pipe_size--; - entity = stream->ved_pipeline[stream->pipe_size]->ent; - entity = vimc_get_source_entity(entity); + ved = stream->ved_pipeline[stream->pipe_size]; + ved->stream = NULL; stream->ved_pipeline[stream->pipe_size] = NULL; - if (!is_media_entity_v4l2_subdev(entity)) + if (!is_media_entity_v4l2_subdev(ved->ent)) continue; - sd = media_entity_to_v4l2_subdev(entity); + sd = media_entity_to_v4l2_subdev(ved->ent); v4l2_subdev_call(sd, video, s_stream, 0); } } @@ -88,19 +88,27 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, return -EINVAL; } stream->ved_pipeline[stream->pipe_size++] = ved; + ved->stream = stream; + + if (is_media_entity_v4l2_subdev(ved->ent)) { + sd = media_entity_to_v4l2_subdev(ved->ent); + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + pr_err("subdev_call error %s\n", + ved->ent->name); + vimc_streamer_pipeline_terminate(stream); + return ret; + } + } entity = vimc_get_source_entity(ved->ent); /* Check if the end of the pipeline was reached*/ if (!entity) return 0; + /* Get the next device in the pipeline */ if (is_media_entity_v4l2_subdev(entity)) { sd = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) { - vimc_streamer_pipeline_terminate(stream); - return ret; - } ved = v4l2_get_subdevdata(sd); } else { vdev = container_of(entity, @@ -117,10 +125,10 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, static int vimc_streamer_thread(void *data) { struct vimc_stream *stream = data; + u8 *frame = NULL; int i; set_freezable(); - set_current_state(TASK_UNINTERRUPTIBLE); for (;;) { try_to_freeze(); @@ -128,15 +136,13 @@ static int vimc_streamer_thread(void *data) break; for (i = stream->pipe_size - 1; i >= 0; i--) { - stream->frame = stream->ved_pipeline[i]->process_frame( - stream->ved_pipeline[i], - stream->frame); - if (!stream->frame) - break; - if (IS_ERR(stream->frame)) + frame = stream->ved_pipeline[i]->process_frame( + stream->ved_pipeline[i], frame); + if (!frame || IS_ERR(frame)) break; } //wait for 60hz + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 60); } diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h index 752af2e2d5a2..2b3667408794 100644 --- a/drivers/media/platform/vimc/vimc-streamer.h +++ b/drivers/media/platform/vimc/vimc-streamer.h @@ -15,12 +15,32 @@ #define VIMC_STREAMER_PIPELINE_MAX_SIZE 16 +/** + * struct vimc_stream - struct that represents a stream in the pipeline + * + * @pipe: the media pipeline object associated with this stream + * @ved_pipeline: array containing all the entities participating in the + * stream. The order is from a video device (usually a capture device) where + * stream_on was called, to the entity generating the first base image to be + * processed in the pipeline. + * @pipe_size: size of @ved_pipeline + * @kthread: thread that generates the frames of the stream. + * @producer_pixfmt: the pixel format requested from the pipeline. This must + * be set just before calling vimc_streamer_s_stream(ent, 1). This value is + * propagated up to the source of the base image (usually a sensor node) and + * can be modified by entities during s_stream callback to request a different + * format from rest of the pipeline. + * + * When the user call stream_on in a video device, struct vimc_stream is + * used to keep track of all entities and subdevices that generates and + * process frames for the stream. + */ struct vimc_stream { struct media_pipeline pipe; struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE]; unsigned int pipe_size; - u8 *frame; struct task_struct *kthread; + u32 producer_pixfmt; }; /** diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index 154de92dd809..4b51d4d6cf93 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig @@ -11,7 +11,7 @@ config VIDEO_VIVID select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG default n - ---help--- + help Enables a virtual video driver. This driver emulates a webcam, TV, S-Video and HDMI capture hardware, including VBI support for the SDTV inputs. Also video output, VBI output, radio receivers, @@ -28,7 +28,7 @@ config VIDEO_VIVID_CEC bool "Enable CEC emulation support" depends on VIDEO_VIVID select CEC_CORE - ---help--- + help When selected the vivid module will emulate the optional HDMI CEC feature. @@ -36,6 +36,6 @@ config VIDEO_VIVID_MAX_DEVS int "Maximum number of devices" depends on VIDEO_VIVID default "64" - ---help--- + help This allows you to specify the maximum number of devices supported by the vivid driver. diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 342e0e6c103b..7047df6f0e0e 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -681,7 +681,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->v4l2_dev.mdev = &dev->mdev; /* Initialize media device */ - strlcpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); + strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info), "platform:%s-%03d", VIVID_MODULE_NAME, inst); dev->mdev.dev = &pdev->dev; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 52eeda624d7e..530ac8decb25 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1007,7 +1007,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); if (dev->bitmap_cap && (compose->width != s->r.width || compose->height != s->r.height)) { - kfree(dev->bitmap_cap); + vfree(dev->bitmap_cap); dev->bitmap_cap = NULL; } *compose = s->r; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index e61b91b414f9..9350ca65dd91 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -798,7 +798,7 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection s->r.height *= factor; if (dev->bitmap_out && (compose->width != s->r.width || compose->height != s->r.height)) { - kfree(dev->bitmap_out); + vfree(dev->bitmap_out); dev->bitmap_out = NULL; } *compose = s->r; @@ -941,15 +941,19 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, return ret; if (win->bitmap) { - new_bitmap = memdup_user(win->bitmap, bitmap_size); + new_bitmap = vzalloc(bitmap_size); - if (IS_ERR(new_bitmap)) - return PTR_ERR(new_bitmap); + if (!new_bitmap) + return -ENOMEM; + if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { + vfree(new_bitmap); + return -EFAULT; + } } dev->overlay_out_top = win->w.top; dev->overlay_out_left = win->w.left; - kfree(dev->bitmap_out); + vfree(dev->bitmap_out); dev->bitmap_out = new_bitmap; dev->clipcount_out = win->clipcount; if (dev->clipcount_out) diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 54ff539ffea0..f72ac01c21ea 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -42,6 +42,30 @@ static const struct vsp1_format_info vsp1_video_formats[] = { VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_RGBA444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_RGBX444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBX_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_ABGR444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_XBGR444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_BGRA444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_BGRX444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, @@ -50,6 +74,30 @@ static const struct vsp1_format_info vsp1_video_formats[] = { VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_RGBA555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_RGBX555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBX_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_ABGR555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_XBGR555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_BGRA555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_BGRX555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, @@ -68,6 +116,20 @@ static const struct vsp1_format_info vsp1_video_formats[] = { { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 1, { 32, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_BGRA32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, + 1, { 32, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_BGRX32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, + 1, { 32, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_RGBA32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 1, { 32, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_RGBX32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 1, { 32, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index 74ec8aaa5ae0..a2773ad7c185 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -5,7 +5,7 @@ config VIDEO_XILINX depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help Driver for Xilinx Video IP Pipelines if VIDEO_XILINX @@ -14,13 +14,13 @@ config VIDEO_XILINX_TPG tristate "Xilinx Video Test Pattern Generator" depends on VIDEO_XILINX select VIDEO_XILINX_VTC - ---help--- + help Driver for the Xilinx Video Test Pattern Generator config VIDEO_XILINX_VTC tristate "Xilinx Video Timing Controller" depends on VIDEO_XILINX - ---help--- + help Driver for the Xilinx Video Timing Controller endif #VIDEO_XILINX diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 9b99dfb2d0c6..9cd00f64af32 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -7,7 +7,7 @@ menuconfig RADIO_ADAPTERS depends on VIDEO_V4L2 depends on MEDIA_RADIO_SUPPORT default y - ---help--- + help Say Y here to enable selecting AM/FM radio adapters. if RADIO_ADAPTERS && VIDEO_V4L2 @@ -29,7 +29,7 @@ config RADIO_SI476X depends on MFD_SI476X_CORE depends on SND_SOC select SND_SOC_SI476X - ---help--- + help Choose Y here if you have this FM radio chip. In order to control your radio card, you will need to use programs @@ -43,7 +43,7 @@ config RADIO_SI476X config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and you must connect the line out connector to a sound card or a @@ -55,7 +55,7 @@ config USB_MR800 config USB_DSBR tristate "D-Link/GemTek USB FM radio support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and you must connect the line out connector to a sound card or a @@ -68,7 +68,7 @@ config RADIO_MAXIRADIO tristate "Guillemot MAXI Radio FM 2000 radio" depends on VIDEO_V4L2 && PCI select RADIO_TEA575X - ---help--- + help Choose Y here if you have this radio card. This card may also be found as Gemtek PCI FM. @@ -84,7 +84,7 @@ config RADIO_SHARK tristate "Griffin radioSHARK USB radio receiver" depends on USB select RADIO_TEA575X - ---help--- + help Choose Y here if you have this radio receiver. There are 2 versions of this device, this driver is for version 1, @@ -101,7 +101,7 @@ config RADIO_SHARK config RADIO_SHARK2 tristate "Griffin radioSHARK2 USB radio receiver" depends on USB - ---help--- + help Choose Y here if you have this radio receiver. There are 2 versions of this device, this driver is for version 2, @@ -118,7 +118,7 @@ config RADIO_SHARK2 config USB_KEENE tristate "Keene FM Transmitter USB support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of FM transmitter to your computer's USB port. @@ -128,7 +128,7 @@ config USB_KEENE config USB_RAREMONO tristate "Thanko's Raremono AM/FM/SW radio support" depends on USB && VIDEO_V4L2 - ---help--- + help The 'Thanko's Raremono' device contains the Si4734 chip from Silicon Labs Inc. It is one of the very few or perhaps the only consumer USB radio device to receive the AM/FM/SW bands. @@ -142,7 +142,7 @@ config USB_RAREMONO config USB_MA901 tristate "Masterkit MA901 USB FM radio support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and you must connect the line out connector to a sound card or a @@ -154,7 +154,7 @@ config USB_MA901 config RADIO_TEA5764 tristate "TEA5764 I2C FM radio support" depends on I2C && VIDEO_V4L2 - ---help--- + help Say Y here if you want to use the TEA5764 FM chip found in EZX phones. This FM chip is present in EZX phones from Motorola, connected to internal pxa I2C bus. @@ -173,7 +173,7 @@ config RADIO_TEA5764_XTAL config RADIO_SAA7706H tristate "SAA7706H Car Radio DSP" depends on I2C && VIDEO_V4L2 - ---help--- + help Say Y here if you want to use the SAA7706H Car radio Digital Signal Processor, found for instance on the Russellville development board. On the russellville the device is connected to internal @@ -185,7 +185,7 @@ config RADIO_SAA7706H config RADIO_TEF6862 tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" depends on I2C && VIDEO_V4L2 - ---help--- + help Say Y here if you want to use the TEF6862 Car Radio Enhanced Selectivity Tuner, found for instance on the Russellville development board. On the russellville the device is connected to internal @@ -200,7 +200,7 @@ config RADIO_TIMBERDALE depends on I2C # for RADIO_SAA7706H select RADIO_TEF6862 select RADIO_SAA7706H - ---help--- + help This is a kind of umbrella driver for the Radio Tuner and DSP found behind the Timberdale FPGA on the Russellville board. Enabling this driver will automatically select the DSP and tuner. @@ -211,7 +211,7 @@ config RADIO_WL1273 select MFD_CORE select MFD_WL1273_CORE select FW_LOADER - ---help--- + help Choose Y here if you have this FM radio chip. In order to control your radio card, you will need to use programs @@ -233,7 +233,7 @@ menuconfig V4L_RADIO_ISA_DRIVERS bool "ISA radio devices" depends on ISA || COMPILE_TEST default n - ---help--- + help Say Y here to enable support for these ISA drivers. if V4L_RADIO_ISA_DRIVERS @@ -246,7 +246,7 @@ config RADIO_CADET tristate "ADS Cadet AM/FM Tuner" depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 - ---help--- + help Choose Y here if you have one of these AM/FM radio cards, and then fill in the port address below. @@ -258,7 +258,7 @@ config RADIO_RTRACK depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address below. @@ -290,7 +290,7 @@ config RADIO_RTRACK2 depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have this FM radio card, and then fill in the port address below. @@ -314,7 +314,7 @@ config RADIO_AZTECH depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address below. @@ -335,7 +335,7 @@ config RADIO_GEMTEK depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have this FM radio card, and then fill in the I/O port address and settings below. The following cards either have GemTek Radio tuner or are rebranded GemTek Radio cards: @@ -377,7 +377,7 @@ config RADIO_MIROPCM20 depends on ISA_DMA_API && VIDEO_V4L2 && SND select SND_ISA select SND_MIRO - ---help--- + help Choose Y here if you have this FM radio card. You also need to enable the ALSA sound system. This choice automatically selects the ALSA sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this @@ -390,7 +390,7 @@ config RADIO_SF16FMI tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio" depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 - ---help--- + help Choose Y here if you have one of these FM radio cards. To compile this driver as a module, choose M here: the @@ -401,7 +401,7 @@ config RADIO_SF16FMR2 depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_TEA575X - ---help--- + help Choose Y here if you have one of these FM radio cards. To compile this driver as a module, choose M here: the @@ -412,7 +412,7 @@ config RADIO_TERRATEC depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have this FM radio card. Note: this driver hasn't been tested since a long time due to lack @@ -451,7 +451,7 @@ config RADIO_TYPHOON depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address and the frequency used for muting below. @@ -486,7 +486,7 @@ config RADIO_ZOLTRIX depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address below. diff --git a/drivers/media/radio/si470x/Kconfig b/drivers/media/radio/si470x/Kconfig index 6dbb158cd2a0..21026488de90 100644 --- a/drivers/media/radio/si470x/Kconfig +++ b/drivers/media/radio/si470x/Kconfig @@ -1,7 +1,7 @@ config RADIO_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support" depends on VIDEO_V4L2 - ---help--- + help This is a driver for devices with the Silicon Labs SI470x chip (either via USB or I2C buses). @@ -15,7 +15,7 @@ config RADIO_SI470X config USB_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support with USB" depends on USB && RADIO_SI470X - ---help--- + help This is a driver for USB devices with the Silicon Labs SI470x chip. Currently these devices are known to work: - 10c4:818a: Silicon Labs USB FM Radio Reference Design @@ -40,7 +40,7 @@ config USB_SI470X config I2C_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support with I2C" depends on I2C && RADIO_SI470X - ---help--- + help This is a driver for I2C devices with the Silicon Labs SI470x chip. diff --git a/drivers/media/radio/si4713/Kconfig b/drivers/media/radio/si4713/Kconfig index 9c8b887cff75..17567c917554 100644 --- a/drivers/media/radio/si4713/Kconfig +++ b/drivers/media/radio/si4713/Kconfig @@ -2,7 +2,7 @@ config USB_SI4713 tristate "Silicon Labs Si4713 FM Radio Transmitter support with USB" depends on USB && I2C && RADIO_SI4713 select I2C_SI4713 - ---help--- + help This is a driver for USB devices with the Silicon Labs SI4713 chip. Currently these devices are known to work. - 10c4:8244: Silicon Labs FM Transmitter USB device. @@ -17,7 +17,7 @@ config PLATFORM_SI4713 tristate "Silicon Labs Si4713 FM Radio Transmitter support with I2C" depends on I2C && RADIO_SI4713 select I2C_SI4713 - ---help--- + help This is a driver for I2C devices with the Silicon Labs SI4713 chip. @@ -30,7 +30,7 @@ config PLATFORM_SI4713 config I2C_SI4713 tristate "Silicon Labs Si4713 FM Radio Transmitter support" depends on I2C && RADIO_SI4713 - ---help--- + help Say Y here if you want support to Si4713 FM Radio Transmitter. This device can transmit audio through FM. It can transmit RDS and RBDS signals as well. This module is the v4l2 radio diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index f4a53f1e856e..a8584371a32d 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -1272,7 +1272,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) if (vm->index > 0) return -EINVAL; - strncpy(vm->name, "FM Modulator", 32); + strscpy(vm->name, "FM Modulator", sizeof(vm->name)); vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS; diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 3c8987af3772..053d51a5890a 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -489,7 +489,8 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, return -EIO; } /* Send response data to caller */ - if (response != NULL && response_len != NULL && evt_hdr->dlen) { + if (response != NULL && response_len != NULL && evt_hdr->dlen && + evt_hdr->dlen <= payload_len) { /* Skip header info and copy only response data */ skb_pull(skb, sizeof(struct fm_event_msg_hdr)); memcpy(response, skb->data, evt_hdr->dlen); @@ -583,6 +584,8 @@ static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) return; fm_evt_hdr = (void *)skb->data; + if (fm_evt_hdr->dlen > sizeof(fmdev->irq_info.flag)) + return; /* Skip header info and copy only response data */ skb_pull(skb, sizeof(struct fm_event_msg_hdr)); @@ -1268,8 +1271,9 @@ static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) switch (action->type) { case ACTION_SEND_COMMAND: /* Send */ - if (fmc_send_cmd(fmdev, 0, 0, action->data, - action->size, NULL, NULL)) + ret = fmc_send_cmd(fmdev, 0, 0, action->data, + action->size, NULL, NULL); + if (ret) goto rel_fw; cmd_cnt++; @@ -1308,7 +1312,7 @@ static int load_default_rx_configuration(struct fmdev *fmdev) static int fm_power_up(struct fmdev *fmdev, u8 mode) { u16 payload; - __be16 asic_id, asic_ver; + __be16 asic_id = 0, asic_ver = 0; int resp_len, ret; u8 fw_name[50]; @@ -1520,7 +1524,7 @@ int fmc_prepare(struct fmdev *fmdev) } ret = 0; - } else if (ret == -1) { + } else if (ret < 0) { fmerr("st_register failed %d\n", ret); return -EAGAIN; } diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 96ce3e5524e0..3fc6ac15c66d 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -2,7 +2,7 @@ menuconfig RC_CORE tristate "Remote Controller support" depends on INPUT - ---help--- + help Enable support for Remote Controllers on Linux. This is needed in order to support several video capture adapters, standalone IR receivers/transmitters, and RF receivers. @@ -19,7 +19,7 @@ source "drivers/media/rc/keymaps/Kconfig" config LIRC bool "LIRC user interface" depends on RC_CORE - ---help--- + help Enable this option to enable the Linux Infrared Remote Control user interface (e.g. /dev/lirc*). This interface passes raw IR to and from userspace, which is needed for @@ -48,7 +48,7 @@ config IR_NEC_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have IR with NEC protocol, and if the IR is decoded in software @@ -57,7 +57,7 @@ config IR_RC5_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have IR with RC-5 protocol, and if the IR is decoded in software @@ -66,7 +66,7 @@ config IR_RC6_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have an infrared remote control which uses the RC6 protocol, and you need software decoding support. @@ -75,7 +75,7 @@ config IR_JVC_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have an infrared remote control which uses the JVC protocol, and you need software decoding support. @@ -84,7 +84,7 @@ config IR_SONY_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have an infrared remote control which uses the Sony protocol, and you need software decoding support. @@ -92,7 +92,7 @@ config IR_SANYO_DECODER tristate "Enable IR raw decoder for the Sanyo protocol" depends on RC_CORE - ---help--- + help Enable this option if you have an infrared remote control which uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), and you need software decoding support. @@ -101,7 +101,7 @@ config IR_SHARP_DECODER tristate "Enable IR raw decoder for the Sharp protocol" depends on RC_CORE - ---help--- + help Enable this option if you have an infrared remote control which uses the Sharp protocol (Sharp, Denon), and you need software decoding support. @@ -111,7 +111,7 @@ config IR_MCE_KBD_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have a Microsoft Remote Keyboard for Windows Media Center Edition, which you would like to use with a raw IR receiver in your system. @@ -121,14 +121,14 @@ config IR_XMP_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have IR with XMP protocol, and if the IR is decoded in software config IR_IMON_DECODER tristate "Enable IR raw decoder for the iMON protocol" depends on RC_CORE - ---help--- + help Enable this option if you have iMON PAD or Antec Veris infrared remote control and you would like to use it with a raw IR receiver, or if you wish to use an encoder to transmit this IR. @@ -177,7 +177,7 @@ config IR_ENE tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receiver /transceiver made by ENE. @@ -203,7 +203,7 @@ config IR_IMON depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) IR Receiver and/or LCD/VFD/VGA display. @@ -215,7 +215,7 @@ config IR_IMON_RAW depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a SoundGraph iMON IR Receiver, early raw models. @@ -227,7 +227,7 @@ config IR_MCEUSB depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a Windows Media Center Edition eHome Infrared Transceiver. @@ -238,7 +238,7 @@ config IR_ITE_CIR tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receivers /transceivers made by ITE Tech Inc. These are found in several ASUS devices, like the ASUS Digimatrix or the ASUS @@ -251,7 +251,7 @@ config IR_FINTEK tristate "Fintek Consumer Infrared Transceiver" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receiver /transceiver made by Fintek. This chip is found on assorted Jetway motherboards (and of course, possibly others). @@ -263,7 +263,7 @@ config IR_MESON tristate "Amlogic Meson IR remote receiver" depends on RC_CORE depends on ARCH_MESON || COMPILE_TEST - ---help--- + help Say Y if you want to use the IR remote receiver available on Amlogic Meson SoCs. @@ -274,7 +274,7 @@ config IR_MTK tristate "Mediatek IR remote receiver" depends on RC_CORE depends on ARCH_MEDIATEK || COMPILE_TEST - ---help--- + help Say Y if you want to use the IR remote receiver available on Mediatek SoCs. @@ -285,7 +285,7 @@ config IR_NUVOTON tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receiver /transceiver made by Nuvoton (formerly Winbond). This chip is found in the ASRock ION 330HT, as well as assorted Intel @@ -301,7 +301,7 @@ config IR_REDRAT3 select NEW_LEDS select LEDS_CLASS select USB - ---help--- + help Say Y here if you want to use a RedRat3 Infrared Transceiver. To compile this driver as a module, choose M here: the @@ -311,7 +311,7 @@ config IR_SPI tristate "SPI connected IR LED" depends on SPI && LIRC depends on OF || COMPILE_TEST - ---help--- + help Say Y if you want to use an IR LED connected through SPI bus. To compile this driver as a module, choose M here: the module will be @@ -322,7 +322,7 @@ config IR_STREAMZAP depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a Streamzap PC Remote Infrared Receiver. @@ -336,7 +336,7 @@ config IR_WINBOND_CIR select NEW_LEDS select LEDS_CLASS select BITREVERSE - ---help--- + help Say Y here if you want to use the IR remote functionality found in some Winbond SuperI/O chips. Currently only the WPCD376I chip is supported (included in some Intel Media series @@ -350,7 +350,7 @@ config IR_IGORPLUGUSB depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use the IgorPlug-USB IR Receiver by Igor Cesko. This device is included on the Fit-PC2. @@ -365,7 +365,7 @@ config IR_IGUANA depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use the IguanaWorks USB IR Transceiver. Both infrared receive and send are supported. If you want to change the ID or the pin config, use the user space driver from @@ -383,7 +383,7 @@ config IR_TTUSBIR select USB select NEW_LEDS select LEDS_CLASS - ---help--- + help Say Y here if you want to use the TechnoTrend USB IR Receiver. The driver can control the led. @@ -393,7 +393,7 @@ config IR_TTUSBIR config IR_RX51 tristate "Nokia N900 IR transmitter diode" depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE - ---help--- + help Say Y or M here if you want to enable support for the IR transmitter diode built in the Nokia N900 (RX51) device. @@ -405,7 +405,7 @@ source "drivers/media/rc/img-ir/Kconfig" config RC_LOOPBACK tristate "Remote Control Loopback Driver" depends on RC_CORE - ---help--- + help Say Y here if you want support for the remote control loopback driver which allows TX data to be sent back as RX data. This is mostly useful for debugging purposes. @@ -419,7 +419,7 @@ config IR_GPIO_CIR tristate "GPIO IR remote control" depends on RC_CORE depends on (OF && GPIOLIB) || COMPILE_TEST - ---help--- + help Say Y if you want to use GPIO based IR Receiver. To compile this driver as a module, choose M here: the module will @@ -430,7 +430,7 @@ config IR_GPIO_TX depends on RC_CORE depends on LIRC depends on (OF && GPIOLIB) || COMPILE_TEST - ---help--- + help Say Y if you want to a GPIO based IR transmitter. This is a bit banging driver. @@ -443,7 +443,7 @@ config IR_PWM_TX depends on LIRC depends on PWM depends on OF || COMPILE_TEST - ---help--- + help Say Y if you want to use a PWM based IR transmitter. This is more power efficient than the bit banging gpio driver. @@ -454,7 +454,7 @@ config RC_ST tristate "ST remote control receiver" depends on RC_CORE depends on ARCH_STI || COMPILE_TEST - ---help--- + help Say Y here if you want support for ST remote control driver which allows both IR and UHF RX. The driver passes raw pulse and space information to the LIRC decoder. @@ -465,7 +465,7 @@ config IR_SUNXI tristate "SUNXI IR remote control" depends on RC_CORE depends on ARCH_SUNXI || COMPILE_TEST - ---help--- + help Say Y if you want to use sunXi internal IR Controller To compile this driver as a module, choose M here: the module will @@ -474,7 +474,7 @@ config IR_SUNXI config IR_SERIAL tristate "Homebrew Serial Port Receiver" depends on RC_CORE - ---help--- + help Say Y if you want to use Homebrew Serial Port Receivers and Transceivers. @@ -484,13 +484,13 @@ config IR_SERIAL config IR_SERIAL_TRANSMITTER bool "Serial Port Transmitter" depends on IR_SERIAL - ---help--- + help Serial Port Transmitter support config IR_SIR tristate "Built-in SIR IrDA port" depends on RC_CORE - ---help--- + help Say Y if you want to use a IrDA SIR port Transceivers. To compile this driver as a module, choose M here: the module will @@ -500,7 +500,7 @@ config IR_TANGO tristate "Sigma Designs SMP86xx IR decoder" depends on RC_CORE depends on ARCH_TANGO || COMPILE_TEST - ---help--- + help Adds support for the HW IR decoder embedded on Sigma Designs Tango-based systems (SMP86xx, SMP87xx). The HW decoder supports NEC, RC-5, RC-6 IR protocols. @@ -522,7 +522,7 @@ config IR_ZX tristate "ZTE ZX IR remote control" depends on RC_CORE depends on ARCH_ZX || COMPILE_TEST - ---help--- + help Say Y if you want to use the IR remote control available on ZTE ZX family SoCs. diff --git a/drivers/media/rc/ir-rcmm-decoder.c b/drivers/media/rc/ir-rcmm-decoder.c index f1096ac1e5c5..64fb65a9a19f 100644 --- a/drivers/media/rc/ir-rcmm-decoder.c +++ b/drivers/media/rc/ir-rcmm-decoder.c @@ -5,7 +5,6 @@ #include "rc-core-priv.h" #include <linux/module.h> -#include <linux/version.h> #define RCMM_UNIT 166667 /* nanosecs */ #define RCMM_PREFIX_PULSE 416666 /* 166666.666666666*2.5 */ diff --git a/drivers/media/rc/keymaps/Kconfig b/drivers/media/rc/keymaps/Kconfig index 767423bbbdd0..f459096d8e9c 100644 --- a/drivers/media/rc/keymaps/Kconfig +++ b/drivers/media/rc/keymaps/Kconfig @@ -3,7 +3,7 @@ config RC_MAP depends on RC_CORE default y - ---help--- + help This option enables the compilation of lots of Remote Controller tables. They are short tables, but if you don't use a remote controller, or prefer to load the diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c index af387244636b..42815ab57bff 100644 --- a/drivers/media/rc/keymaps/rc-xbox-dvd.c +++ b/drivers/media/rc/keymaps/rc-xbox-dvd.c @@ -42,7 +42,7 @@ static struct rc_map_list xbox_dvd_map = { .map = { .scan = xbox_dvd, .size = ARRAY_SIZE(xbox_dvd), - .rc_proto = RC_PROTO_UNKNOWN, + .rc_proto = RC_PROTO_XBOX_DVD, .name = RC_MAP_XBOX_DVD, } }; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index e8fa28e20192..be5fd129d728 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -76,6 +76,7 @@ static const struct { .scancode_bits = 0x00ffffff, .repeat_period = 114 }, [RC_PROTO_RCMM32] = { .name = "rc-mm-32", .scancode_bits = 0xffffffff, .repeat_period = 114 }, + [RC_PROTO_XBOX_DVD] = { .name = "xbox-dvd", .repeat_period = 64 }, }; /* Used to keep track of known keymaps */ @@ -1027,6 +1028,7 @@ static const struct { { RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32, "rc-mm", "ir-rcmm-decoder" }, + { RC_PROTO_BIT_XBOX_DVD, "xbox-dvd", NULL }, }; /** diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index ffe2c672d105..3998ba29beb6 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -773,8 +773,6 @@ static void serial_ir_exit(void) static int __init serial_ir_init_module(void) { - int result; - switch (type) { case IR_HOMEBREW: case IR_IRDEO: @@ -802,12 +800,7 @@ static int __init serial_ir_init_module(void) if (sense != -1) sense = !!sense; - result = serial_ir_init(); - if (!result) - return 0; - - serial_ir_exit(); - return result; + return serial_ir_init(); } static void __exit serial_ir_exit_module(void) diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c index f959cbb94744..4a3f2cc4ef18 100644 --- a/drivers/media/rc/xbox_remote.c +++ b/drivers/media/rc/xbox_remote.c @@ -107,7 +107,7 @@ static void xbox_remote_input_report(struct urb *urb) return; } - rc_keydown(xbox_remote->rdev, RC_PROTO_UNKNOWN, + rc_keydown(xbox_remote->rdev, RC_PROTO_XBOX_DVD, le16_to_cpup((__le16 *)(data + 2)), 0); } @@ -148,7 +148,7 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote) struct rc_dev *rdev = xbox_remote->rdev; rdev->priv = xbox_remote; - rdev->allowed_protocols = RC_PROTO_BIT_UNKNOWN; + rdev->allowed_protocols = RC_PROTO_BIT_XBOX_DVD; rdev->driver_name = "xbox_remote"; rdev->open = xbox_remote_rc_open; @@ -157,6 +157,8 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote) rdev->device_name = xbox_remote->rc_name; rdev->input_phys = xbox_remote->rc_phys; + rdev->timeout = MS_TO_NS(10); + usb_to_input_id(xbox_remote->udev, &rdev->input_id); rdev->dev.parent = &xbox_remote->interface->dev; } diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index b07ac86fc53c..df169ecf0c27 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -6,7 +6,7 @@ menu "SPI helper chips" config VIDEO_GS1662 tristate "Gennum Serializers video" depends on SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- + help Enable the GS1662 driver which serializes video streams. endmenu diff --git a/drivers/media/usb/airspy/Kconfig b/drivers/media/usb/airspy/Kconfig index 10b204cf4dbc..67578511bb9a 100644 --- a/drivers/media/usb/airspy/Kconfig +++ b/drivers/media/usb/airspy/Kconfig @@ -2,7 +2,7 @@ config USB_AIRSPY tristate "AirSpy" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help This is a video4linux2 driver for AirSpy SDR device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 65fc067eb864..0ad985542c60 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -2,6 +2,8 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_DVB select I2C_ALGOBIT select VIDEO_TVEEPROM select VIDEOBUF2_VMALLOC if VIDEO_V4L2 @@ -9,7 +11,7 @@ config VIDEO_AU0828 select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a hybrid analog/digital tv capture driver for Auvitek's AU0828 USB device. @@ -23,7 +25,7 @@ config VIDEO_AU0828_V4L2 select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TUNER default y - ---help--- + help This is a video4linux driver for Auvitek's USB device. Choose Y here to include support for v4l2 analog video @@ -34,5 +36,5 @@ config VIDEO_AU0828_RC depends on RC_CORE depends on !(RC_CORE=m && VIDEO_AU0828=y) depends on VIDEO_AU0828 - ---help--- + help Enables Remote Controller support on au0828 driver. diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 3f8c92a70116..925a80437822 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -155,9 +155,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev) dev->media_dev->disable_source = NULL; mutex_unlock(&mdev->graph_mutex); - media_device_unregister(dev->media_dev); - media_device_cleanup(dev->media_dev); - kfree(dev->media_dev); + media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE); dev->media_dev = NULL; #endif } @@ -210,14 +208,10 @@ static int au0828_media_device_init(struct au0828_dev *dev, #ifdef CONFIG_MEDIA_CONTROLLER struct media_device *mdev; - mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE); if (!mdev) return -ENOMEM; - /* check if media device is already initialized */ - if (!mdev->dev) - media_device_usb_init(mdev, udev, udev->product); - dev->media_dev = mdev; #endif return 0; @@ -278,6 +272,28 @@ create_link: } } +static bool au0828_is_link_shareable(struct media_entity *owner, + struct media_entity *entity) +{ + bool shareable = false; + + /* Tuner link can be shared by audio, video, and VBI */ + switch (owner->function) { + case MEDIA_ENT_F_IO_V4L: + case MEDIA_ENT_F_AUDIO_CAPTURE: + case MEDIA_ENT_F_IO_VBI: + if (entity->function == MEDIA_ENT_F_IO_V4L || + entity->function == MEDIA_ENT_F_AUDIO_CAPTURE || + entity->function == MEDIA_ENT_F_IO_VBI) + shareable = true; + break; + case MEDIA_ENT_F_DTV_DEMOD: + default: + break; + } + return shareable; +} + /* Callers should hold graph_mutex */ static int au0828_enable_source(struct media_entity *entity, struct media_pipeline *pipe) @@ -320,18 +336,20 @@ static int au0828_enable_source(struct media_entity *entity, /* * Default input is tuner and default input_type * is AU0828_VMUX_TELEVISION. - * FIXME: + * * There is a problem when s_input is called to * change the default input. s_input will try to * enable_source before attempting to change the * input on the device, and will end up enabling * default source which is tuner. * - * Additional logic is necessary in au0828 - * to detect that the input has changed and - * enable the right source. + * Additional logic is necessary in au0828 to detect + * that the input has changed and enable the right + * source. au0828 handles this case in its s_input. + * It will disable the old source and enable the new + * source. + * */ - if (dev->input_type == AU0828_VMUX_TELEVISION) find_source = dev->tuner; else if (dev->input_type == AU0828_VMUX_SVIDEO || @@ -344,27 +362,33 @@ static int au0828_enable_source(struct media_entity *entity, } } - /* Is an active link between sink and source */ + /* Is there an active link between sink and source */ if (dev->active_link) { - /* - * If DVB is using the tuner and calling entity is - * audio/video, the following check will be false, - * since sink is different. Result is Busy. - */ - if (dev->active_link->sink->entity == sink && - dev->active_link->source->entity == find_source) { - /* - * Either ALSA or Video own tuner. sink is - * the same for both. Prevent Video stepping - * on ALSA when ALSA owns the source. + if (dev->active_link_owner == entity) { + /* This check is necessary to handle multiple + * enable_source calls from v4l_ioctls during + * the course of video/vbi application run-time. */ - if (dev->active_link_owner != entity && - dev->active_link_owner->function == - MEDIA_ENT_F_AUDIO_CAPTURE) { - pr_debug("ALSA has the tuner\n"); - ret = -EBUSY; - goto end; - } + pr_debug("%s already owns the tuner\n", entity->name); + ret = 0; + goto end; + } else if (au0828_is_link_shareable(dev->active_link_owner, + entity)) { + /* Either ALSA or Video own tuner. Sink is the same + * for both. Allow sharing the active link between + * their common source (tuner) and sink (decoder). + * Starting pipeline between sharing entity and sink + * will fail with pipe mismatch, while owner has an + * active pipeline. Switch pipeline ownership from + * user to owner when owner disables the source. + */ + dev->active_link_shared = true; + /* save the user info to use from disable */ + dev->active_link_user = entity; + dev->active_link_user_pipe = pipe; + pr_debug("%s owns the tuner %s can share!\n", + dev->active_link_owner->name, + entity->name); ret = 0; goto end; } else { @@ -391,7 +415,7 @@ static int au0828_enable_source(struct media_entity *entity, source = found_link->source->entity; ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED); if (ret) { - pr_err("Activate tuner link %s->%s. Error %d\n", + pr_err("Activate link from %s->%s. Error %d\n", source->name, sink->name, ret); goto end; } @@ -401,25 +425,26 @@ static int au0828_enable_source(struct media_entity *entity, pr_err("Start Pipeline: %s->%s Error %d\n", source->name, entity->name, ret); ret = __media_entity_setup_link(found_link, 0); - pr_err("Deactivate link Error %d\n", ret); + if (ret) + pr_err("Deactivate link Error %d\n", ret); goto end; } - /* - * save active link and active link owner to avoid audio - * deactivating video owned link from disable_source and - * vice versa + + /* save link state to allow audio and video share the link + * and not disable the link while the other is using it. + * active_link_owner is used to deactivate the link. */ dev->active_link = found_link; dev->active_link_owner = entity; dev->active_source = source; dev->active_sink = sink; - pr_debug("Enabled Source: %s->%s->%s Ret %d\n", + pr_info("Enabled Source: %s->%s->%s Ret %d\n", dev->active_source->name, dev->active_sink->name, dev->active_link_owner->name, ret); end: - pr_debug("au0828_enable_source() end %s %d %d\n", - entity->name, entity->function, ret); + pr_debug("%s end: ent:%s fnc:%d ret %d\n", + __func__, entity->name, entity->function, ret); return ret; } @@ -438,21 +463,95 @@ static void au0828_disable_source(struct media_entity *entity) if (!dev->active_link) return; - /* link is active - stop pipeline from source (tuner) */ + /* link is active - stop pipeline from source + * (tuner/s-video/Composite) to the entity + * When DVB/s-video/Composite owns tuner, it won't be in + * shared state. + */ if (dev->active_link->sink->entity == dev->active_sink && dev->active_link->source->entity == dev->active_source) { /* - * prevent video from deactivating link when audio - * has active pipeline + * Prevent video from deactivating link when audio + * has active pipeline and vice versa. In addition + * handle the case when more than one video/vbi + * application is sharing the link. */ + bool owner_is_audio = false; + + if (dev->active_link_owner->function == + MEDIA_ENT_F_AUDIO_CAPTURE) + owner_is_audio = true; + + if (dev->active_link_shared) { + pr_debug("Shared link owner %s user %s %d\n", + dev->active_link_owner->name, + entity->name, dev->users); + + /* Handle video device users > 1 + * When audio owns the shared link with + * more than one video users, avoid + * disabling the source and/or switching + * the owner until the last disable_source + * call from video _close(). Use dev->users to + * determine when to switch/disable. + */ + if (dev->active_link_owner != entity) { + /* video device has users > 1 */ + if (owner_is_audio && dev->users > 1) + return; + + dev->active_link_user = NULL; + dev->active_link_user_pipe = NULL; + dev->active_link_shared = false; + return; + } + + /* video owns the link and has users > 1 */ + if (!owner_is_audio && dev->users > 1) + return; + + /* stop pipeline */ + __media_pipeline_stop(dev->active_link_owner); + pr_debug("Pipeline stop for %s\n", + dev->active_link_owner->name); + + ret = __media_pipeline_start( + dev->active_link_user, + dev->active_link_user_pipe); + if (ret) { + pr_err("Start Pipeline: %s->%s %d\n", + dev->active_source->name, + dev->active_link_user->name, + ret); + goto deactivate_link; + } + /* link user is now the owner */ + dev->active_link_owner = dev->active_link_user; + dev->active_link_user = NULL; + dev->active_link_user_pipe = NULL; + dev->active_link_shared = false; + + pr_debug("Pipeline started for %s\n", + dev->active_link_owner->name); + return; + } else if (!owner_is_audio && dev->users > 1) + /* video/vbi owns the link and has users > 1 */ + return; + if (dev->active_link_owner != entity) return; - __media_pipeline_stop(entity); + + /* stop pipeline */ + __media_pipeline_stop(dev->active_link_owner); + pr_debug("Pipeline stop for %s\n", + dev->active_link_owner->name); + +deactivate_link: ret = __media_entity_setup_link(dev->active_link, 0); if (ret) pr_err("Deactivate link Error %d\n", ret); - pr_debug("Disabled Source: %s->%s->%s Ret %d\n", + pr_info("Disabled Source: %s->%s->%s Ret %d\n", dev->active_source->name, dev->active_sink->name, dev->active_link_owner->name, ret); @@ -460,6 +559,8 @@ static void au0828_disable_source(struct media_entity *entity) dev->active_link_owner = NULL; dev->active_source = NULL; dev->active_sink = NULL; + dev->active_link_shared = false; + dev->active_link_user = NULL; } } #endif @@ -480,6 +581,9 @@ static int au0828_media_device_register(struct au0828_dev *dev, /* register media device */ ret = media_device_register(dev->media_dev); if (ret) { + media_device_delete(dev->media_dev, KBUILD_MODNAME, + THIS_MODULE); + dev->media_dev = NULL; dev_err(&udev->dev, "Media Device Register Error: %d\n", ret); return ret; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 7876c897cc1d..4bde3db83aa2 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -758,6 +758,9 @@ static int au0828_analog_stream_enable(struct au0828_dev *d) dprintk(1, "au0828_analog_stream_enable called\n"); + if (test_bit(DEV_DISCONNECTED, &d->dev_state)) + return -ENODEV; + iface = usb_ifnum_to_if(d->usbdev, 0); if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) { dprintk(1, "Changing intf#0 to alt 5\n"); @@ -839,9 +842,9 @@ int au0828_start_analog_streaming(struct vb2_queue *vq, unsigned int count) return rc; } + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - v4l2_device_call_all(&dev->v4l2_dev, 0, video, - s_stream, 1); dev->vid_timeout_running = 1; mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); } else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) { @@ -861,10 +864,11 @@ static void au0828_stop_streaming(struct vb2_queue *vq) dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users); - if (dev->streaming_users-- == 1) + if (dev->streaming_users-- == 1) { au0828_uninit_isoc(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + } - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); dev->vid_timeout_running = 0; del_timer_sync(&dev->vid_timeout); @@ -893,8 +897,10 @@ void au0828_stop_vbi_streaming(struct vb2_queue *vq) dprintk(1, "au0828_stop_vbi_streaming called %d\n", dev->streaming_users); - if (dev->streaming_users-- == 1) + if (dev->streaming_users-- == 1) { au0828_uninit_isoc(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + } spin_lock_irqsave(&dev->slock, flags); if (dev->isoc_ctl.vbi_buf != NULL) { @@ -1065,7 +1071,7 @@ static int au0828_v4l2_close(struct file *filp) * streaming. * * On most USB devices like au0828 the tuner can - * be safely put in sleep stare here if ALSA isn't + * be safely put in sleep state here if ALSA isn't * streaming. Exceptions are some very old USB tuner * models such as em28xx-based WinTV USB2 which have * a separate audio output jack. The devices that have @@ -1074,7 +1080,7 @@ static int au0828_v4l2_close(struct file *filp) * so the s_power callback are silently ignored. * So, the current logic here does the following: * Disable (put tuner to sleep) when - * - ALSA and DVB aren't not streaming; + * - ALSA and DVB aren't streaming. * - the last V4L2 file handler is closed. * * FIXME: diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 425c35d16057..b47ecc9affd8 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -31,6 +31,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-fh.h> #include <media/media-device.h> +#include <media/media-dev-allocator.h> /* DVB */ #include <media/demux.h> @@ -283,9 +284,12 @@ struct au0828_dev { struct media_entity_notify entity_notify; struct media_entity *tuner; struct media_link *active_link; - struct media_entity *active_link_owner; struct media_entity *active_source; struct media_entity *active_sink; + struct media_entity *active_link_owner; + struct media_entity *active_link_user; + struct media_pipeline *active_link_user_pipe; + bool active_link_shared; #endif }; diff --git a/drivers/media/usb/cpia2/Kconfig b/drivers/media/usb/cpia2/Kconfig index 66e9283f5993..7029a04f3ffd 100644 --- a/drivers/media/usb/cpia2/Kconfig +++ b/drivers/media/usb/cpia2/Kconfig @@ -1,7 +1,7 @@ config VIDEO_CPIA2 tristate "CPiA2 Video For Linux" depends on VIDEO_DEV && USB && VIDEO_V4L2 - ---help--- + help This is the video4linux driver for cameras based on Vision's CPiA2 (Colour Processor Interface ASIC), such as the Digital Blue QX5 Microscope. If you have one of these cameras, say Y here diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 95c0bd4a19dc..45caf78119c4 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -1240,8 +1240,7 @@ static int __init cpia2_init(void) LOG("%s v%s\n", ABOUT, CPIA_VERSION); check_parameters(); - cpia2_usb_init(); - return 0; + return cpia2_usb_init(); } diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 9e5b3e7c3ef5..9262d0d7439a 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -7,7 +7,7 @@ config VIDEO_CX231XX select VIDEO_CX25840 select VIDEO_CX2341X - ---help--- + help This is a video4linux driver for Conexant 231xx USB based TV cards. To compile this driver as a module, choose M here: the @@ -18,7 +18,7 @@ config VIDEO_CX231XX_RC depends on RC_CORE=y || RC_CORE=VIDEO_CX231XX depends on VIDEO_CX231XX default y - ---help--- + help cx231xx hardware has a builtin RX/TX support. However, a few designs opted to not use it, but, instead, some other hardware. This module enables the usage of those other hardware, like the @@ -31,7 +31,7 @@ config VIDEO_CX231XX_ALSA depends on VIDEO_CX231XX && SND select SND_PCM - ---help--- + help This is an ALSA driver for Cx231xx USB based TV cards. To compile this driver as a module, choose M here: the @@ -52,6 +52,6 @@ config VIDEO_CX231XX_DVB select DVB_MN88473 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB cards based on the Conexant cx231xx chips. diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 80d3bd3a0f24..1b7f1af399fb 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -846,6 +846,7 @@ static int af9035_read_config(struct dvb_usb_device *d) state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; + state->it930x_addresses = 0; if (state->chip_type == 0x9135) { /* feed clock for integrated RF tuner */ @@ -872,6 +873,10 @@ static int af9035_read_config(struct dvb_usb_device *d) * IT930x is an USB bridge, only single demod-single tuner * configurations seen so far. */ + if ((le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) && + (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_TD310)) { + state->it930x_addresses = 1; + } return 0; } @@ -1218,6 +1223,48 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); + /* I2C master bus 2 clock speed 300k */ + ret = af9035_wr_reg(d, 0x00f6a7, 0x07); + if (ret < 0) + goto err; + + /* I2C master bus 1,3 clock speed 300k */ + ret = af9035_wr_reg(d, 0x00f103, 0x07); + if (ret < 0) + goto err; + + /* set gpio11 low */ + ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01); + if (ret < 0) + goto err; + + /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */ + ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01); + if (ret < 0) + goto err; + + msleep(200); + + ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01); + if (ret < 0) + goto err; + memset(&si2168_config, 0, sizeof(si2168_config)); si2168_config.i2c_adapter = &adapter; si2168_config.fe = &adap->fe[0]; @@ -1225,8 +1272,9 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) state->af9033_config[adap->id].fe = &adap->fe[0]; state->af9033_config[adap->id].ops = &state->ops; - ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config, - &d->i2c_adap); + ret = af9035_add_i2c_dev(d, "si2168", + it930x_addresses_table[state->it930x_addresses].frontend_i2c_addr, + &si2168_config, &d->i2c_adap); if (ret) goto err; @@ -1575,54 +1623,12 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap) dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); - /* I2C master bus 2 clock speed 300k */ - ret = af9035_wr_reg(d, 0x00f6a7, 0x07); - if (ret < 0) - goto err; - - /* I2C master bus 1,3 clock speed 300k */ - ret = af9035_wr_reg(d, 0x00f103, 0x07); - if (ret < 0) - goto err; - - /* set gpio11 low */ - ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01); - if (ret < 0) - goto err; - - /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */ - ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01); - if (ret < 0) - goto err; - - msleep(200); - - ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01); - if (ret < 0) - goto err; - memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe[0]; - si2157_config.if_port = 1; - ret = af9035_add_i2c_dev(d, "si2157", 0x63, - &si2157_config, state->i2c_adapter_demod); - + si2157_config.if_port = it930x_addresses_table[state->it930x_addresses].tuner_if_port; + ret = af9035_add_i2c_dev(d, "si2157", + it930x_addresses_table[state->it930x_addresses].tuner_i2c_addr, + &si2157_config, state->i2c_adapter_demod); if (ret) goto err; @@ -2128,6 +2134,8 @@ static const struct usb_device_id af9035_id_table[] = { /* IT930x devices */ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303, &it930x_props, "ITE 9303 Generic", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310, + &it930x_props, "AVerMedia TD310 DVB-T2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index a76e6bf0ab1e..bc41c16f9727 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -69,6 +69,7 @@ struct state { u8 dual_mode:1; u8 no_read:1; u8 af9033_i2c_addr[2]; + u8 it930x_addresses; struct af9033_config af9033_config[2]; struct af9033_ops ops; #define AF9035_I2C_CLIENT_MAX 4 @@ -77,6 +78,17 @@ struct state { struct platform_device *platform_device_tuner[2]; }; +struct address_table { + u8 frontend_i2c_addr; + u8 tuner_i2c_addr; + u8 tuner_if_port; +}; + +static const struct address_table it930x_addresses_table[] = { + { 0x67, 0x63, 1 }, + { 0x64, 0x60, 0 }, +}; + static const u32 clock_lut_af9035[] = { 20480000, /* FPGA */ 16384000, /* 16.38 MHz */ diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index e28bd8836751..ae0814dd202a 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -615,16 +615,18 @@ static int dvbsky_init(struct dvb_usb_device *d) return 0; } -static void dvbsky_exit(struct dvb_usb_device *d) +static int dvbsky_frontend_detach(struct dvb_usb_adapter *adap) { + struct dvb_usb_device *d = adap_to_d(adap); struct dvbsky_state *state = d_to_priv(d); - struct dvb_usb_adapter *adap = &d->adapter[0]; + + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); dvb_module_release(state->i2c_client_tuner); dvb_module_release(state->i2c_client_demod); dvb_module_release(state->i2c_client_ci); - adap->fe[0] = NULL; + return 0; } /* DVB USB Driver stuff */ @@ -640,11 +642,11 @@ static struct dvb_usb_device_properties dvbsky_s960_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_s960_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -667,11 +669,11 @@ static struct dvb_usb_device_properties dvbsky_s960c_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_s960c_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -694,11 +696,11 @@ static struct dvb_usb_device_properties dvbsky_t680c_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_t680c_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -721,11 +723,11 @@ static struct dvb_usb_device_properties dvbsky_t330_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_t330_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -748,11 +750,11 @@ static struct dvb_usb_device_properties mygica_t230c_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_mygica_t230c_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .num_adapters = 1, .adapter = { diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index 451e076525d3..639da7e24066 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -13,7 +13,7 @@ config VIDEO_EM28XX_V4L2 select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT - ---help--- + help This is a video4linux driver for Empia 28xx based TV cards. To compile this driver as a module, choose M here: the @@ -23,7 +23,7 @@ config VIDEO_EM28XX_ALSA depends on VIDEO_EM28XX && SND select SND_PCM tristate "Empia EM28xx ALSA audio module" - ---help--- + help This is an ALSA driver for some Empia 28xx based TV cards. This is not required for em2800/em2820/em2821 boards. However, @@ -66,7 +66,7 @@ config VIDEO_EM28XX_DVB select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB cards based on the Empiatech em28xx chips. @@ -76,5 +76,5 @@ config VIDEO_EM28XX_RC depends on VIDEO_EM28XX depends on !(RC_CORE=m && VIDEO_EM28XX=y) default VIDEO_EM28XX - ---help--- + help Enables Remote Controller support on em28xx driver. diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index f84a1208d5d3..d85ea1af6aa1 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -499,7 +499,7 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) * at address 0x18, so if that address is needed for another board in * the future, please put it after 0x1f. */ - const unsigned short addr_list[] = { + static const unsigned short addr_list[] = { 0x1f, 0x30, 0x47, I2C_CLIENT_END }; diff --git a/drivers/media/usb/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig index af1d02430931..beab257c092f 100644 --- a/drivers/media/usb/go7007/Kconfig +++ b/drivers/media/usb/go7007/Kconfig @@ -13,7 +13,7 @@ config VIDEO_GO7007 select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for the WIS GO7007 MPEG encoder chip. @@ -23,7 +23,7 @@ config VIDEO_GO7007 config VIDEO_GO7007_USB tristate "WIS GO7007 USB support" depends on VIDEO_GO7007 && USB - ---help--- + help This is a video4linux driver for the WIS GO7007 MPEG encoder chip over USB. @@ -34,7 +34,7 @@ config VIDEO_GO7007_LOADER tristate "WIS GO7007 Loader support" depends on VIDEO_GO7007 default y - ---help--- + help This is a go7007 firmware loader driver for the WIS GO7007 MPEG encoder chip over USB. @@ -44,7 +44,7 @@ config VIDEO_GO7007_LOADER config VIDEO_GO7007_USB_S2250_BOARD tristate "Sensoray 2250/2251 support" depends on VIDEO_GO7007_USB && USB - ---help--- + help This is a video4linux driver for the Sensoray 2250/2251 device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c index 24f5b615dc7a..dfa9f899d0c2 100644 --- a/drivers/media/usb/go7007/go7007-fw.c +++ b/drivers/media/usb/go7007/go7007-fw.c @@ -1499,8 +1499,8 @@ static int modet_to_package(struct go7007 *go, __le16 *code, int space) return cnt; } -static int do_special(struct go7007 *go, u16 type, __le16 *code, int space, - int *framelen) +static noinline_for_stack int do_special(struct go7007 *go, u16 type, + __le16 *code, int space, int *framelen) { switch (type) { case SPECIAL_FRM_HEAD: diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 19c6a0354ce0..abe98488be23 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1132,7 +1132,7 @@ static int go7007_usb_probe(struct usb_interface *intf, usb->usbdev = usbdev; usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info)); go->board_id = id->driver_info; - strncpy(go->name, name, sizeof(go->name)); + strscpy(go->name, name, sizeof(go->name)); if (board->flags & GO7007_USB_EZUSB) go->hpi_ops = &go7007_usb_ezusb_hpi_ops; else @@ -1198,7 +1198,7 @@ static int go7007_usb_probe(struct usb_interface *intf, go->board_id = GO7007_BOARDID_ENDURA; usb->board = board = &board_endura; go->board_info = &board->main_info; - strncpy(go->name, "Pelco Endura", + strscpy(go->name, "Pelco Endura", sizeof(go->name)); } else { u16 channel; @@ -1232,21 +1232,21 @@ static int go7007_usb_probe(struct usb_interface *intf, case 1: go->tuner_type = TUNER_SONY_BTF_PG472Z; go->std = V4L2_STD_PAL; - strncpy(go->name, "Plextor PX-TV402U-EU", - sizeof(go->name)); + strscpy(go->name, "Plextor PX-TV402U-EU", + sizeof(go->name)); break; case 2: go->tuner_type = TUNER_SONY_BTF_PK467Z; go->std = V4L2_STD_NTSC_M_JP; num_i2c_devs -= 2; - strncpy(go->name, "Plextor PX-TV402U-JP", - sizeof(go->name)); + strscpy(go->name, "Plextor PX-TV402U-JP", + sizeof(go->name)); break; case 3: go->tuner_type = TUNER_SONY_BTF_PB463Z; num_i2c_devs -= 2; - strncpy(go->name, "Plextor PX-TV402U-NA", - sizeof(go->name)); + strscpy(go->name, "Plextor PX-TV402U-NA", + sizeof(go->name)); break; default: pr_debug("unable to detect tuner type!\n"); diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 7a2781fa83e7..bebdfcecf600 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -327,7 +327,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt->flags = V4L2_FMT_FLAG_COMPRESSED; - strncpy(fmt->description, desc, sizeof(fmt->description)); + strscpy(fmt->description, desc, sizeof(fmt->description)); return 0; } diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 088566e88467..0e6f36cb46e6 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -4,7 +4,7 @@ menuconfig USB_GSPCA depends on INPUT || INPUT=n select VIDEOBUF2_VMALLOC default m - ---help--- + help Say Y here if you want to enable selecting webcams based on the GSPCA framework. diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index ac70b36d67b7..4d7517411cc2 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -294,7 +294,7 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ st = urb->iso_frame_desc[i].status; if (st) { - pr_err("ISOC data error: [%d] len=%d, status=%d\n", + gspca_dbg(gspca_dev, D_PACK, "ISOC data error: [%d] len=%d, status=%d\n", i, len, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; @@ -314,6 +314,8 @@ static void fill_frame(struct gspca_dev *gspca_dev, } resubmit: + if (!gspca_dev->streaming) + return; /* resubmit the URB */ st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) @@ -330,7 +332,7 @@ static void isoc_irq(struct urb *urb) struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; gspca_dbg(gspca_dev, D_PACK, "isoc irq\n"); - if (!vb2_start_streaming_called(&gspca_dev->queue)) + if (!gspca_dev->streaming) return; fill_frame(gspca_dev, urb); } @@ -344,7 +346,7 @@ static void bulk_irq(struct urb *urb) int st; gspca_dbg(gspca_dev, D_PACK, "bulk irq\n"); - if (!vb2_start_streaming_called(&gspca_dev->queue)) + if (!gspca_dev->streaming) return; switch (urb->status) { case 0: @@ -367,6 +369,8 @@ static void bulk_irq(struct urb *urb) urb->actual_length); resubmit: + if (!gspca_dev->streaming) + return; /* resubmit the URB */ if (gspca_dev->cam.bulk_nurbs != 0) { st = usb_submit_urb(urb, GFP_ATOMIC); @@ -1638,6 +1642,8 @@ void gspca_disconnect(struct usb_interface *intf) mutex_lock(&gspca_dev->usb_lock); gspca_dev->present = false; + destroy_urbs(gspca_dev); + gspca_input_destroy_urb(gspca_dev); vb2_queue_error(&gspca_dev->queue); diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig index 937e6f5c1e8e..072e186018f5 100644 --- a/drivers/media/usb/hackrf/Kconfig +++ b/drivers/media/usb/hackrf/Kconfig @@ -2,7 +2,7 @@ config USB_HACKRF tristate "HackRF" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help This is a video4linux2 driver for HackRF SDR device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/hdpvr/Kconfig b/drivers/media/usb/hdpvr/Kconfig index d73d9a1952b4..9e78c0c32651 100644 --- a/drivers/media/usb/hdpvr/Kconfig +++ b/drivers/media/usb/hdpvr/Kconfig @@ -2,7 +2,7 @@ config VIDEO_HDPVR tristate "Hauppauge HD PVR support" depends on VIDEO_DEV && VIDEO_V4L2 - ---help--- + help This is a video4linux driver for Hauppauge's HD PVR USB device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e082086428a4..3804aa3fb50f 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -769,8 +769,7 @@ static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) i->type = V4L2_INPUT_TYPE_CAMERA; - strncpy(i->name, iname[n], sizeof(i->name) - 1); - i->name[sizeof(i->name) - 1] = '\0'; + strscpy(i->name, iname[n], sizeof(i->name)); i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF; @@ -841,8 +840,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, audio->capability = V4L2_AUDCAP_STEREO; - strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1); - audio->name[sizeof(audio->name) - 1] = '\0'; + strscpy(audio->name, audio_iname[n], sizeof(audio->name)); return 0; } @@ -874,7 +872,6 @@ static int vidioc_g_audio(struct file *file, void *private_data, audio->index = dev->options.audio_input; audio->capability = V4L2_AUDCAP_STEREO; strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); - audio->name[sizeof(audio->name) - 1] = '\0'; return 0; } @@ -991,7 +988,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return -EINVAL; f->flags = V4L2_FMT_FLAG_COMPRESSED; - strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32); + strscpy(f->description, "MPEG2-TS with AVC/AAC streams", + sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/usb/pulse8-cec/Kconfig b/drivers/media/usb/pulse8-cec/Kconfig index 18ead44824ba..11f1b75d3efd 100644 --- a/drivers/media/usb/pulse8-cec/Kconfig +++ b/drivers/media/usb/pulse8-cec/Kconfig @@ -4,7 +4,7 @@ config USB_PULSE8_CEC select CEC_CORE select SERIO select SERIO_SERPORT - ---help--- + help This is a cec driver for the Pulse Eight HDMI CEC device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c index b085b14f3f87..ea9ee74fa336 100644 --- a/drivers/media/usb/pulse8-cec/pulse8-cec.c +++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c @@ -435,7 +435,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 0); if (err) return err; - strncpy(log_addrs->osd_name, data, 13); + strscpy(log_addrs->osd_name, data, sizeof(log_addrs->osd_name)); dev_dbg(pulse8->dev, "OSD name: %s\n", log_addrs->osd_name); return 0; @@ -566,7 +566,7 @@ static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) char *osd_str = cmd + 1; cmd[0] = MSGCODE_SET_OSD_NAME; - strncpy(cmd + 1, adap->log_addrs.osd_name, 13); + strscpy(cmd + 1, adap->log_addrs.osd_name, sizeof(cmd) - 1); if (osd_len < 4) { memset(osd_str + osd_len, ' ', 4 - osd_len); osd_len = 4; diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 1ad913fc30bf..ac6612cf1bec 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -9,7 +9,7 @@ config VIDEO_PVRUSB2 select VIDEO_MSP3400 select VIDEO_WM8775 select VIDEO_CS53L32A - ---help--- + help This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -20,7 +20,7 @@ config VIDEO_PVRUSB2_SYSFS bool "pvrusb2 sysfs support" default y depends on VIDEO_PVRUSB2 && SYSFS - ---help--- + help This option enables the operation of a sysfs based interface for query and control of the pvrusb2 driver. @@ -43,7 +43,7 @@ config VIDEO_PVRUSB2_DVB select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This option enables a DVB interface for the pvrusb2 driver. If your device does not support digital television, this feature will have no affect on the driver's operation. @@ -53,7 +53,7 @@ config VIDEO_PVRUSB2_DVB config VIDEO_PVRUSB2_DEBUGIFC bool "pvrusb2 debug interface" depends on VIDEO_PVRUSB2_SYSFS - ---help--- + help This option enables the inclusion of a debug interface in the pvrusb2 driver, hosted through sysfs. diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 446a999dd2ce..816c85786c2a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -666,6 +666,8 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) { + if (v < 0 || v > PVR2_CVAL_INPUT_MAX) + return 0; return ((1 << v) & cptr->hdw->input_allowed_mask) != 0; } @@ -2459,9 +2461,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { ciptr->set_value = ctrl_cx2341x_set; } - strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name, - PVR2_CTLD_INFO_DESC_SIZE); - hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0; + strscpy(hdw->mpeg_ctrl_info[idx].desc, qctrl.name, + sizeof(hdw->mpeg_ctrl_info[idx].desc)); ciptr->default_value = qctrl.default_value; switch (qctrl.type) { default: diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index 25648add77e5..bd2b7a67b732 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -50,6 +50,7 @@ #define PVR2_CVAL_INPUT_COMPOSITE 2 #define PVR2_CVAL_INPUT_SVIDEO 3 #define PVR2_CVAL_INPUT_RADIO 4 +#define PVR2_CVAL_INPUT_MAX PVR2_CVAL_INPUT_RADIO enum pvr2_config { pvr2_config_empty, /* No configuration */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 08d5b7aa3537..cb6668580d77 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -284,7 +284,7 @@ static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin) if (vin->index > 0) return -EINVAL; - strncpy(vin->name, "PVRUSB2 Audio", 14); + strscpy(vin->name, "PVRUSB2 Audio", sizeof(vin->name)); vin->capability = V4L2_AUDCAP_STEREO; return 0; } @@ -293,7 +293,7 @@ static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin) { /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */ vin->index = 0; - strncpy(vin->name, "PVRUSB2 Audio", 14); + strscpy(vin->name, "PVRUSB2 Audio", sizeof(vin->name)); vin->capability = V4L2_AUDCAP_STEREO; return 0; } diff --git a/drivers/media/usb/pwc/Kconfig b/drivers/media/usb/pwc/Kconfig index d63d0a850035..5f6d91edca41 100644 --- a/drivers/media/usb/pwc/Kconfig +++ b/drivers/media/usb/pwc/Kconfig @@ -2,7 +2,7 @@ config USB_PWC tristate "USB Philips Cameras" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help Say Y or M here if you want to use one of these Philips & OEM webcams: * Philips PCA645, PCA646 @@ -41,7 +41,7 @@ config USB_PWC_INPUT_EVDEV bool "USB Philips Cameras input events device support" default y depends on USB_PWC && (USB_PWC=INPUT || INPUT=y) - ---help--- + help This option makes USB Philips cameras register the snapshot button as an input device to report button events. diff --git a/drivers/media/usb/pwc/pwc-ctrl.c b/drivers/media/usb/pwc/pwc-ctrl.c index 655cef39eb3d..b681a184ef87 100644 --- a/drivers/media/usb/pwc/pwc-ctrl.c +++ b/drivers/media/usb/pwc/pwc-ctrl.c @@ -242,14 +242,14 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression */ - pChoose = NULL; - while (*compression <= 3) { + do { pChoose = &Timon_table[size][fps][*compression]; if (pChoose->alternate != 0) break; (*compression)++; - } - if (pChoose == NULL || pChoose->alternate == 0) + } while (*compression <= 3); + + if (pChoose->alternate == 0) return -ENOENT; /* Not supported. */ if (send_to_cam) @@ -279,7 +279,7 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, int frames, int *compression, int send_to_cam) { - const struct Kiara_table_entry *pChoose = NULL; + const struct Kiara_table_entry *pChoose; int fps, ret = 0; if (size >= PSZ_MAX || *compression < 0 || *compression > 3) @@ -293,13 +293,14 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression */ - while (*compression <= 3) { + do { pChoose = &Kiara_table[size][fps][*compression]; if (pChoose->alternate != 0) break; (*compression)++; - } - if (pChoose == NULL || pChoose->alternate == 0) + } while (*compression <= 3); + + if (pChoose->alternate == 0) return -ENOENT; /* Not supported. */ /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ diff --git a/drivers/media/usb/rainshadow-cec/Kconfig b/drivers/media/usb/rainshadow-cec/Kconfig index 030ef01b1ff0..6b00be618db8 100644 --- a/drivers/media/usb/rainshadow-cec/Kconfig +++ b/drivers/media/usb/rainshadow-cec/Kconfig @@ -4,7 +4,7 @@ config USB_RAINSHADOW_CEC select CEC_CORE select SERIO select SERIO_SERPORT - ---help--- + help This is a cec driver for the RainShadow Tech HDMI CEC device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig index d37b742d4f7a..cc5e5aa3c93a 100644 --- a/drivers/media/usb/siano/Kconfig +++ b/drivers/media/usb/siano/Kconfig @@ -8,6 +8,6 @@ config SMS_USB_DRV depends on !RC_CORE || RC_CORE select MEDIA_COMMON_OPTIONS select SMS_SIANO_MDTV - ---help--- + help Choose if you would like to have Siano's support for USB interface diff --git a/drivers/media/usb/stk1160/Kconfig b/drivers/media/usb/stk1160/Kconfig index 425ed00e2599..03426e4437ea 100644 --- a/drivers/media/usb/stk1160/Kconfig +++ b/drivers/media/usb/stk1160/Kconfig @@ -2,7 +2,7 @@ config VIDEO_STK1160_COMMON tristate "STK1160 USB video capture support" depends on VIDEO_DEV && I2C - ---help--- + help This is a video4linux driver for STK1160 based video capture devices. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/stkwebcam/Kconfig b/drivers/media/usb/stkwebcam/Kconfig index a6a00aa4fce6..ea9e04b3caaf 100644 --- a/drivers/media/usb/stkwebcam/Kconfig +++ b/drivers/media/usb/stkwebcam/Kconfig @@ -1,7 +1,7 @@ config USB_STKWEBCAM tristate "USB Syntek DC1125 Camera support" depends on VIDEO_V4L2 - ---help--- + help Say Y here if you want to use this type of camera. Supported devices are typically found in some Asus laptops, with USB id 174f:a311 and 05e1:0501. Other Syntek cameras diff --git a/drivers/media/usb/tm6000/Kconfig b/drivers/media/usb/tm6000/Kconfig index a43b77abd931..321ae691f4d9 100644 --- a/drivers/media/usb/tm6000/Kconfig +++ b/drivers/media/usb/tm6000/Kconfig @@ -18,7 +18,7 @@ config VIDEO_TM6000_ALSA tristate "TV Master TM5600/6000/6010 audio support" depends on VIDEO_TM6000 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio for TM5600/TM6000/TM6010 USB Devices. @@ -29,5 +29,5 @@ config VIDEO_TM6000_DVB tristate "DVB Support for tm6000 based TV cards" depends on VIDEO_TM6000 && DVB_CORE && USB select DVB_ZL10353 - ---help--- + help This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig index 14a0941fa0d0..2b4ac0848469 100644 --- a/drivers/media/usb/usbtv/Kconfig +++ b/drivers/media/usb/usbtv/Kconfig @@ -4,7 +4,7 @@ config VIDEO_USBTV select SND_PCM select VIDEOBUF2_VMALLOC - ---help--- + help This is a video4linux2 driver for USBTV007 based video capture devices. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/usbvision/Kconfig b/drivers/media/usb/usbvision/Kconfig index 6b6afc5d8f7e..7aa080cb9884 100644 --- a/drivers/media/usb/usbvision/Kconfig +++ b/drivers/media/usb/usbvision/Kconfig @@ -3,7 +3,7 @@ config VIDEO_USBVISION depends on I2C && VIDEO_V4L2 select VIDEO_TUNER select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help There are more than 50 different USB video devices based on NT1003/1004/1005 USB Bridges. This driver enables using those devices. diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 92d166bf8c12..abc4eed832a3 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -2302,6 +2302,9 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!usbvision->sbuf[buf_idx].data) + return -ENOMEM; + urb->dev = dev; urb->context = usbvision; urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp); diff --git a/drivers/media/usb/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig index 6ed85efabcaa..94937d0cc2e3 100644 --- a/drivers/media/usb/uvc/Kconfig +++ b/drivers/media/usb/uvc/Kconfig @@ -2,7 +2,7 @@ config USB_VIDEO_CLASS tristate "USB Video Class (UVC)" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help Support for the USB Video Class (UVC). Currently only video input devices, such as webcams, are supported. @@ -13,7 +13,7 @@ config USB_VIDEO_CLASS_INPUT_EVDEV default y depends on USB_VIDEO_CLASS depends on USB_VIDEO_CLASS=INPUT || INPUT=y - ---help--- + help This option makes USB Video Class devices register an input device to report button events. diff --git a/drivers/media/usb/zr364xx/Kconfig b/drivers/media/usb/zr364xx/Kconfig index ac429bca70e8..979b1d4f3f68 100644 --- a/drivers/media/usb/zr364xx/Kconfig +++ b/drivers/media/usb/zr364xx/Kconfig @@ -3,7 +3,7 @@ config USB_ZR364XX depends on VIDEO_V4L2 select VIDEOBUF_GEN select VIDEOBUF_VMALLOC - ---help--- + help Say Y here if you want to connect this type of camera to your computer's USB port. See <file:Documentation/media/v4l-drivers/zr364xx.rst> for more info diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index c0940f5c69b4..8402096f7796 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -13,7 +13,7 @@ config VIDEO_V4L2 config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality on V4L2 drivers" default n - ---help--- + help Say Y here to enable advanced debugging functionality on some V4L devices. In doubt, say N. @@ -21,7 +21,7 @@ config VIDEO_ADV_DEBUG config VIDEO_FIXED_MINOR_RANGES bool "Enable old-style fixed minor ranges on drivers/video devices" default n - ---help--- + help Say Y here to enable the old-style fixed-range minor assignments. Only useful if you rely on the old behavior and use mknod instead of udev. @@ -33,7 +33,7 @@ config VIDEO_PCI_SKELETON depends on SAMPLES depends on VIDEO_V4L2 && VIDEOBUF2_CORE depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG - ---help--- + help Enable build of the skeleton PCI driver, used as a reference when developing new drivers. @@ -51,7 +51,7 @@ config V4L2_FLASH_LED_CLASS tristate "V4L2 flash API for LED flash class devices" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on LEDS_CLASS_FLASH - ---help--- + help Say Y here to enable V4L2 flash API support for LED flash class drivers. diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 663730f088cd..b5778b2ffa27 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -445,3 +445,189 @@ int v4l2_s_parm_cap(struct video_device *vdev, return ret; } EXPORT_SYMBOL_GPL(v4l2_s_parm_cap); + +const struct v4l2_format_info *v4l2_format_info(u32 format) +{ + static const struct v4l2_format_info formats[] = { + /* RGB formats */ + { .format = V4L2_PIX_FMT_BGR24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_HSV24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_XBGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_XRGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_HSV32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ARGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ABGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_GREY, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + + /* YUV packed formats */ + { .format = V4L2_PIX_FMT_YUYV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVYU, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_UYVY, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_VYUY, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + + /* YUV planar formats */ + { .format = V4L2_PIX_FMT_NV12, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV21, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV16, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV61, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV24, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV42, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + + { .format = V4L2_PIX_FMT_YUV410, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YVU410, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YUV411P, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV420, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YVU420, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YUV422P, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + + /* YUV planar formats, non contiguous variant */ + { .format = V4L2_PIX_FMT_YUV420M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YVU420M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YUV422M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVU422M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV444M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVU444M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, + + { .format = V4L2_PIX_FMT_NV12M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV21M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV16M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV61M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + + /* Bayer RGB formats */ + { .format = V4L2_PIX_FMT_SBGGR8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) + if (formats[i].format == format) + return &formats[i]; + return NULL; +} +EXPORT_SYMBOL(v4l2_format_info); + +static inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane) +{ + if (!info->block_w[plane]) + return 1; + return info->block_w[plane]; +} + +static inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane) +{ + if (!info->block_h[plane]) + return 1; + return info->block_h[plane]; +} + +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + int pixelformat, int width, int height) +{ + const struct v4l2_format_info *info; + struct v4l2_plane_pix_format *plane; + int i; + + info = v4l2_format_info(pixelformat); + if (!info) + return -EINVAL; + + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + pixfmt->num_planes = info->mem_planes; + + if (info->mem_planes == 1) { + plane = &pixfmt->plane_fmt[0]; + plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; + plane->sizeimage = 0; + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); + aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); + + plane->sizeimage += info->bpp[i] * + DIV_ROUND_UP(aligned_width, hdiv) * + DIV_ROUND_UP(aligned_height, vdiv); + } + } else { + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); + aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); + + plane = &pixfmt->plane_fmt[i]; + plane->bytesperline = + info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv); + plane->sizeimage = + plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv); + } + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); + +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, int width, int height) +{ + const struct v4l2_format_info *info; + int i; + + info = v4l2_format_info(pixelformat); + if (!info) + return -EINVAL; + + /* Single planar API cannot be used for multi plane formats. */ + if (info->mem_planes > 1) + return -EINVAL; + + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; + pixfmt->sizeimage = 0; + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); + aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); + + pixfmt->sizeimage += info->bpp[i] * + DIV_ROUND_UP(aligned_width, hdiv) * + DIV_ROUND_UP(aligned_height, vdiv); + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index b79d3bbd8350..89a1fe564675 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -828,6 +828,10 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: return "H264 Constrained Intra Pred"; case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: return "H264 I-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -849,6 +853,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices"; + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: return "FWHT Stateless Parameters"; + case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; + case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; /* VPX controls */ case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions"; @@ -1303,6 +1310,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: *type = V4L2_CTRL_TYPE_MPEG2_QUANTIZATION; break; + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + *type = V4L2_CTRL_TYPE_FWHT_PARAMS; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1599,7 +1609,7 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_INTEGER_MENU: if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum) return -ERANGE; - if (ctrl->menu_skip_mask & (1 << ptr.p_s32[idx])) + if (ctrl->menu_skip_mask & (1ULL << ptr.p_s32[idx])) return -EINVAL; if (ctrl->type == V4L2_CTRL_TYPE_MENU && ctrl->qmenu[ptr.p_s32[idx]][0] == '\0') @@ -1669,6 +1679,9 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: return 0; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + return 0; + default: return -EINVAL; } @@ -2249,6 +2262,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization); break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_fwht_params); + break; default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); @@ -2918,7 +2934,7 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) return -EINVAL; /* Use mask to see if this menu item should be skipped */ - if (ctrl->menu_skip_mask & (1 << i)) + if (ctrl->menu_skip_mask & (1ULL << i)) return -EINVAL; /* Empty menu items should also be skipped */ if (ctrl->type == V4L2_CTRL_TYPE_MENU) { @@ -3899,18 +3915,19 @@ void v4l2_ctrl_request_complete(struct media_request *req, } EXPORT_SYMBOL(v4l2_ctrl_request_complete); -void v4l2_ctrl_request_setup(struct media_request *req, +int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_handler *main_hdl) { struct media_request_object *obj; struct v4l2_ctrl_handler *hdl; struct v4l2_ctrl_ref *ref; + int ret = 0; if (!req || !main_hdl) - return; + return 0; if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) - return; + return -EBUSY; /* * Note that it is valid if nothing was found. It means @@ -3919,10 +3936,10 @@ void v4l2_ctrl_request_setup(struct media_request *req, */ obj = media_request_object_find(req, &req_ops, main_hdl); if (!obj) - return; + return 0; if (obj->completed) { media_request_object_put(obj); - return; + return -EBUSY; } hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); @@ -3990,12 +4007,15 @@ void v4l2_ctrl_request_setup(struct media_request *req, update_from_auto_cluster(master); } - try_or_set_cluster(NULL, master, true, 0); - + ret = try_or_set_cluster(NULL, master, true, 0); v4l2_ctrl_unlock(master); + + if (ret) + break; } media_request_object_put(obj); + return ret; } EXPORT_SYMBOL(v4l2_ctrl_request_setup); diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index e0ddb9a52bd1..7cca0de1b730 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -216,10 +216,18 @@ error_module: } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); +static void v4l2_subdev_release(struct v4l2_subdev *sd) +{ + struct module *owner = !sd->owner_v4l2_dev ? sd->owner : NULL; + + if (sd->internal_ops && sd->internal_ops->release) + sd->internal_ops->release(sd); + module_put(owner); +} + static void v4l2_device_release_subdev_node(struct video_device *vdev) { - struct v4l2_subdev *sd = video_get_drvdata(vdev); - sd->devnode = NULL; + v4l2_subdev_release(video_get_drvdata(vdev)); kfree(vdev); } @@ -318,8 +326,9 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) media_device_unregister_entity(&sd->entity); } #endif - video_unregister_device(sd->devnode); - if (!sd->owner_v4l2_dev) - module_put(sd->owner); + if (sd->devnode) + video_unregister_device(sd->devnode); + else + v4l2_subdev_release(sd); } EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 20571846e636..ea1ed88f9dc8 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -163,7 +163,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, } if (use_default_lane_mapping) - pr_debug("using default lane mapping\n"); + pr_debug("no lane mapping given, using defaults\n"); } rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); @@ -175,6 +175,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, num_data_lanes); have_data_lanes = true; + if (use_default_lane_mapping) { + pr_debug("data-lanes property exists; disabling default mapping\n"); + use_default_lane_mapping = false; + } } for (i = 0; i < num_data_lanes; i++) { @@ -225,6 +229,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, if (bus_type == V4L2_MBUS_CSI2_DPHY || bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used || have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) { + /* Only D-PHY has a clock lane. */ + unsigned int dfl_data_lane_index = + bus_type == V4L2_MBUS_CSI2_DPHY; + bus->flags = flags; if (bus_type == V4L2_MBUS_UNKNOWN) vep->bus_type = V4L2_MBUS_CSI2_DPHY; @@ -233,7 +241,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, if (use_default_lane_mapping) { bus->clock_lane = 0; for (i = 0; i < num_data_lanes; i++) - bus->data_lanes[i] = 1 + i; + bus->data_lanes[i] = dfl_data_lane_index + i; } else { bus->clock_lane = clock_lane; for (i = 0; i < num_data_lanes; i++) @@ -820,7 +828,10 @@ error: * underneath the fwnode identified by the previous tuple, etc. until you * reached the fwnode you need. * - * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt: + * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A + * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under + * Documentation/acpi/dsd instead and especially graph.txt, + * data-node-references.txt and leds.txt . * * Scope (\_SB.PCI0.I2C2) * { diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f6d663934648..ac87c3e37280 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1337,6 +1337,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VP9: descr = "VP9"; break; case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ + case V4L2_PIX_FMT_FWHT_STATELESS: descr = "FWHT Stateless"; break; /* used in vicodec */ case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; @@ -1373,7 +1374,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) } if (descr) - WARN_ON(strscpy(fmt->description, descr, sz) >= sz); + WARN_ON(strscpy(fmt->description, descr, sz) < 0); fmt->flags = flags; } diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f5f0d71ec745..d75815ab0d7b 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -18,6 +18,7 @@ #include <linux/ioctl.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/videodev2.h> @@ -54,9 +55,6 @@ static int subdev_open(struct file *file) struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_subdev_fh *subdev_fh; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = NULL; -#endif int ret; subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); @@ -73,12 +71,15 @@ static int subdev_open(struct file *file) v4l2_fh_add(&subdev_fh->vfh); file->private_data = &subdev_fh->vfh; #if defined(CONFIG_MEDIA_CONTROLLER) - if (sd->v4l2_dev->mdev) { - entity = media_entity_get(&sd->entity); - if (!entity) { + if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) { + struct module *owner; + + owner = sd->entity.graph_obj.mdev->dev->driver->owner; + if (!try_module_get(owner)) { ret = -EBUSY; goto err; } + subdev_fh->owner = owner; } #endif @@ -91,9 +92,7 @@ static int subdev_open(struct file *file) return 0; err: -#if defined(CONFIG_MEDIA_CONTROLLER) - media_entity_put(entity); -#endif + module_put(subdev_fh->owner); v4l2_fh_del(&subdev_fh->vfh); v4l2_fh_exit(&subdev_fh->vfh); subdev_fh_free(subdev_fh); @@ -111,10 +110,7 @@ static int subdev_close(struct file *file) if (sd->internal_ops && sd->internal_ops->close) sd->internal_ops->close(sd, subdev_fh); -#if defined(CONFIG_MEDIA_CONTROLLER) - if (sd->v4l2_dev->mdev) - media_entity_put(&sd->entity); -#endif + module_put(subdev_fh->owner); v4l2_fh_del(vfh); v4l2_fh_exit(vfh); subdev_fh_free(subdev_fh); |