linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/15] Add a plugin for Exynos4 camera
@ 2016-01-18 16:17 Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 01/15] mediactl: Introduce v4l2_subdev structure Jacek Anaszewski
                   ` (14 more replies)
  0 siblings, 15 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

This is a sixth version of the patch series adding a plugin for the 
Exynos4 camera.

The plugin doesn't link against libmediactl, but has its sources
compiled in. Currently utils are built after the plugins, but
libv4l-exynos4-camera plugin depends on the utils. In order to link
the plugin against libmediactl the build system would have to be
modified.

================
Changes from v5:
================

- fixed and tested use cases with S5K6A3 sensor and FIMC-IS-ISP
- added conversion "colorspace id to string"

================
Changes from v4:
================

- removed some redundant functions for traversing media device graph
  and switched over to using existing ones
- avoided accessing struct v4l2_subdev from libmediactl
- applied various improvements

================
Changes from v3:
================

- added struct v4l2_subdev and put entity fd and 
  information about supported controls to it
- improved functions for negotiating and setting
  pipeline format by using available libv4lsubdev API
- applied minor improvements and cleanups

================
Changes from v2:
================

- switched to using mediatext library for parsing
  the media device configuration
- extended libmediactl
- switched to using libmediactl

================
Changes from v1:
================

- removed redundant mbus code negotiation
- split the parser, media device helpers and ioctl wrappers
  to the separate modules
- added mechanism for querying extended controls
- applied various fixes and modifications



The plugin was tested on v4.4 with patches fixing several
issues for Exynos4 camera
(patch set titled "Exynos4-is fixes for libv4l exynos4 camera plugin").

The plugin expects a configuration file:
/var/lib/libv4l/exynos4_capture_conf

Exemplary configuration file for pipeline with sensor
S5C73M3 (rear camera):

==========================================

link-conf "s5p-mipi-csis.0":1 -> "FIMC.0":0 [1]
ctrl-to-subdev-conf 0x0098091f -> "fimc.0.capture"
ctrl-to-subdev-conf 0x00980902 -> "S5C73M3"
ctrl-to-subdev-conf 0x00980922 -> "fimc.0.capture"
ctrl-to-subdev-conf 0x009a0914 -> "S5C73M3"

==========================================

With this settings the plugin can be tested on the exynos4412-trats2 board
using following gstreamer pipeline:

gst-launch-1.0 v4l2src device=/dev/video1 extra-controls="c,rotate=90,color_effects=2" ! video/x-raw,width=960,height=720 ! fbdevsink

Exemplary configuration file for pipeline with sensor
S5K6A3 (front camera):

==========================================

link-conf "s5p-mipi-csis.1":1 -> "FIMC-LITE.1":0 [1]
link-conf "FIMC-LITE.1":2 -> "FIMC-IS-ISP":0 [1]
link-conf "FIMC-IS-ISP":1 -> "FIMC.0":1 [1]

==========================================

gst-launch-1.0 v4l2src device=/dev/video1 extra-controls="c,rotate=270,color_effects=2,horizontal_flip=1" ! video/x-raw,width=960,height=920 ! fbdevsink


Thanks,
Jacek Anaszewski

Jacek Anaszewski (14):
  mediactl: Introduce v4l2_subdev structure
  mediactl: Add support for v4l2-ctrl-redir config
  mediatext: Add library
  mediactl: Add media device graph helpers
  mediactl: Add media_device creation helpers
  mediactl: libv4l2subdev: add VYUY8_2X8 mbus code
  mediactl: Add support for media device pipelines
  mediactl: libv4l2subdev: Add colorspace logging
  mediactl: libv4l2subdev: add support for comparing mbus formats
  mediactl: libv4l2subdev: add support for setting pipeline format
  mediactl: libv4l2subdev: add get_pipeline_entity_by_cid function
  mediactl: Add media device ioctl API
  mediactl: libv4l2subdev: Enable opening/closing pipelines
  Add a libv4l plugin for Exynos4 camera

Sakari Ailus (1):
  mediactl: Separate entity and pad parsing

 configure.ac                                      |    1 +
 lib/Makefile.am                                   |    5 +
 lib/libv4l-exynos4-camera/Makefile.am             |    7 +
 lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c |  620 +++++++++++++++++++++
 utils/media-ctl/Makefile.am                       |   12 +-
 utils/media-ctl/libmediactl.c                     |  272 ++++++++-
 utils/media-ctl/libmediatext.pc.in                |   10 +
 utils/media-ctl/libv4l2media_ioctl.c              |  404 ++++++++++++++
 utils/media-ctl/libv4l2media_ioctl.h              |   48 ++
 utils/media-ctl/libv4l2subdev.c                   |  340 ++++++++++-
 utils/media-ctl/mediactl-priv.h                   |   11 +-
 utils/media-ctl/mediactl.h                        |  151 +++++
 utils/media-ctl/mediatext-test.c                  |   64 +++
 utils/media-ctl/mediatext.c                       |  311 +++++++++++
 utils/media-ctl/mediatext.h                       |   52 ++
 utils/media-ctl/v4l2subdev.h                      |  148 +++++
 16 files changed, 2426 insertions(+), 30 deletions(-)
 create mode 100644 lib/libv4l-exynos4-camera/Makefile.am
 create mode 100644 lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
 create mode 100644 utils/media-ctl/libmediatext.pc.in
 create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
 create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
 create mode 100644 utils/media-ctl/mediatext-test.c
 create mode 100644 utils/media-ctl/mediatext.c
 create mode 100644 utils/media-ctl/mediatext.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 01/15] mediactl: Introduce v4l2_subdev structure
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-12 12:42   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config Jacek Anaszewski
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add struct v4l2_subdev - a representation of the v4l2 sub-device,
related to the media entity. Add field 'sd', the pointer to
the newly introduced structure, to the struct media_entity
and move 'fd' property from struct media entity to struct v4l2_subdev.
Avoid accessing sub-device file descriptor from libmediactl and
make the v4l2_subdev_open capable of creating the v4l2_subdev
if the 'sd' pointer is uninitialized.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libmediactl.c   |    4 --
 utils/media-ctl/libv4l2subdev.c |   82 +++++++++++++++++++++++++++++++--------
 utils/media-ctl/mediactl-priv.h |    5 ++-
 utils/media-ctl/v4l2subdev.h    |   38 ++++++++++++++++++
 4 files changed, 107 insertions(+), 22 deletions(-)

diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 4a82d24..7e98440 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -525,7 +525,6 @@ static int media_enum_entities(struct media_device *media)
 
 		entity = &media->entities[media->entities_count];
 		memset(entity, 0, sizeof(*entity));
-		entity->fd = -1;
 		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
 		entity->media = media;
 
@@ -719,8 +718,6 @@ void media_device_unref(struct media_device *media)
 
 		free(entity->pads);
 		free(entity->links);
-		if (entity->fd != -1)
-			close(entity->fd);
 	}
 
 	free(media->entities);
@@ -747,7 +744,6 @@ int media_device_add_entity(struct media_device *media,
 	entity = &media->entities[media->entities_count - 1];
 	memset(entity, 0, sizeof *entity);
 
-	entity->fd = -1;
 	entity->media = media;
 	strncpy(entity->devname, devnode, sizeof entity->devname);
 	entity->devname[sizeof entity->devname - 1] = '\0';
diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 33c1ee6..3977ce5 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -39,13 +39,61 @@
 #include "tools.h"
 #include "v4l2subdev.h"
 
+int v4l2_subdev_create(struct media_entity *entity)
+{
+	if (entity->sd)
+		return 0;
+
+	entity->sd = calloc(1, sizeof(*entity->sd));
+	if (entity->sd == NULL)
+		return -ENOMEM;
+
+	entity->sd->fd = -1;
+
+	return 0;
+}
+
+int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
+{
+	int ret;
+
+	if (entity->sd)
+		return -EEXIST;
+
+	ret = v4l2_subdev_create(entity);
+	if (ret < 0)
+		return ret;
+
+	entity->sd->fd = fd;
+
+	return 0;
+}
+
+void v4l2_subdev_release(struct media_entity *entity, bool close_fd)
+{
+	if (entity->sd == NULL)
+		return;
+
+	if (close_fd)
+		v4l2_subdev_close(entity);
+
+	free(entity->sd->v4l2_control_redir);
+	free(entity->sd);
+}
+
 int v4l2_subdev_open(struct media_entity *entity)
 {
-	if (entity->fd != -1)
+	int ret;
+
+	ret = v4l2_subdev_create(entity);
+	if (ret < 0)
+		return ret;
+
+	if (entity->sd->fd != -1)
 		return 0;
 
-	entity->fd = open(entity->devname, O_RDWR);
-	if (entity->fd == -1) {
+	entity->sd->fd = open(entity->devname, O_RDWR);
+	if (entity->sd->fd == -1) {
 		int ret = -errno;
 		media_dbg(entity->media,
 			  "%s: Failed to open subdev device node %s\n", __func__,
@@ -58,8 +106,8 @@ int v4l2_subdev_open(struct media_entity *entity)
 
 void v4l2_subdev_close(struct media_entity *entity)
 {
-	close(entity->fd);
-	entity->fd = -1;
+	close(entity->sd->fd);
+	entity->sd->fd = -1;
 }
 
 int v4l2_subdev_get_format(struct media_entity *entity,
@@ -77,7 +125,7 @@ int v4l2_subdev_get_format(struct media_entity *entity,
 	fmt.pad = pad;
 	fmt.which = which;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
 	if (ret < 0)
 		return -errno;
 
@@ -101,7 +149,7 @@ int v4l2_subdev_set_format(struct media_entity *entity,
 	fmt.which = which;
 	fmt.format = *format;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
 	if (ret < 0)
 		return -errno;
 
@@ -128,7 +176,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
 	u.sel.target = target;
 	u.sel.which = which;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
 	if (ret >= 0) {
 		*rect = u.sel.r;
 		return 0;
@@ -140,7 +188,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
 	u.crop.pad = pad;
 	u.crop.which = which;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
 	if (ret < 0)
 		return -errno;
 
@@ -168,7 +216,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
 	u.sel.which = which;
 	u.sel.r = *rect;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
 	if (ret >= 0) {
 		*rect = u.sel.r;
 		return 0;
@@ -181,7 +229,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
 	u.crop.which = which;
 	u.crop.rect = *rect;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
 	if (ret < 0)
 		return -errno;
 
@@ -202,7 +250,7 @@ int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
 	memset(caps, 0, sizeof(*caps));
 	caps->pad = pad;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
 	if (ret < 0)
 		return -errno;
 
@@ -220,7 +268,7 @@ int v4l2_subdev_query_dv_timings(struct media_entity *entity,
 
 	memset(timings, 0, sizeof(*timings));
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
 	if (ret < 0)
 		return -errno;
 
@@ -238,7 +286,7 @@ int v4l2_subdev_get_dv_timings(struct media_entity *entity,
 
 	memset(timings, 0, sizeof(*timings));
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
 	if (ret < 0)
 		return -errno;
 
@@ -254,7 +302,7 @@ int v4l2_subdev_set_dv_timings(struct media_entity *entity,
 	if (ret < 0)
 		return ret;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
 	if (ret < 0)
 		return -errno;
 
@@ -273,7 +321,7 @@ int v4l2_subdev_get_frame_interval(struct media_entity *entity,
 
 	memset(&ival, 0, sizeof(ival));
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
 	if (ret < 0)
 		return -errno;
 
@@ -294,7 +342,7 @@ int v4l2_subdev_set_frame_interval(struct media_entity *entity,
 	memset(&ival, 0, sizeof(ival));
 	ival.interval = *interval;
 
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
 	if (ret < 0)
 		return -errno;
 
diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
index a0d3a55..f531c52 100644
--- a/utils/media-ctl/mediactl-priv.h
+++ b/utils/media-ctl/mediactl-priv.h
@@ -26,6 +26,8 @@
 
 #include "mediactl.h"
 
+struct v4l2_subdev;
+
 struct media_entity {
 	struct media_device *media;
 	struct media_entity_desc info;
@@ -34,8 +36,9 @@ struct media_entity {
 	unsigned int max_links;
 	unsigned int num_links;
 
+	struct v4l2_subdev *sd;
+
 	char devname[32];
-	int fd;
 };
 
 struct media_device {
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index 104e420..ba9b8c4 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -27,6 +27,44 @@
 struct media_device;
 struct media_entity;
 
+struct v4l2_subdev {
+	int fd;
+};
+
+/**
+ * @brief Create a v4l2-subdev
+ * @param entity - sub-device media entity.
+ *
+ * Create the representation of the entity sub-device.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_create(struct media_entity *entity);
+
+/**
+ * @brief Create a representation of the already opened v4l2-subdev
+ * @param entity - sub-device media entity.
+ * @param fd - sub-device file descriptor.
+ *
+ * Create the representation of the sub-device that had been opened
+ * before the parent media device was created, and associate it
+ * with the media entity.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd);
+
+/**
+ * @brief Release a v4l2-subdev
+ * @param entity - sub-device media entity.
+ * @param close_fd - indicates whether subdev fd should be closed.
+ *
+ * Release the representation of the entity sub-device.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+void v4l2_subdev_release(struct media_entity *entity, bool close_fd);
+
 /**
  * @brief Open a sub-device.
  * @param entity - sub-device media entity.
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 01/15] mediactl: Introduce v4l2_subdev structure Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-15 10:58   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 03/15] mediactl: Separate entity and pad parsing Jacek Anaszewski
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Make struct v4l2_subdev capable of aggregating v4l2-ctrl-redir
media device configuration entries. Added are also functions for
validating the config and checking whether a v4l2 sub-device
expects to receive ioctls related to the v4l2-control with given id.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |   49 ++++++++++++++++++++++++++++++++++++++-
 utils/media-ctl/v4l2subdev.h    |   30 ++++++++++++++++++++++++
 2 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 3977ce5..069ded6 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -26,7 +26,6 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -50,7 +49,15 @@ int v4l2_subdev_create(struct media_entity *entity)
 
 	entity->sd->fd = -1;
 
+	entity->sd->v4l2_control_redir = malloc(sizeof(__u32));
+	if (entity->sd->v4l2_control_redir == NULL)
+		goto err_v4l2_control_redir_alloc;
+
 	return 0;
+
+err_v4l2_control_redir_alloc:
+	free(entity->sd);
+	return -ENOMEM;
 }
 
 int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
@@ -870,3 +877,43 @@ enum v4l2_field v4l2_subdev_string_to_field(const char *string,
 
 	return fields[i].field;
 }
+
+int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
+				   struct media_entity *entity,
+				   __u32 ctrl_id)
+{
+	struct v4l2_queryctrl queryctrl = {};
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	queryctrl.id = ctrl_id;
+
+	ret = ioctl(entity->sd->fd, VIDIOC_QUERYCTRL, &queryctrl);
+	if (ret < 0)
+		return ret;
+
+	media_dbg(media, "Validated control \"%s\" (0x%8.8x) on entity %s\n",
+		  queryctrl.name, queryctrl.id, entity->info.name);
+
+	return 0;
+}
+
+bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
+				  struct media_entity *entity,
+				  int ctrl_id)
+{
+	struct v4l2_subdev *sd = entity->sd;
+	int i;
+
+	if (!sd)
+		return false;
+
+	for (i = 0; i < sd->v4l2_control_redir_num; ++i)
+		if (sd->v4l2_control_redir[i] == ctrl_id)
+			return true;
+
+	return false;
+}
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index ba9b8c4..f395065 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -23,12 +23,17 @@
 #define __SUBDEV_H__
 
 #include <linux/v4l2-subdev.h>
+#include <stdbool.h>
 
 struct media_device;
 struct media_entity;
+struct media_device;
 
 struct v4l2_subdev {
 	int fd;
+
+	__u32 *v4l2_control_redir;
+	unsigned int v4l2_control_redir_num;
 };
 
 /**
@@ -316,5 +321,30 @@ const char *v4l2_subdev_field_to_string(enum v4l2_field field);
  */
 enum v4l2_field v4l2_subdev_string_to_field(const char *string,
 					    unsigned int length);
+/**
+ * @brief Validate v4l2 control for a sub-device
+ * @param media - media device.
+ * @param entity - subdev-device media entity.
+ * @param ctrl_id - id of the v4l2 control to validate.
+ *
+ * Verify if the entity supports v4l2-control with given ctrl_id.
+ *
+ * @return 1 if the control is supported, 0 otherwise.
+ */
+int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
+				   struct media_entity *entity,
+				   __u32 ctrl_id);
+/**
+ * @brief Check if there was a v4l2_control redirection defined for the entity
+ * @param media - media device.
+ * @param entity - subdev-device media entity.
+ * @param ctrl_id - v4l2 control identifier.
+ *
+ * Check if there was a v4l2-ctrl-redir entry defined for the entity.
+ *
+ * @return true if the entry exists, false otherwise
+ */
+bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
+	struct media_entity *entity, int ctrl_id);
 
 #endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 03/15] mediactl: Separate entity and pad parsing
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 01/15] mediactl: Introduce v4l2_subdev structure Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 04/15] mediatext: Add library Jacek Anaszewski
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Sometimes it's useful to be able to parse the entity independent of the pad.
Separate entity parsing into media_parse_entity().

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 utils/media-ctl/libmediactl.c |   28 ++++++++++++++++++++++++----
 utils/media-ctl/mediactl.h    |   14 ++++++++++++++
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 7e98440..61b5f50 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -781,10 +781,10 @@ int media_device_add_entity(struct media_device *media,
 	return 0;
 }
 
-struct media_pad *media_parse_pad(struct media_device *media,
-				  const char *p, char **endp)
+struct media_entity *media_parse_entity(struct media_device *media,
+					const char *p, char **endp)
 {
-	unsigned int entity_id, pad;
+	unsigned int entity_id;
 	struct media_entity *entity;
 	char *end;
 
@@ -821,7 +821,27 @@ struct media_pad *media_parse_pad(struct media_device *media,
 			return NULL;
 		}
 	}
-	for (; isspace(*end); ++end);
+	for (p = end; isspace(*p); ++p);
+
+	*endp = (char *)p;
+
+	return entity;
+}
+
+struct media_pad *media_parse_pad(struct media_device *media,
+				  const char *p, char **endp)
+{
+	unsigned int pad;
+	struct media_entity *entity;
+	char *end;
+
+	if (endp == NULL)
+		endp = &end;
+
+	entity = media_parse_entity(media, p, &end);
+	if (!entity)
+		return NULL;
+	*endp = end;
 
 	if (*end != ':') {
 		media_dbg(media, "Expected ':'\n", *end);
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 77ac182..3faee71 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -368,6 +368,20 @@ int media_setup_link(struct media_device *media,
 int media_reset_links(struct media_device *media);
 
 /**
+ * @brief Parse string to an entity on the media device.
+ * @param media - media device.
+ * @param p - input string
+ * @param endp - pointer to string where parsing ended
+ *
+ * Parse NULL terminated string describing an entity and return its
+ * struct media_entity instance.
+ *
+ * @return Pointer to struct media_entity on success, NULL on failure.
+ */
+struct media_entity *media_parse_entity(struct media_device *media,
+					const char *p, char **endp);
+
+/**
  * @brief Parse string to a pad on the media device.
  * @param media - media device.
  * @param p - input string
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 04/15] mediatext: Add library
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (2 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 03/15] mediactl: Separate entity and pad parsing Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 05/15] mediactl: Add media device graph helpers Jacek Anaszewski
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski, Teemu Tuominen

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 14351 bytes --]

libmediatext is a helper library for converting configurations (Media
controller links, V4L2 controls and V4L2 sub-device media bus formats and
selections) from text-based form into IOCTLs.

libmediatext depends on libv4l2subdev and libmediactl.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Teemu Tuominen <teemu.tuominen@intel.com>
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
---
 utils/media-ctl/Makefile.am        |   10 +-
 utils/media-ctl/libmediatext.pc.in |   10 ++
 utils/media-ctl/mediatext-test.c   |   64 ++++++++
 utils/media-ctl/mediatext.c        |  311 ++++++++++++++++++++++++++++++++++++
 utils/media-ctl/mediatext.h        |   52 ++++++
 5 files changed, 445 insertions(+), 2 deletions(-)
 create mode 100644 utils/media-ctl/libmediatext.pc.in
 create mode 100644 utils/media-ctl/mediatext-test.c
 create mode 100644 utils/media-ctl/mediatext.c
 create mode 100644 utils/media-ctl/mediatext.h

diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
index a3931fb..3e883e0 100644
--- a/utils/media-ctl/Makefile.am
+++ b/utils/media-ctl/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la
+noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
 
 libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
 libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
@@ -9,9 +9,15 @@ libv4l2subdev_la_LIBADD = libmediactl.la
 libv4l2subdev_la_CFLAGS = -static
 libv4l2subdev_la_LDFLAGS = -static
 
+libmediatext_la_SOURCES = mediatext.c
+libmediatext_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
+libmediatext_la_LDFLAGS = -static $(LIBUDEV_LIBS)
+
 mediactl_includedir=$(includedir)/mediactl
 noinst_HEADERS = mediactl.h v4l2subdev.h
 
-bin_PROGRAMS = media-ctl
+bin_PROGRAMS = media-ctl mediatext-test
 media_ctl_SOURCES = media-ctl.c options.c options.h tools.h
 media_ctl_LDADD = libmediactl.la libv4l2subdev.la
+mediatext_test_SOURCES = mediatext-test.c
+mediatext_test_LDADD = libmediatext.la libmediactl.la libv4l2subdev.la
diff --git a/utils/media-ctl/libmediatext.pc.in b/utils/media-ctl/libmediatext.pc.in
new file mode 100644
index 0000000..6aa6353
--- /dev/null
+++ b/utils/media-ctl/libmediatext.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libmediatext
+Description: Media controller and V4L2 text-based configuration library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lmediatext
diff --git a/utils/media-ctl/mediatext-test.c b/utils/media-ctl/mediatext-test.c
new file mode 100644
index 0000000..e3ae89c
--- /dev/null
+++ b/utils/media-ctl/mediatext-test.c
@@ -0,0 +1,64 @@
+/*
+ * libmediatext test program
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mediactl.h"
+#include "mediatext.h"
+
+int main(int argc, char *argv[])
+{
+	struct media_device *device;
+	int rval;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s <media device> <string>\n\n", argv[0]);
+		fprintf(stderr, "\tstring := [ v4l2-ctrl | v4l2-mbus | link-reset | link-conf]\n\n");
+		fprintf(stderr, "\tv4l2-ctrl := \"entity\" ctrl_type ctrl_id ctrl_value\n");
+		fprintf(stderr, "\tctrl_type := [ int | int64 | bitmask ]\n");
+		fprintf(stderr, "\tctrl_value := [ %%d | %%PRId64 | bitmask_value ]\n");
+		fprintf(stderr, "\tbitmask_value := b<binary_number>\n\n");
+		fprintf(stderr, "\tv4l2-mbus := \n");
+		fprintf(stderr, "\tlink-conf := \"entity\":pad -> \"entity\":pad[link-flags]\n");
+		fprintf(stderr, "\tv4l2-ctrl-redir := ctrl_id -> \"entity\"\n");
+		return EXIT_FAILURE;
+	}
+
+	device = media_device_new(argv[1]);
+	if (!device)
+		return EXIT_FAILURE;
+
+	rval = media_device_enumerate(device);
+	if (rval)
+		return EXIT_FAILURE;
+
+	rval = mediatext_parse(device, argv[2]);
+	if (rval) {
+		fprintf(stderr, "bad string %s (%s)\n", argv[2], strerror(-rval));
+		return EXIT_FAILURE;
+	}
+
+	media_device_unref(device);
+
+	return EXIT_SUCCESS;
+}
diff --git a/utils/media-ctl/mediatext.c b/utils/media-ctl/mediatext.c
new file mode 100644
index 0000000..c39e889
--- /dev/null
+++ b/utils/media-ctl/mediatext.c
@@ -0,0 +1,311 @@
+/*
+ * Media controller text-based configuration library
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/ioctl.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <linux/types.h>
+
+#include "mediactl.h"
+#include "mediactl-priv.h"
+#include "tools.h"
+#include "v4l2subdev.h"
+
+struct parser {
+	char *prefix;
+	int (*parse)(struct media_device *media, const struct parser *p,
+		     char *string);
+	struct parser *next;
+	bool no_args;
+};
+
+static int parse(struct media_device *media, const struct parser *p, char *string)
+{
+	for (; p->prefix; p++) {
+		size_t len = strlen(p->prefix);
+
+		if (strncmp(p->prefix, string, len) || string[len] != ' ')
+			continue;
+
+		string += len;
+
+		for (; isspace(*string); string++);
+
+		if (p->no_args)
+			return p->parse(media, p->next, NULL);
+
+		if (strlen(string) == 0)
+			return -ENOEXEC;
+
+		return p->parse(media, p->next, string);
+	}
+
+	media_dbg(media, "Unknown parser prefix\n");
+
+	return -ENOENT;
+}
+
+struct ctrl_type {
+	uint32_t type;
+	char *str;
+} ctrltypes[] = {
+	{ V4L2_CTRL_TYPE_INTEGER, "int" },
+	{ V4L2_CTRL_TYPE_MENU, "menu" },
+	{ V4L2_CTRL_TYPE_INTEGER_MENU, "intmenu" },
+	{ V4L2_CTRL_TYPE_BITMASK, "bitmask" },
+	{ V4L2_CTRL_TYPE_INTEGER64, "int64" },
+};
+
+static int parse_v4l2_ctrl_id(struct media_device *media, const struct parser *p,
+			      char *string, char **endp, __u32 *ctrl_id)
+{
+	int rval;
+
+	for (; isspace(*string); string++);
+	rval = sscanf(string, "0x%" PRIx32, ctrl_id);
+	if (rval <= 0)
+		return -EINVAL;
+
+	for (; !isspace(*string) && *string; string++);
+	for (; isspace(*string); string++);
+
+	*endp = string;
+
+	return 0;
+}
+
+/* adapted from yavta.c */
+static int parse_v4l2_ctrl(struct media_device *media, const struct parser *p,
+			   char *string)
+{
+	struct v4l2_ext_control ctrl = { 0 };
+	struct v4l2_ext_controls ctrls = { .count = 1,
+					   .controls = &ctrl };
+	int64_t val;
+	int rval;
+	struct media_entity *entity;
+	struct ctrl_type *ctype;
+	unsigned int i;
+
+	entity = media_parse_entity(media, string, &string);
+	if (!entity)
+		return -ENOENT;
+
+	for (i = 0; i < ARRAY_SIZE(ctrltypes); i++)
+		if (!strncmp(string, ctrltypes[i].str,
+			     strlen(ctrltypes[i].str)))
+			break;
+
+	if (i == ARRAY_SIZE(ctrltypes))
+		return -ENOENT;
+
+	ctype = &ctrltypes[i];
+
+	string += strlen(ctrltypes[i].str);
+
+	rval = parse_v4l2_ctrl_id(media, p, string, &string, &ctrl.id);
+	if (rval < 0)
+		return -EINVAL;
+
+	ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(ctrl.id);
+
+	switch (ctype->type) {
+	case V4L2_CTRL_TYPE_BITMASK:
+		if (*string++ != 'b')
+			return -EINVAL;
+		while (*string == '1' || *string == '0') {
+			val <<= 1;
+			if (*string == '1')
+				val++;
+			string++;
+		}
+		break;
+	default:
+		rval = sscanf(string, "%" PRId64, &val);
+		break;
+	}
+	if (rval <= 0)
+		return -EINVAL;
+
+	media_dbg(media, "Setting control 0x%8.8x (type %s), value %" PRId64 "\n",
+		  ctrl.id, ctype->str, val);
+
+	if (ctype->type == V4L2_CTRL_TYPE_INTEGER64)
+		ctrl.value64 = val;
+	else
+		ctrl.value = val;
+
+	rval = v4l2_subdev_open(entity);
+	if (rval < 0)
+		return rval;
+
+	rval = ioctl(entity->sd->fd, VIDIOC_S_EXT_CTRLS, &ctrls);
+	if (ctype->type != V4L2_CTRL_TYPE_INTEGER64) {
+		if (rval != -1) {
+			ctrl.value64 = ctrl.value;
+		} else if (ctype->type != V4L2_CTRL_TYPE_STRING &&
+			   (errno == EINVAL || errno == ENOTTY)) {
+			struct v4l2_control old = { .id = ctrl.id,
+						    .value = val };
+
+			rval = ioctl(entity->sd->fd, VIDIOC_S_CTRL, &old);
+			if (rval != -1)
+				ctrl.value64 = old.value;
+		}
+	}
+	if (rval == -1) {
+		media_dbg(media,
+			  "Failed setting control 0x%8.8x: %s (%d) to value %"
+			  PRId64 "\n", ctrl.id, strerror(errno), errno, val);
+		return -errno;
+	}
+
+	if (val != ctrl.value64)
+		media_dbg(media, "Asking for %" PRId64 ", got %" PRId64 "\n",
+			  val, ctrl.value64);
+
+	return 0;
+}
+
+/*
+
+parse_name(string, end)
+
+*/
+
+int parse_v4l2_ctrl_redir(struct media_device *media, const struct parser *p,
+			   char *string)
+{
+	struct media_entity *entity;
+	struct v4l2_subdev *sd;
+	__u32 ctrl_id;
+	int rval;
+
+	rval = parse_v4l2_ctrl_id(media, p, string, &string, &ctrl_id);
+	if (rval < 0)
+		return -EINVAL;
+
+	for (; isspace(*string); ++string);
+
+	if (string[0] != '-' || string[1] != '>') {
+		media_dbg(media, "Expected '->'\n");
+		return -EINVAL;
+	}
+
+	string += 2;
+
+	entity = media_parse_entity(media, string, &string);
+	if (!entity)
+		return -ENOENT;
+
+	rval = v4l2_subdev_validate_v4l2_ctrl(media, entity, ctrl_id);
+	if (rval < 0) {
+		media_dbg(media, "Failed to validate a v4l2 control on entity %s\n",
+			  entity->info.name);
+		return rval;
+	}
+
+	sd = entity->sd;
+
+	sd->v4l2_control_redir = realloc(sd->v4l2_control_redir,
+					 sizeof(*sd->v4l2_control_redir) *
+					 (sd->v4l2_control_redir_num + 1));
+	if (!sd->v4l2_control_redir)
+		return -ENOMEM;
+
+	sd->v4l2_control_redir[sd->v4l2_control_redir_num] = ctrl_id;
+	++sd->v4l2_control_redir_num;
+
+	return 0;
+}
+
+static int parse_v4l2_mbus(struct media_device *media, const struct parser *p,
+			   char *string)
+{
+	media_dbg(media, "Media bus format setup: %s\n", string);
+	return v4l2_subdev_parse_setup_formats(media, string);
+}
+
+static int parse_link_reset(struct media_device *media, const struct parser *p,
+			    char *string)
+{
+	media_dbg(media, "Resetting links\n");
+	return media_reset_links(media);
+}
+
+static int parse_link_conf(struct media_device *media, const struct parser *p,
+			   char *string)
+{
+	media_dbg(media, "Configuring links: %s\n", string);
+	return media_parse_setup_links(media, string);
+}
+
+static const struct parser parsers[] = {
+	{ "v4l2-ctrl", parse_v4l2_ctrl },
+	{ "v4l2-ctrl-redir", parse_v4l2_ctrl_redir },
+	{ "v4l2-mbus", parse_v4l2_mbus },
+	{ "link-reset", parse_link_reset, NULL, true },
+	{ "link-conf", parse_link_conf },
+	{ 0 }
+};
+
+int mediatext_parse(struct media_device *media, char *string)
+{
+	return parse(media, parsers, string);
+}
+
+int mediatext_parse_setup_config(struct media_device *device, const char *conf_path)
+{
+	char *line;
+	size_t n = 0;
+	FILE *f;
+	int ret;
+
+	if (conf_path == NULL)
+		return -EINVAL;
+
+	f = fopen(conf_path, "r");
+	if (!f)
+		return -EINVAL;
+
+	while (getline(&line, &n, f) != -1) {
+		ret = mediatext_parse(device, line);
+		if (ret < 0)
+			goto err_parse;
+		free(line);
+		line = NULL;
+		n = 0;
+	}
+
+err_parse:
+	fclose(f);
+	return ret;
+}
diff --git a/utils/media-ctl/mediatext.h b/utils/media-ctl/mediatext.h
new file mode 100644
index 0000000..7dfbaf6
--- /dev/null
+++ b/utils/media-ctl/mediatext.h
@@ -0,0 +1,52 @@
+/*
+ * Media controller text-based configuration library
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MEDIATEXT_H__
+#define __MEDIATEXT_H__
+
+struct media_device;
+
+/**
+ * @brief Parse and apply media device command
+ * @param device - media device
+ * @param string - string to parse
+ *
+ * Parse media device command and apply it to the media device
+ * passed in the device argument.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int mediatext_parse(struct media_device *device, char *string);
+
+/**
+ * @brief Parse and apply media device configuration
+ * @param media - media device
+ * @param conf_path - path to the configuration file
+ *
+ * Parse the media device commands listed in the file under
+ * conf_path and apply them to the media device passed in the
+ * device argument.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int mediatext_parse_setup_config(struct media_device *device, const char *conf_path);
+
+#endif /* __MEDIATEXT_H__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 05/15] mediactl: Add media device graph helpers
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (3 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 04/15] mediatext: Add library Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-15 12:02   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 06/15] mediactl: Add media_device creation helpers Jacek Anaszewski
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add new graph helpers useful for video pipeline discovering.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libmediactl.c |   48 +++++++++++++++++++++++++++++++++++++++++
 utils/media-ctl/mediactl.h    |   36 +++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 61b5f50..0be1845 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -35,6 +35,7 @@
 #include <unistd.h>
 
 #include <linux/media.h>
+#include <linux/kdev_t.h>
 #include <linux/videodev2.h>
 
 #include "mediactl.h"
@@ -87,6 +88,29 @@ struct media_entity *media_get_entity_by_name(struct media_device *media,
 	return NULL;
 }
 
+struct media_entity *media_get_entity_by_devname(struct media_device *media,
+						 const char *devname,
+						 size_t length)
+{
+	unsigned int i;
+
+	/* A match is impossible if the entity devname is longer than the
+	 * maximum size we can get from the kernel.
+	 */
+	if (length >= FIELD_SIZEOF(struct media_entity, devname))
+		return NULL;
+
+	for (i = 0; i < media->entities_count; ++i) {
+		struct media_entity *entity = &media->entities[i];
+
+		if (strncmp(entity->devname, devname, length) == 0 &&
+		    entity->devname[length] == '\0')
+			return entity;
+	}
+
+	return NULL;
+}
+
 struct media_entity *media_get_entity_by_id(struct media_device *media,
 					    __u32 id)
 {
@@ -145,6 +169,11 @@ const char *media_entity_get_devname(struct media_entity *entity)
 	return entity->devname[0] ? entity->devname : NULL;
 }
 
+const char *media_entity_get_name(struct media_entity *entity)
+{
+	return entity->info.name;
+}
+
 struct media_entity *media_get_default_entity(struct media_device *media,
 					      unsigned int type)
 {
@@ -177,6 +206,25 @@ const struct media_entity_desc *media_entity_get_info(struct media_entity *entit
 	return &entity->info;
 }
 
+int media_get_backlinks_by_entity(struct media_entity *entity,
+				struct media_link **backlinks,
+				int *num_backlinks)
+{
+	int num_bklinks = 0, i;
+
+	if (entity == NULL || backlinks == NULL || num_backlinks == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < entity->num_links; ++i)
+		if ((entity->links[i].flags & MEDIA_LNK_FL_ENABLED) &&
+		    (entity->links[i].sink->entity == entity))
+			backlinks[num_bklinks++] = &entity->links[i];
+
+	*num_backlinks = num_bklinks;
+
+	return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * Open/close
  */
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 3faee71..9db40a8 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -231,6 +231,15 @@ const struct media_link *media_entity_get_link(struct media_entity *entity,
 const char *media_entity_get_devname(struct media_entity *entity);
 
 /**
+ * @brief Get the name for an entity
+ * @param entity - media entity.
+ *
+ * This function returns the name of the entity.
+ *
+ * @return A pointer to the string with entity name
+ */
+const char *media_entity_get_name(struct media_entity *entity);
+
  * @brief Get the type of an entity.
  * @param entity - the entity.
  *
@@ -255,6 +264,19 @@ struct media_entity *media_get_entity_by_name(struct media_device *media,
 	const char *name, size_t length);
 
 /**
+ * @brief Find an entity by the corresponding device node name.
+ * @param media - media device.
+ * @param devname - device node name.
+ * @param length - size of @a devname.
+ *
+ * Search for an entity with a device node name equal to @a devname.
+ *
+ * @return A pointer to the entity if found, or NULL otherwise.
+ */
+struct media_entity *media_get_entity_by_devname(struct media_device *media,
+	const char *devname, size_t length);
+
+/**
  * @brief Find an entity by its ID.
  * @param media - media device.
  * @param id - entity ID.
@@ -434,4 +456,18 @@ int media_parse_setup_link(struct media_device *media,
  */
 int media_parse_setup_links(struct media_device *media, const char *p);
 
+/**
+ * @brief Get entity's enabled backlinks
+ * @param entity - media entity.
+ * @param backlinks - array of pointers to matching backlinks.
+ * @param num_backlinks - number of matching backlinks.
+ *
+ * Get links that are connected to the entity sink pads.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_backlinks_by_entity(struct media_entity *entity,
+				struct media_link **backlinks,
+				int *num_backlinks);
+
 #endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 06/15] mediactl: Add media_device creation helpers
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (4 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 05/15] mediactl: Add media device graph helpers Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-15 14:30   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 07/15] mediactl: libv4l2subdev: add VYUY8_2X8 mbus code Jacek Anaszewski
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add helper functions that allow for easy instantiation of media_device
object basing on whether the media device contains video device with
given node name.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libmediactl.c |   75 +++++++++++++++++++++++++++++++++++++++++
 utils/media-ctl/mediactl.h    |   30 +++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 0be1845..3a45ecc 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -734,6 +734,44 @@ struct media_device *media_device_new(const char *devnode)
 	return media;
 }
 
+struct media_device *media_device_new_by_entity_devname(char *entity_devname)
+{
+	struct media_device *media;
+	char media_devname[32];
+	struct media_entity *entity;
+	int i, ret;
+
+	/* query all available media devices */
+	for (i = 0;; ++i) {
+		sprintf(media_devname, "/dev/media%d", i);
+
+		media = media_device_new(media_devname);
+		if (media == NULL)
+			return NULL;
+
+		ret = media_device_enumerate(media);
+		if (ret < 0) {
+			media_dbg(media, "Failed to enumerate %s (%d)\n",
+				  media_devname, ret);
+			goto err_dev_enum;
+		}
+
+		/* Check if the media device contains entity with entity_devname */
+		entity = media_get_entity_by_devname(media, entity_devname,
+							strlen(entity_devname));
+		if (entity)
+			return media;
+
+		if (media)
+			media_device_unref(media);
+	}
+
+err_dev_enum:
+	if (media)
+		media_device_unref(media);
+	return NULL;
+}
+
 struct media_device *media_device_new_emulated(struct media_device_info *info)
 {
 	struct media_device *media;
@@ -773,6 +811,43 @@ void media_device_unref(struct media_device *media)
 	free(media);
 }
 
+int media_get_devname_by_fd(int fd, char *node_name)
+{
+	struct udev *udev;
+	struct media_entity tmp_entity;
+	struct stat stat;
+	int ret;
+
+	if (node_name == NULL)
+		return -EINVAL;
+
+	ret = fstat(fd, &stat);
+	if (ret < 0)
+		return -EINVAL;
+
+	tmp_entity.info.v4l.major = MAJOR(stat.st_rdev);
+	tmp_entity.info.v4l.minor = MINOR(stat.st_rdev);
+
+	ret = media_udev_open(&udev);
+	if (ret < 0)
+		printf("Can't get udev context\n");
+
+	/* Try to get the device name via udev */
+	ret = media_get_devname_udev(udev, &tmp_entity);
+	if (!ret)
+		goto out;
+
+	ret = media_get_devname_sysfs(&tmp_entity);
+	if (ret < 0)
+		goto err_get_devname;
+
+out:
+	strcpy(node_name, tmp_entity.devname);
+err_get_devname:
+	media_udev_close(udev);
+	return ret;
+}
+
 int media_device_add_entity(struct media_device *media,
 			    const struct media_entity_desc *desc,
 			    const char *devnode)
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 9db40a8..1d62191 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -76,6 +76,23 @@ struct media_device *media_device_new(const char *devnode);
 struct media_device *media_device_new_emulated(struct media_device_info *info);
 
 /**
+ * @brief Create a new media device if it comprises entity with given devname
+ * @param entity_devname - device node name of the entity to be matched.
+ *
+ * Query all media devices available in the system to find the one comprising
+ * the entity with given devname. If the media device is matched then its
+ * instance is created and initialized with enumerated entities and links.
+ * The returned device can be accessed.
+ *
+ * Media devices are reference-counted, see media_device_ref() and
+ * media_device_unref() for more information.
+ *
+ * @return A pointer to the new media device or NULL if video_devname cannot
+ * be matched or memory cannot be allocated.
+ */
+struct media_device *media_device_new_by_entity_devname(char *entity_devname);
+
+/**
  * @brief Take a reference to the device.
  * @param media - device instance.
  *
@@ -240,6 +257,19 @@ const char *media_entity_get_devname(struct media_entity *entity);
  */
 const char *media_entity_get_name(struct media_entity *entity);
 
+/**
+ * @brief Get the device node name by its file descriptor
+ * @param fd - file descriptor of a device.
+ * @param node_name - output device node name string.
+ *
+ * This function returns the full path and name to the device node corresponding
+ * to the given file descriptor.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_devname_by_fd(int fd, char *node_name);
+
+/**
  * @brief Get the type of an entity.
  * @param entity - the entity.
  *
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 07/15] mediactl: libv4l2subdev: add VYUY8_2X8 mbus code
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (5 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 06/15] mediactl: Add media_device creation helpers Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-15 15:55   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 08/15] mediactl: Add support for media device pipelines Jacek Anaszewski
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

The VYUY8_2X8 media bus format is the only one supported
by the S5C73M3 camera sensor, that is a part of the media
device on the Exynos4412-trats2 board.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 069ded6..5175188 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -780,6 +780,7 @@ static struct {
 	{ "YUYV", MEDIA_BUS_FMT_YUYV8_1X16 },
 	{ "YUYV1_5X8", MEDIA_BUS_FMT_YUYV8_1_5X8 },
 	{ "YUYV2X8", MEDIA_BUS_FMT_YUYV8_2X8 },
+	{ "VYUY8_2X8", V4L2_MBUS_FMT_VYUY8_2X8 },
 	{ "UYVY", MEDIA_BUS_FMT_UYVY8_1X16 },
 	{ "UYVY1_5X8", MEDIA_BUS_FMT_UYVY8_1_5X8 },
 	{ "UYVY2X8", MEDIA_BUS_FMT_UYVY8_2X8 },
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 08/15] mediactl: Add support for media device pipelines
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (6 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 07/15] mediactl: libv4l2subdev: add VYUY8_2X8 mbus code Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-15 16:53   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 09/15] mediactl: libv4l2subdev: Add colorspace logging Jacek Anaszewski
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add infrastructure for linking media entities and discovering
media device pipelines.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libmediactl.c   |  117 +++++++++++++++++++++++++++++++++++++++
 utils/media-ctl/mediactl-priv.h |    6 ++
 utils/media-ctl/mediactl.h      |   71 ++++++++++++++++++++++++
 3 files changed, 194 insertions(+)

diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 3a45ecc..9909c1c 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -1109,3 +1109,120 @@ int media_parse_setup_links(struct media_device *media, const char *p)
 
 	return *end ? -EINVAL : 0;
 }
+
+/* -----------------------------------------------------------------------------
+ * Pipeline operations
+ */
+
+int media_discover_pipeline_by_entity(struct media_device *media,
+				      struct media_entity *entity)
+{
+	struct media_entity *pipe_head = NULL;
+	struct media_pad *src_pad;
+	struct media_link *link = NULL, *backlinks[10];
+	int i, num_backlinks, ret;
+
+	if (entity == NULL)
+		return -EINVAL;
+
+	for (;;) {
+		/* Make recently discovered entity the pipeline head */
+		if (pipe_head == NULL) {
+			pipe_head = entity;
+		} else {
+			entity->next = pipe_head;
+			pipe_head = entity;
+		}
+
+		/* Cache a source pad used for linking the entity */
+		if (link)
+			entity->pipe_src_pad = link->source;
+
+		ret = media_get_backlinks_by_entity(entity,
+						    backlinks,
+						    &num_backlinks);
+		if (ret < 0)
+			return ret;
+
+		/* check if pipeline source entity has been reached */
+		if (num_backlinks > 2) {
+			media_dbg(media, "Unexpected number of busy sink pads (%d)\n", num_backlinks);
+			return -EINVAL;
+		} else if (num_backlinks == 2) {
+			/*
+			 * Allow two active pads only in case of
+			 * S5C73M3-OIF entity.
+			 */
+			if (strcmp(entity->info.name, "S5C73M3-OIF")) {
+				media_dbg(media, "Ambiguous media device topology: two busy sink pads");
+				return -EINVAL;
+			}
+			/*
+			 * Two active links are allowed betwen S5C73M3-OIF and
+			 * S5C73M3 entities. In such a case a route through pad
+			 * with id == 0 has to be selected.
+			 */
+			for (i = 0; i < num_backlinks; i++)
+				if (backlinks[i]->sink->index == 0)
+					link = backlinks[i];
+		} else if (num_backlinks == 1)
+			link = backlinks[0];
+		else
+			break;
+
+		/* Cache a sink pad used for linking the entity */
+		entity->pipe_sink_pad = link->sink;
+
+		media_dbg(media, "Discovered sink pad %d for the %s entity\n",
+			  entity->pipe_sink_pad->index, media_entity_get_name(entity));
+
+		src_pad = media_entity_remote_source(link->sink);
+		if (!src_pad)
+			return -EINVAL;
+
+		entity = src_pad->entity;
+	}
+
+	media->pipeline = pipe_head;
+
+	return 0;
+}
+
+int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name)
+{
+	if (pipeline == NULL || entity_name == NULL)
+		return -EINVAL;
+
+	while (pipeline) {
+		if (!strncmp(pipeline->info.name, entity_name,
+			     strlen(entity_name)))
+			return 1;
+		pipeline = pipeline->next;
+	}
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Media entity access
+ */
+
+struct media_entity *media_get_pipeline(struct media_device *media)
+{
+	return media->pipeline;
+}
+
+int media_entity_get_src_pad_index(struct media_entity *entity)
+{
+	return entity->pipe_src_pad->index;
+}
+
+int media_entity_get_sink_pad_index(struct media_entity *entity)
+{
+	return entity->pipe_sink_pad->index;
+}
+
+struct media_entity *media_entity_get_next(struct media_entity *entity)
+{
+	return entity->next;
+}
diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
index f531c52..3378880 100644
--- a/utils/media-ctl/mediactl-priv.h
+++ b/utils/media-ctl/mediactl-priv.h
@@ -36,9 +36,14 @@ struct media_entity {
 	unsigned int max_links;
 	unsigned int num_links;
 
+	struct media_pad *pipe_src_pad;
+	struct media_pad *pipe_sink_pad;
+
 	struct v4l2_subdev *sd;
 
 	char devname[32];
+
+	struct media_entity *next;
 };
 
 struct media_device {
@@ -49,6 +54,7 @@ struct media_device {
 	struct media_device_info info;
 	struct media_entity *entities;
 	unsigned int entities_count;
+	struct media_entity *pipeline;
 
 	void (*debug_handler)(void *, ...);
 	void *debug_priv;
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 1d62191..4570160 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -500,4 +500,75 @@ int media_get_backlinks_by_entity(struct media_entity *entity,
 				struct media_link **backlinks,
 				int *num_backlinks);
 
+/**
+ * @brief Check presence of the entity in the pipeline
+ * @param pipeline - video pipeline within a media device.
+ * @param entity_name - name of the entity to search for.
+ *
+ * Check if the entity with entity_name belongs to
+ * the pipeline.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name);
+
+/**
+ * @brief Discover the video pipeline
+ * @param media - media device.
+ * @param entity - media entity.
+ *
+ * Discover the pipeline of sub-devices, by walking
+ * upstream starting from the passed sink entity until
+ * the camera sensor entity is encountered.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_discover_pipeline_by_entity(struct media_device *media,
+				struct media_entity *entity);
+
+/**
+ * @brief Get source pad of the pipeline entity
+ * @param entity - media entity.
+ *
+ * This function returns the source pad of the entity.
+ *
+ * @return entity source pad, or NULL if the entity is not linked.
+ */
+int media_entity_get_src_pad_index(struct media_entity *entity);
+
+/**
+ * @brief Get sink pad of the pipeline entity
+ * @param entity - media entity.
+ *
+ * This function returns the sink pad of the entity.
+ *
+ * @return entity sink pad, or NULL if the entity is not linked.
+ */
+int media_entity_get_sink_pad_index(struct media_entity *entity);
+
+/**
+ * @brief Get next entity in the pipeline
+ * @param entity - media entity
+ *
+ * This function gets the entity connected to a source pad of this entity.
+ *
+ * @return next enetity in the pipeline,
+ *	   or NULL if the entity is not linked
+ */
+struct media_entity *media_entity_get_next(struct media_entity *entity);
+
+/**
+ * @brief Get the video pipeline
+ * @param media - media device
+ *
+ * This function gets the pipeline of media entities. The pipeline
+ * source entity is a camera sensor and the sink one is the entity
+ * representing opened video device node. The pipeline has to be
+ * discovered with use of the function media_discover_pipeline_by_entity.
+ *
+ * @return first media_entity in the pipeline,
+ *	   or NULL if the pipeline hasn't been discovered
+ */
+struct media_entity *media_get_pipeline(struct media_device *media);
+
 #endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 09/15] mediactl: libv4l2subdev: Add colorspace logging
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (7 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 08/15] mediactl: Add support for media device pipelines Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 10/15] mediactl: libv4l2subdev: add support for comparing mbus formats Jacek Anaszewski
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add a function for obtaining colorspace name by id.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |   32 ++++++++++++++++++++++++++++++++
 utils/media-ctl/v4l2subdev.h    |   10 ++++++++++
 2 files changed, 42 insertions(+)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 5175188..b3d11ef 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -32,6 +32,7 @@
 #include <unistd.h>
 
 #include <linux/v4l2-subdev.h>
+#include <linux/videodev2.h>
 
 #include "mediactl.h"
 #include "mediactl-priv.h"
@@ -819,6 +820,37 @@ const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code)
 	return "unknown";
 }
 
+static struct {
+	const char *name;
+	enum v4l2_colorspace cs;
+} colorspaces[] = {
+        { "DEFAULT", V4L2_COLORSPACE_DEFAULT },
+        { "SMPTE170M", V4L2_COLORSPACE_SMPTE170M },
+        { "SMPTE240M", V4L2_COLORSPACE_SMPTE240M },
+        { "REC709", V4L2_COLORSPACE_REC709 },
+        { "BT878", V4L2_COLORSPACE_BT878 },
+        { "470_SYSTEM_M", V4L2_COLORSPACE_470_SYSTEM_M },
+        { "470_SYSTEM_BG", V4L2_COLORSPACE_470_SYSTEM_BG },
+        { "JPEG", V4L2_COLORSPACE_JPEG },
+        { "SRGB", V4L2_COLORSPACE_SRGB },
+        { "ADOBERGB", V4L2_COLORSPACE_ADOBERGB },
+        { "BT2020", V4L2_COLORSPACE_BT2020 },
+        { "RAW", V4L2_COLORSPACE_RAW },
+        { "DCI_P3", V4L2_COLORSPACE_DCI_P3 },
+};
+
+const char *v4l2_subdev_colorspace_to_string(enum v4l2_colorspace cs)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(colorspaces); ++i) {
+		if (colorspaces[i].cs == cs)
+			return colorspaces[i].name;
+	}
+
+	return "unknown";
+}
+
 enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
 							 unsigned int length)
 {
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index f395065..7d9e53a 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -289,6 +289,16 @@ int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p);
 const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code);
 
 /**
+ * @brief Convert colorspace to string.
+ * @param code - input string
+ *
+ * Convert colorspace @a to a human-readable string.
+ *
+ * @return A pointer to a string on success, NULL on failure.
+ */
+const char *v4l2_subdev_colorspace_to_string(enum v4l2_colorspace cs);
+
+/**
  * @brief Parse string to media bus pixel code.
  * @param string - input string
  * @param length - length of the string
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 10/15] mediactl: libv4l2subdev: add support for comparing mbus formats
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (8 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 09/15] mediactl: libv4l2subdev: Add colorspace logging Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 11/15] mediactl: libv4l2subdev: add support for setting pipeline format Jacek Anaszewski
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

This patch adds a function for checking whether two mbus formats
are compatible.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |   39 +++++++++++++++++++++++++++++++++++++++
 utils/media-ctl/v4l2subdev.h    |   22 ++++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index b3d11ef..3282fe9 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -934,6 +934,45 @@ int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
 	return 0;
 }
 
+enum v4l2_subdev_fmt_mismatch v4l2_subdev_format_compare(
+				struct v4l2_mbus_framefmt *fmt1,
+				struct v4l2_mbus_framefmt *fmt2)
+{
+	if (fmt1 == NULL || fmt2 == NULL)
+		return 0;
+
+	if (fmt1->width != fmt2->width) {
+		printf("width mismatch (%d %d)\n", fmt1->width, fmt2->width);
+		return FMT_MISMATCH_WIDTH;
+	}
+
+	if (fmt1->height != fmt2->height) {
+		printf("height mismatch (%d %d)\n", fmt1->height, fmt2->height);
+		return FMT_MISMATCH_HEIGHT;
+	}
+
+	if (fmt1->code != fmt2->code) {
+		printf("mbus code mismatch (%s %s)\n",
+			v4l2_subdev_pixelcode_to_string(fmt1->code),
+			v4l2_subdev_pixelcode_to_string(fmt2->code));
+		return FMT_MISMATCH_CODE;
+	}
+
+	if (fmt1->field != fmt2->field) {
+		printf("field mismatch (%d %d)\n", fmt1->field, fmt2->field);
+		return FMT_MISMATCH_FIELD;
+	}
+
+	if (fmt1->colorspace != fmt2->colorspace) {
+		printf("colorspace mismatch (%s %s)\n",
+			v4l2_subdev_colorspace_to_string(fmt1->colorspace),
+			v4l2_subdev_colorspace_to_string(fmt2->colorspace));
+		return FMT_MISMATCH_COLORSPACE;
+	}
+
+	return FMT_MISMATCH_NONE;
+}
+
 bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
 				  struct media_entity *entity,
 				  int ctrl_id)
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index 7d9e53a..3732755 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -29,6 +29,15 @@ struct media_device;
 struct media_entity;
 struct media_device;
 
+enum v4l2_subdev_fmt_mismatch {
+	FMT_MISMATCH_NONE = 0,
+	FMT_MISMATCH_WIDTH,
+	FMT_MISMATCH_HEIGHT,
+	FMT_MISMATCH_CODE,
+	FMT_MISMATCH_FIELD,
+	FMT_MISMATCH_COLORSPACE,
+};
+
 struct v4l2_subdev {
 	int fd;
 
@@ -345,6 +354,19 @@ int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
 				   struct media_entity *entity,
 				   __u32 ctrl_id);
 /**
+ * @brief Compare mbus formats
+ * @param fmt1 - 1st mbus format to compare.
+ * @param fmt2 - 2nd mbus format to compare.
+ *
+ * Check whether two mbus formats are compatible.
+ *
+ * @return 1 if formats are compatible, 0 otherwise.
+ */
+enum v4l2_subdev_fmt_mismatch v4l2_subdev_format_compare(
+				struct v4l2_mbus_framefmt *fmt1,
+				struct v4l2_mbus_framefmt *fmt2);
+
+/**
  * @brief Check if there was a v4l2_control redirection defined for the entity
  * @param media - media device.
  * @param entity - subdev-device media entity.
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 11/15] mediactl: libv4l2subdev: add support for setting pipeline format
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (9 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 10/15] mediactl: libv4l2subdev: add support for comparing mbus formats Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 12/15] mediactl: libv4l2subdev: add get_pipeline_entity_by_cid function Jacek Anaszewski
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

This patch adds a function for setting the media device pipeline format.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |   63 +++++++++++++++++++++++++++++++++++++++
 utils/media-ctl/v4l2subdev.h    |   15 ++++++++++
 2 files changed, 78 insertions(+)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 3282fe9..9d48ac1 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -165,6 +165,69 @@ int v4l2_subdev_set_format(struct media_entity *entity,
 	return 0;
 }
 
+int v4l2_subdev_apply_pipeline_fmt(struct media_device *media,
+				   struct v4l2_format *fmt)
+{
+	struct v4l2_mbus_framefmt mbus_fmt = { 0 };
+	struct media_entity *entity = media->pipeline;
+	struct media_pad *pad;
+	int ret;
+
+	while (entity) {
+		/*
+		 * Source entity is linked only through a source pad
+		 * and this pad should be used for setting the format.
+		 * For other entities set the format on a sink pad.
+		 */
+		pad = entity->pipe_sink_pad ? entity->pipe_sink_pad :
+					      entity->pipe_src_pad;
+		if (pad == NULL)
+			return -EINVAL;
+
+		ret = v4l2_subdev_get_format(entity, &mbus_fmt, pad->index,
+					     V4L2_SUBDEV_FORMAT_TRY);
+
+		if (ret < 0)
+			return ret;
+
+		media_dbg(media, "VIDIOC_SUBDEV_G_FMT %s:%d: mcode: %s, cs: %s, w: %d, h: %d\n",
+			  media_entity_get_name(entity), pad->index,
+			  v4l2_subdev_pixelcode_to_string(mbus_fmt.code),
+			  v4l2_subdev_colorspace_to_string(mbus_fmt.colorspace),
+			  mbus_fmt.width, mbus_fmt.height);
+
+		ret = v4l2_subdev_set_format(entity, &mbus_fmt, pad->index,
+					     V4L2_SUBDEV_FORMAT_ACTIVE);
+		if (ret < 0)
+			return ret;
+
+		media_dbg(media, "VIDIOC_SUBDEV_S_FMT %s:%d: mcode: %s, cs: %s, w: %d, h: %d\n",
+			  media_entity_get_name(entity), pad->index,
+			  v4l2_subdev_pixelcode_to_string(mbus_fmt.code),
+			  v4l2_subdev_colorspace_to_string(mbus_fmt.colorspace),
+			  mbus_fmt.width, mbus_fmt.height);
+
+		entity = entity->next;
+
+		/* Last entity in the pipeline is not a sub-device */
+		if (entity->next == NULL)
+			break;
+	}
+
+	/*
+	 * Sink entity represents a video device node and is not
+	 * a sub-device. Nonetheless because it has associated
+	 * file descriptor and can expose v4l2-controls the
+	 * v4l2-subdev structure is used for caching the
+	 * related data.
+	 */
+	ret = ioctl(entity->sd->fd, VIDIOC_S_FMT, fmt);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 int v4l2_subdev_get_selection(struct media_entity *entity,
 	struct v4l2_rect *rect, unsigned int pad, unsigned int target,
 	enum v4l2_subdev_format_whence which)
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index 3732755..be2d82e 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -141,6 +141,21 @@ int v4l2_subdev_set_format(struct media_entity *entity,
 	enum v4l2_subdev_format_whence which);
 
 /**
+ * @brief Set media device pipeline format
+ * @param media - media device.
+ * @param fmt - negotiated format.
+ *
+ * Set the active format on all the media device pipeline entities.
+ * The format has to be at first negotiated with VIDIOC_SUBDEV_S_FMT
+ * by struct v4l2_subdev_format's 'whence' property set to
+ * V4L2_SUBDEV_FORMAT_TRY.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_apply_pipeline_fmt(struct media_device *media,
+				   struct v4l2_format *fmt);
+
+/**
  * @brief Retrieve a selection rectangle on a pad.
  * @param entity - subdev-device media entity.
  * @param r - rectangle to be filled.
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 12/15] mediactl: libv4l2subdev: add get_pipeline_entity_by_cid function
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (10 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 11/15] mediactl: libv4l2subdev: add support for setting pipeline format Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 13/15] mediactl: Add media device ioctl API Jacek Anaszewski
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add a function for obtaining the v4l2 sub-device for which
the v4l2 control related ioctl is predestined.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |   14 ++++++++++++++
 utils/media-ctl/v4l2subdev.h    |   15 +++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 9d48ac1..14e9423 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -1052,3 +1052,17 @@ bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
 
 	return false;
 }
+
+struct media_entity *v4l2_subdev_get_pipeline_entity_by_cid(struct media_device *media,
+						int cid)
+{
+	struct media_entity *entity = media->pipeline;
+
+	while (entity) {
+		if (v4l2_subdev_has_v4l2_control_redir(media, entity, cid))
+			return entity;
+		entity = entity->next;
+	}
+
+	return NULL;
+}
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index be2d82e..607ec50 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -394,4 +394,19 @@ enum v4l2_subdev_fmt_mismatch v4l2_subdev_format_compare(
 bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
 	struct media_entity *entity, int ctrl_id);
 
+/**
+ * @brief Get the first pipeline entity supporting the control
+ * @param media - media device.
+ * @param cid - v4l2 control identifier.
+ *
+ * Get the first entity in the media device pipeline,
+ * for which v4l2_control with cid is to be redirected
+ *
+ * @return associated entity if defined, or NULL if the
+ *	   control redirection wasn't defined for any entity
+ *	   in the pipeline
+ */
+struct media_entity *v4l2_subdev_get_pipeline_entity_by_cid(
+	struct media_device *media, int cid);
+
 #endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 13/15] mediactl: Add media device ioctl API
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (11 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 12/15] mediactl: libv4l2subdev: add get_pipeline_entity_by_cid function Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-02-15 12:41   ` Sakari Ailus
  2016-01-18 16:17 ` [PATCH 14/15] mediactl: libv4l2subdev: Enable opening/closing pipelines Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 15/15] Add a libv4l plugin for Exynos4 camera Jacek Anaszewski
  14 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Ioctls executed on complex media devices need special handling.
For instance some ioctls need to be targeted for specific sub-devices,
depending on the media device configuration. The APIs being introduced
address such requirements.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/Makefile.am          |    2 +-
 utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
 utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
 3 files changed, 453 insertions(+), 1 deletion(-)
 create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
 create mode 100644 utils/media-ctl/libv4l2media_ioctl.h

diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
index 3e883e0..7f18624 100644
--- a/utils/media-ctl/Makefile.am
+++ b/utils/media-ctl/Makefile.am
@@ -1,6 +1,6 @@
 noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
 
-libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
+libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
 libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
 libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
 
diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
new file mode 100644
index 0000000..b186121
--- /dev/null
+++ b/utils/media-ctl/libv4l2media_ioctl.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <linux/videodev2.h>
+
+#include "libv4l2media_ioctl.h"
+#include "mediactl-priv.h"
+#include "mediactl.h"
+#include "v4l2subdev.h"
+
+#define VIDIOC_CTRL(type)					\
+	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
+				   "VIDIOC_G_CTRL")
+
+#define VIDIOC_EXT_CTRL(type)					\
+	((type) == VIDIOC_S_EXT_CTRLS ? 			\
+		"VIDIOC_S_EXT_CTRLS"	:			\
+		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
+				    "VIDIOC_G_EXT_CTRLS" :	\
+				    "VIDIOC_TRY_EXT_CTRLS"))
+
+#define SYS_IOCTL(fd, cmd, arg) \
+	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+
+
+int media_ioctl_ctrl(struct media_device *media, int request,
+		     struct v4l2_control *arg)
+{
+	struct media_entity *entity = media->pipeline;
+	struct v4l2_control ctrl = *arg;
+	struct v4l2_queryctrl queryctrl;
+	bool ctrl_found = 0;
+	int ret;
+
+	/*
+	 * The control has to be reset to the default value
+	 * on all of the pipeline entities, prior setting a new
+	 * value. This is required in cases when the control config
+	 * is changed between subsequent calls to VIDIOC_S_CTRL,
+	 * to avoid the situation when a control is set on more
+	 * than one sub-device.
+	 */
+	if (request == VIDIOC_S_CTRL) {
+		while (entity) {
+			queryctrl.id = ctrl.id;
+
+			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYCTRL,
+					&queryctrl);
+			if (ret < 0) {
+				entity = entity->next;
+				continue;
+			}
+
+			ctrl_found = true;
+
+			if (queryctrl.type & V4L2_CTRL_TYPE_BUTTON)
+				break;
+
+			ctrl.value = queryctrl.default_value;
+			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_S_CTRL, &ctrl);
+			if (ret < 0)
+				return -EINVAL;
+
+			entity = entity->next;
+		}
+
+		ctrl.value = arg->value;
+	}
+
+	if (!ctrl_found) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, ctrl.id);
+
+	if (entity) {
+		ret = SYS_IOCTL(entity->sd->fd, request, &ctrl);
+	} else {
+		/* Walk the pipeline until the request succeeds */
+		entity = media->pipeline;
+
+		ret = -ENOENT;
+
+		while (entity) {
+			ret = SYS_IOCTL(entity->sd->fd, request, &ctrl);
+			if (!ret)
+				break;
+
+			entity = entity->next;
+		}
+	}
+
+exit:
+	*arg = ctrl;
+
+	media_dbg(media, "%s [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
+		  VIDIOC_CTRL(request), ctrl.id, ret ? NULL : queryctrl.name,
+		  entity ? entity->info.name : NULL, ret);
+
+	return ret;
+}
+
+static int media_ioctl_single_ext_ctrl(struct media_device *media,
+				int request, struct v4l2_ext_controls *arg)
+{
+	struct media_entity *entity = media->pipeline;
+	struct v4l2_ext_controls ctrls = *arg;
+	struct v4l2_ext_control *ctrl;
+	struct v4l2_query_ext_ctrl queryctrl;
+	bool ctrl_found = 0;
+	int ret = -EINVAL;
+
+	ctrl = &ctrls.controls[0];
+
+	/*
+	 * The control has to be reset to the default value
+	 * on all of the pipeline entities, prior setting a new
+	 * value. This is required in cases when the control config
+	 * is changed between subsequent calls to VIDIOC_S_EXT_CTRLS,
+	 * to avoid the situation when a control is set on more
+	 * than one sub-device.
+	 */
+	if (request == VIDIOC_S_EXT_CTRLS) {
+		while (entity) {
+			queryctrl.id = ctrl->id;
+
+			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERY_EXT_CTRL,
+					&queryctrl);
+			if (ret < 0) {
+				entity = entity->next;
+				continue;
+			}
+
+			ctrl_found = true;
+
+			if (queryctrl.type & V4L2_CTRL_TYPE_BUTTON)
+				break;
+
+			ctrl->value64 = queryctrl.default_value;
+
+			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_S_EXT_CTRLS,
+					&ctrls);
+			if (ret < 0)
+				return -EINVAL;
+
+			entity = entity->next;
+		}
+
+		ctrl->value64 = arg->controls[0].value64;
+	}
+
+	if (!ctrl_found) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, ctrl->id);
+
+	if (entity) {
+		ret = SYS_IOCTL(entity->sd->fd, request, &ctrls);
+	} else {
+		/* Walk the pipeline until the request succeeds */
+		entity = media->pipeline;
+
+		while (entity) {
+			ret = SYS_IOCTL(entity->sd->fd, request, &ctrls);
+			if (!ret)
+				break;
+
+			entity = entity->next;
+		}
+	}
+
+exit:
+	*arg = ctrls;
+
+	media_dbg(media, "%s [id: 0x%8.8x, entity: %s] (%d)\n",
+		  VIDIOC_EXT_CTRL(request), ctrl->id,
+		  entity ? entity->info.name : NULL, ret);
+
+	return ret;
+}
+
+int media_ioctl_ext_ctrl(struct media_device *media, int request,
+			 struct v4l2_ext_controls *arg)
+{
+	struct v4l2_ext_controls out_ctrls = *arg, ctrls = *arg;
+	int ret = -EINVAL, i;
+
+	ctrls.count = 1;
+
+	/*
+	 * Split cluster to individual ioctl calls for each control
+	 * from the array, to make possible redirection of every
+	 * single control to different sub-device, according to the
+	 * configuration settings.
+	 */
+	for (i = 0; i < arg->count; ++i) {
+		ctrls.controls = &arg->controls[i];
+
+		ret = media_ioctl_single_ext_ctrl(media, request, &ctrls);
+		out_ctrls.controls[i] = ctrls.controls[i];
+		if (ret < 0) {
+			if (ctrls.error_idx == 1)
+				out_ctrls.error_idx = ctrls.count;
+			else
+				out_ctrls.error_idx = i;
+			break;
+		}
+	}
+
+	*arg = out_ctrls;
+	return ret;
+}
+
+int sort_ctrls(const void * a, const void * b)
+{
+	const struct media_entity_to_cid *ctrl_a = a, *ctrl_b = b;
+
+	return ctrl_a->queryctrl.id - ctrl_b->queryctrl.id;
+}
+
+int media_ioctl_queryctrl(struct media_device *media,
+			  struct v4l2_queryctrl *arg)
+{
+	struct media_entity *entity = media->pipeline, *target_entity;
+	struct v4l2_queryctrl queryctrl = *arg;
+	int ret = -EINVAL, num_ctrls = 0;
+	struct media_entity_to_cid *ctrls_found;
+
+	/*
+	 * If id is or'ed with V4L2_CTRL_FLAG_NEXT_CTRL then the control to
+	 * be found is the one with the next lowest id among all entities
+	 * in the pipeline.
+	 */
+	if (queryctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+		ctrls_found = malloc(sizeof(*ctrls_found));
+
+		while (entity) {
+			queryctrl = *arg;
+
+			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYCTRL,
+					&queryctrl);
+			if (!ret) {
+				ctrls_found = realloc(ctrls_found,
+					sizeof(*ctrls_found) * (num_ctrls + 1));
+				ctrls_found[num_ctrls].queryctrl = queryctrl;
+				ctrls_found[num_ctrls].entity = entity;
+				++num_ctrls;
+			}
+
+			entity = entity->next;
+		}
+
+		if (num_ctrls == 0) {
+			ret = -EINVAL;
+			entity = NULL;
+			goto done;
+		}
+
+		qsort(ctrls_found, num_ctrls, sizeof(*ctrls_found), sort_ctrls);
+
+		queryctrl = ctrls_found[0].queryctrl;
+		target_entity = ctrls_found[0].entity;
+
+		free(ctrls_found);
+	}
+
+	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, queryctrl.id);
+	if (entity)
+		target_entity = entity;
+
+	ret = SYS_IOCTL(target_entity->sd->fd, VIDIOC_QUERYCTRL,
+				&queryctrl);
+
+done:
+	media_dbg(media,
+		  "VIDIOC_QUERYCTRL [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
+		  ret ? arg->id : queryctrl.id, ret ? NULL : queryctrl.name,
+		  target_entity ? target_entity->info.name : NULL, ret);
+
+	*arg = queryctrl;
+
+	return ret;
+}
+
+int media_ioctl_query_ext_ctrl(struct media_device *media,
+			       struct v4l2_query_ext_ctrl *arg)
+{
+	struct media_entity *entity = media->pipeline, *target_entity;
+	struct v4l2_query_ext_ctrl query_ext_ctrl = *arg;
+	int ret = -EINVAL, num_ctrls = 0;
+	struct media_entity_to_cid *ctrls_found;
+
+	/*
+	 * If id is or'ed with V4L2_CTRL_FLAG_NEXT_CTRL then the control to
+	 * be found is the one with the next lowest id among all entities
+	 * in the pipeline.
+	 */
+	if (query_ext_ctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+		ctrls_found = malloc(sizeof(*ctrls_found));
+
+		while (entity) {
+			query_ext_ctrl = *arg;
+
+			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERY_EXT_CTRL,
+					&query_ext_ctrl.id);
+			if (!ret) {
+				ctrls_found = realloc(ctrls_found,
+					sizeof(*ctrls_found) * (num_ctrls + 1));
+				ctrls_found[num_ctrls].query_ext_ctrl =
+								query_ext_ctrl;
+				ctrls_found[num_ctrls].entity = entity;
+				++num_ctrls;
+			}
+
+			entity = entity->next;
+		}
+
+		if (num_ctrls == 0) {
+			ret = -EINVAL;
+			entity = NULL;
+			goto done;
+		}
+
+		qsort(ctrls_found, num_ctrls, sizeof(*ctrls_found), sort_ctrls);
+
+		query_ext_ctrl = ctrls_found[0].query_ext_ctrl;
+		target_entity = ctrls_found[0].entity;
+
+		free(ctrls_found);
+	}
+
+	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, query_ext_ctrl.id);
+	if (entity)
+		target_entity = entity;
+
+	ret = SYS_IOCTL(target_entity->sd->fd, VIDIOC_QUERYCTRL,
+				&query_ext_ctrl);
+
+done:
+	media_dbg(media,
+		  "VIDIOC_QUERY_EXT_CTRL [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
+		  ret ? arg->id : query_ext_ctrl.id,
+		  ret ? NULL : query_ext_ctrl.name,
+		  target_entity ? target_entity->info.name : NULL, ret);
+
+	*arg = query_ext_ctrl;
+
+	return ret;
+}
+
+int media_ioctl_querymenu(struct media_device *media,
+			  struct v4l2_querymenu *arg)
+{
+	struct media_entity *entity = media->pipeline;
+	struct v4l2_querymenu querymenu = *arg;
+	int ret = -EINVAL;
+
+	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, querymenu.id);
+	if (entity) {
+		ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYMENU, &querymenu);
+		goto exit;
+	}
+
+	entity = media->pipeline;
+
+	while (entity) {
+		ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYMENU, &querymenu);
+		if (!ret)
+			break;
+
+		entity = entity->next;
+	}
+
+exit:
+	*arg = querymenu;
+
+	media_dbg(media, "VIDIOC_QUERYMENU [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
+		  querymenu.id, ret ? NULL : querymenu.name,
+		  entity ? entity->info.name : NULL, ret);
+
+	return ret;
+}
diff --git a/utils/media-ctl/libv4l2media_ioctl.h b/utils/media-ctl/libv4l2media_ioctl.h
new file mode 100644
index 0000000..5501895
--- /dev/null
+++ b/utils/media-ctl/libv4l2media_ioctl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIBV4L2MEDIA_IOCTL_H
+#define __LIBV4L2MEDIA_IOCTL_H
+
+#include <linux/videodev2.h>
+
+struct media_device;
+
+struct media_entity_to_cid {
+	struct media_entity *entity;
+	union {
+		struct v4l2_queryctrl queryctrl;
+		struct v4l2_query_ext_ctrl query_ext_ctrl;
+	};
+};
+
+int media_ioctl_ctrl(struct media_device *media, int request,
+			struct v4l2_control *arg);
+
+int media_ioctl_ext_ctrl(struct media_device *media, int request,
+			struct v4l2_ext_controls *arg);
+
+int media_ioctl_queryctrl(struct media_device *media,
+			struct v4l2_queryctrl *arg);
+
+int media_ioctl_query_ext_ctrl(struct media_device *media,
+			struct v4l2_query_ext_ctrl *arg);
+
+int media_ioctl_querymenu(struct media_device *media,
+			struct v4l2_querymenu *arg);
+
+#endif /* __LIBV4L2MEDIA_IOCTL_H */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 14/15] mediactl: libv4l2subdev: Enable opening/closing pipelines
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (12 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 13/15] mediactl: Add media device ioctl API Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  2016-01-18 16:17 ` [PATCH 15/15] Add a libv4l plugin for Exynos4 camera Jacek Anaszewski
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

Add functions for opening and closing media entity pipelines
at one go.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 utils/media-ctl/libv4l2subdev.c |   60 +++++++++++++++++++++++++++++++++++++++
 utils/media-ctl/v4l2subdev.h    |   18 ++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 14e9423..6e626fe 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -118,6 +118,66 @@ void v4l2_subdev_close(struct media_entity *entity)
 	entity->sd->fd = -1;
 }
 
+int v4l2_subdev_open_pipeline(struct media_device *media)
+{
+	struct media_entity *entity = media->pipeline;
+	int ret;
+
+	if (entity == NULL)
+		return 0;
+
+	/*
+	 * Stop walking the pipeline on the last last but one entity, because
+	 * the sink entity sub-device was opened by libv4l2 core and its
+	 * file descriptor needs to be preserved.
+	 */
+	while (entity->next) {
+		media_dbg(media, "Opening sub-device: %s\n", entity->devname);
+		ret = v4l2_subdev_open(entity);
+		if (ret < 0)
+			return ret;
+
+		if (entity->sd->fd < 0)
+			goto err_open_subdev;
+
+		entity = entity->next;
+	}
+
+	return 0;
+
+err_open_subdev:
+	v4l2_subdev_release_pipeline(media);
+
+	return -EINVAL;
+}
+
+void v4l2_subdev_release_pipeline(struct media_device *media)
+{
+	struct media_entity *entity = media->pipeline;
+
+	if (entity == NULL)
+		return;
+	/*
+	 * Stop walking the pipeline on the last last but one entity, because
+	 * the sink entity sub-device should be released by the client that
+	 * instantiated it.
+	 */
+	while (entity->next) {
+		if (!entity->sd) {
+			entity = entity->next;
+			continue;
+		}
+
+		if (entity->sd->fd >= 0) {
+			media_dbg(media, "Releasing sub-device: %s\n", entity->devname);
+			v4l2_subdev_release(entity, true);
+		}
+
+		entity = entity->next;
+	}
+}
+
+
 int v4l2_subdev_get_format(struct media_entity *entity,
 	struct v4l2_mbus_framefmt *format, unsigned int pad,
 	enum v4l2_subdev_format_whence which)
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index 607ec50..94f6bf1 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -100,6 +100,24 @@ int v4l2_subdev_open(struct media_entity *entity);
 void v4l2_subdev_close(struct media_entity *entity);
 
 /**
+ * @brief Open media device pipeline
+ * @param media - media device.
+ *
+ * Open all sub-devices in the media device pipeline.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_open_pipeline(struct media_device *media);
+
+/**
+ * @brief Release media device pipeline sub-devices
+ * @param media - media device.
+ *
+ * Release all sub-devices in the media device pipeline.
+ */
+void v4l2_subdev_release_pipeline(struct media_device *media);
+
+/**
  * @brief Retrieve the format on a pad.
  * @param entity - subdev-device media entity.
  * @param format - format to be filled.
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 15/15] Add a libv4l plugin for Exynos4 camera
  2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
                   ` (13 preceding siblings ...)
  2016-01-18 16:17 ` [PATCH 14/15] mediactl: libv4l2subdev: Enable opening/closing pipelines Jacek Anaszewski
@ 2016-01-18 16:17 ` Jacek Anaszewski
  14 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-01-18 16:17 UTC (permalink / raw)
  To: linux-media
  Cc: sakari.ailus, laurent.pinchart, gjasny, hdegoede, hverkuil,
	Jacek Anaszewski

The plugin provides support for the media device on Exynos4 SoC.
It performs single plane <-> multi plane API conversion,
video pipeline linking and takes care of automatic data format
negotiation for the whole pipeline, after intercepting
VIDIOC_S_FMT or VIDIOC_TRY_FMT ioctls.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 configure.ac                                      |    1 +
 lib/Makefile.am                                   |    5 +
 lib/libv4l-exynos4-camera/Makefile.am             |    7 +
 lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c |  620 +++++++++++++++++++++
 4 files changed, 633 insertions(+)
 create mode 100644 lib/libv4l-exynos4-camera/Makefile.am
 create mode 100644 lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c

diff --git a/configure.ac b/configure.ac
index 1b61f15..afc9e86 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,7 @@ AC_CONFIG_FILES([Makefile
 	lib/libdvbv5/Makefile
 	lib/libv4l2rds/Makefile
 	lib/libv4l-mplane/Makefile
+	lib/libv4l-exynos4-camera/Makefile
 
 	utils/Makefile
 	utils/libv4l2util/Makefile
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 351c7d3..1576d06 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -5,6 +5,11 @@ SUBDIRS = \
 	libv4l2rds \
 	libv4l-mplane
 
+if WITH_V4LUTILS
+SUBDIRS += \
+	libv4l-exynos4-camera
+endif
+
 if LINUX_OS
 SUBDIRS += \
 	libdvbv5
diff --git a/lib/libv4l-exynos4-camera/Makefile.am b/lib/libv4l-exynos4-camera/Makefile.am
new file mode 100644
index 0000000..23c60c6
--- /dev/null
+++ b/lib/libv4l-exynos4-camera/Makefile.am
@@ -0,0 +1,7 @@
+if WITH_V4L_PLUGINS
+libv4l2plugin_LTLIBRARIES = libv4l-exynos4-camera.la
+endif
+
+libv4l_exynos4_camera_la_SOURCES = libv4l-exynos4-camera.c ../../utils/media-ctl/libmediactl.c ../../utils/media-ctl/libv4l2subdev.c ../../utils/media-ctl/libv4l2media_ioctl.c ../../utils/media-ctl/mediatext.c
+libv4l_exynos4_camera_la_CFLAGS = -fvisibility=hidden -std=gnu99
+libv4l_exynos4_camera_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lpthread
diff --git a/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c b/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
new file mode 100644
index 0000000..12ebda7
--- /dev/null
+++ b/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <linux/types.h>
+
+#include "../../utils/media-ctl/libv4l2media_ioctl.h"
+#include "../../utils/media-ctl/mediactl.h"
+#include "../../utils/media-ctl/mediatext.h"
+#include "../../utils/media-ctl/v4l2subdev.h"
+#include "libv4l-plugin.h"
+
+struct media_device;
+struct media_entity;
+
+/*
+ * struct exynos4_camera_plugin - libv4l exynos4 camera plugin
+ * @media:		media device comprising the vid_fd related video device
+ */
+struct exynos4_camera_plugin {
+	struct media_device *media;
+	struct media_entity *sink_entity;
+};
+
+#ifdef DEBUG
+#define V4L2_EXYNOS4_DBG(format, ARG...)\
+	printf("[%s:%d] [%s] " format " \n", __FILE__, __LINE__, __func__, ##ARG)
+#else
+#define V4L2_EXYNOS4_DBG(format, ARG...)
+#endif
+
+#define V4L2_EXYNOS4_ERR(format, ARG...)\
+	fprintf(stderr, "Libv4l Exynos4 camera plugin: "format "\n", ##ARG)
+
+#define V4L2_EXYNOS4_LOG(format, ARG...)\
+	fprintf(stdout, "Libv4l Exynos4 camera plugin: "format "\n", ##ARG)
+
+#if HAVE_VISIBILITY
+#define PLUGIN_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define PLUGIN_PUBLIC
+#endif
+
+#define SYS_IOCTL(fd, cmd, arg) \
+	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+
+#define SIMPLE_CONVERT_IOCTL(fd, cmd, arg, __struc) ({  \
+	int __ret;                                      \
+	struct __struc *req = arg;                      \
+	uint32_t type = req->type;                      \
+	req->type = convert_type(type);                 \
+	__ret = SYS_IOCTL(fd, cmd, arg);                \
+	req->type = type;                               \
+	__ret;                                          \
+	})
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+
+#define EXYNOS4_FIMC_DRV	"exynos4-fimc"
+#define EXYNOS4_FIMC_LITE_DRV	"exynos-fimc-lit"
+#define EXYNOS4_FIMC_IS_ISP_DRV	"exynos4-fimc-is"
+#define ENTITY_CAPTURE_SEGMENT	"capture"
+#define EXYNOS4_CAPTURE_CONF	"/var/lib/libv4l/exynos4_capture_conf"
+#define EXYNOS4_FIMC_IS_ISP	"FIMC-IS-ISP"
+#define EXYNOS4_S5K6A3		"S5K6A3"
+#define EXYNOS4_FIMC_LITE	"FIMC-LITE."
+#define EXYNOS4_FIMC_PREFIX	"FIMC."
+#define MAX_FMT_NEGO_NUM	50
+
+
+static int __capture_entity(const char *name)
+{
+	int cap_segment_pos;
+
+	if (name == NULL)
+		return 0;
+
+	cap_segment_pos = strlen(name) - strlen(ENTITY_CAPTURE_SEGMENT);
+
+	if (strcmp(name + cap_segment_pos, ENTITY_CAPTURE_SEGMENT) == 0)
+		return 1;
+
+	return 0;
+}
+
+static int __adjust_format_to_fimc_is_isp(struct v4l2_mbus_framefmt *mbus_fmt)
+{
+	if (mbus_fmt == NULL)
+		return -EINVAL;
+
+	mbus_fmt->width = max(128, mbus_fmt->width);
+	mbus_fmt->height = max(128, mbus_fmt->height);
+
+	mbus_fmt->width += 16;
+	mbus_fmt->height += 12;
+
+	return 0;
+}
+
+static int negotiate_pipeline_fmt(struct media_entity *pipeline,
+				  struct v4l2_format *dev_fmt)
+{
+	struct media_entity *entity = pipeline;
+	struct v4l2_mbus_framefmt mbus_fmt = { 0 }, common_fmt;
+	int repeat_negotiation, cnt_negotiation = 0, ret, pad_id;
+	enum v4l2_subdev_fmt_mismatch fmt_err;
+
+	if (pipeline == NULL || dev_fmt == NULL)
+		return -EINVAL;
+
+	mbus_fmt.width = dev_fmt->fmt.pix_mp.width;
+	mbus_fmt.height = dev_fmt->fmt.pix_mp.height;
+	mbus_fmt.field = dev_fmt->fmt.pix_mp.field;
+	mbus_fmt.colorspace = dev_fmt->fmt.pix_mp.colorspace;
+
+	if (media_has_pipeline_entity(entity, EXYNOS4_FIMC_IS_ISP)) {
+		ret = __adjust_format_to_fimc_is_isp(&mbus_fmt);
+		if (ret < 0)
+			return ret;
+	}
+
+	V4L2_EXYNOS4_DBG("Begin pipeline format negotiation...");
+
+	for (;;) {
+		repeat_negotiation = 0;
+		entity = pipeline;
+
+		pad_id = media_entity_get_src_pad_index(entity);
+
+		V4L2_EXYNOS4_DBG("Setting format on the source entity pad %s:%d",
+				 media_entity_get_name(entity), pad_id);
+
+		ret = v4l2_subdev_set_format(entity, &mbus_fmt,
+					     pad_id, V4L2_SUBDEV_FORMAT_TRY);
+		if (ret < 0)
+			return ret;
+
+		V4L2_EXYNOS4_DBG("Format set on the pad %s:%d: mcode: %s, cs: %s, w: %d, h: %d",
+				 media_entity_get_name(entity), pad_id,
+				 v4l2_subdev_pixelcode_to_string(mbus_fmt.code),
+				 v4l2_subdev_colorspace_to_string(mbus_fmt.colorspace),
+				 mbus_fmt.width, mbus_fmt.height);
+
+		common_fmt = mbus_fmt;
+
+		entity = media_entity_get_next(entity);
+
+		while (entity) {
+			pad_id = media_entity_get_sink_pad_index(entity);
+
+			/* Set format on the entity sink pad */
+			V4L2_EXYNOS4_DBG("Setting format on the pad %s:%d: mcode: %s, cs: %s, w: %d, h: %d",
+					 media_entity_get_name(entity), pad_id,
+					 v4l2_subdev_pixelcode_to_string(mbus_fmt.code),
+					 v4l2_subdev_colorspace_to_string(mbus_fmt.colorspace),
+					 mbus_fmt.width, mbus_fmt.height);
+
+			ret = v4l2_subdev_set_format(entity, &mbus_fmt, pad_id,
+							V4L2_SUBDEV_FORMAT_TRY);
+			if (ret < 0)
+				return ret;
+
+			fmt_err = v4l2_subdev_format_compare(&mbus_fmt, &common_fmt);
+			if (fmt_err) {
+				if (fmt_err == FMT_MISMATCH_WIDTH &&
+				     !strncmp(media_entity_get_name(entity),
+					      EXYNOS4_FIMC_LITE,
+					      strlen(EXYNOS4_FIMC_LITE))) {
+					/*
+					 * Align width downwards, according to the FIMC-LITE
+					 * width step. Otherwise pipeline format negotiation
+					 * wouldn't succeed for widths excessing maximum sensor
+					 * frame width, which is being probed by GStreamer,
+					 * no matter what actual frame size is to be set.
+					 */
+					mbus_fmt.width -= 8;
+				}
+				repeat_negotiation = 1;
+				break;
+			}
+
+			/*
+			 * Do not check format on FIMC.[n] source pad
+			 * and stop negotiation.
+			 */
+			if (!strncmp(media_entity_get_name(entity),
+				     EXYNOS4_FIMC_PREFIX,
+				     strlen(EXYNOS4_FIMC_PREFIX)))
+				break;
+
+			pad_id = media_entity_get_src_pad_index(entity);
+
+			/* Get format on the entity src pad */
+			ret = v4l2_subdev_get_format(entity, &mbus_fmt, pad_id,
+							V4L2_SUBDEV_FORMAT_TRY);
+			if (ret < 0)
+				return -EINVAL;
+
+			V4L2_EXYNOS4_DBG("Format propagated to the pad %s:%d: mcode: %s, cs: %s, w: %d, h: %d",
+					 media_entity_get_name(entity), pad_id,
+					 v4l2_subdev_pixelcode_to_string(mbus_fmt.code),
+					 v4l2_subdev_colorspace_to_string(mbus_fmt.colorspace),
+					 mbus_fmt.width, mbus_fmt.height);
+
+			if (!strcmp(media_entity_get_name(entity),
+				    EXYNOS4_FIMC_IS_ISP)) {
+				common_fmt.code = mbus_fmt.code;
+				common_fmt.colorspace = mbus_fmt.colorspace;
+				common_fmt.width -= 16;
+				common_fmt.height -= 12;
+			}
+
+			if (v4l2_subdev_format_compare(&mbus_fmt, &common_fmt)) {
+				repeat_negotiation = 1;
+				break;
+			}
+
+			entity = media_entity_get_next(entity);
+
+			/*
+			 * Stop if this is last element in the
+			 * pipeline as it is not a sub-device.
+			 */
+			if (media_entity_get_next(entity) == NULL)
+				break;
+		}
+
+		if (!repeat_negotiation) {
+			break;
+		} else if (++cnt_negotiation > MAX_FMT_NEGO_NUM) {
+			V4L2_EXYNOS4_DBG("Pipeline format negotiation failed!");
+			return -EINVAL;
+		}
+	}
+
+	dev_fmt->fmt.pix_mp.width = mbus_fmt.width;
+	dev_fmt->fmt.pix_mp.height = mbus_fmt.height;
+	dev_fmt->fmt.pix_mp.field = mbus_fmt.field;
+	dev_fmt->fmt.pix_mp.colorspace = mbus_fmt.colorspace;
+
+	V4L2_EXYNOS4_DBG("Pipeline format successfuly negotiated");
+
+	return 0;
+}
+
+static __u32 convert_type(__u32 type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	default:
+		return type;
+	}
+}
+
+static int set_fmt_ioctl(struct media_device *media,
+			 unsigned long int cmd,
+			 struct v4l2_format *arg,
+			 enum v4l2_subdev_format_whence set_mode)
+{
+	struct v4l2_format fmt = { 0 };
+	int ret;
+
+	fmt.type = convert_type(arg->type);
+	if (fmt.type != arg->type) {
+		fmt.fmt.pix_mp.width = arg->fmt.pix.width;
+		fmt.fmt.pix_mp.height = arg->fmt.pix.height;
+		fmt.fmt.pix_mp.pixelformat = arg->fmt.pix.pixelformat;
+		fmt.fmt.pix_mp.field = arg->fmt.pix.field;
+		fmt.fmt.pix_mp.colorspace = arg->fmt.pix.colorspace;
+		fmt.fmt.pix_mp.num_planes = 1;
+		fmt.fmt.pix_mp.flags = arg->fmt.pix.flags;
+		fmt.fmt.pix_mp.plane_fmt[0].bytesperline = arg->fmt.pix.bytesperline;
+		fmt.fmt.pix_mp.plane_fmt[0].sizeimage = arg->fmt.pix.sizeimage;
+	} else {
+		fmt = *arg;
+	}
+
+	ret = negotiate_pipeline_fmt(media_get_pipeline(media), &fmt);
+	if (ret < 0)
+		return ret;
+
+	if (set_mode == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ret = v4l2_subdev_apply_pipeline_fmt(media, &fmt);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (fmt.type != arg->type) {
+		arg->fmt.pix.width = fmt.fmt.pix_mp.width;
+		arg->fmt.pix.height = fmt.fmt.pix_mp.height;
+		arg->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat;
+		arg->fmt.pix.field = fmt.fmt.pix_mp.field;
+		arg->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace;
+		arg->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+		arg->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+		arg->fmt.pix.flags = fmt.fmt.pix_mp.flags;
+	} else {
+		*arg = fmt;
+	}
+
+	return 0;
+}
+
+static int get_fmt_ioctl(int fd,
+			 unsigned long int cmd,
+			 struct v4l2_format *arg)
+{
+	struct v4l2_format fmt = { 0 };
+	int ret;
+
+	fmt.type = convert_type(arg->type);
+
+	if (fmt.type == arg->type)
+		return SYS_IOCTL(fd, cmd, arg);
+
+	ret = SYS_IOCTL(fd, cmd, &fmt);
+	if (ret < 0)
+		return ret;
+
+	memset(&arg->fmt.pix, 0, sizeof(arg->fmt.pix));
+	arg->fmt.pix.width = fmt.fmt.pix_mp.width;
+	arg->fmt.pix.height = fmt.fmt.pix_mp.height;
+	arg->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat;
+	arg->fmt.pix.field = fmt.fmt.pix_mp.field;
+	arg->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace;
+	arg->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+	arg->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+	arg->fmt.pix.flags = fmt.fmt.pix_mp.flags;
+
+	return ret;
+}
+
+static int buf_ioctl(int fd,
+		     unsigned long int cmd,
+		     struct v4l2_buffer *arg)
+{
+	struct v4l2_buffer buf = *arg;
+	struct v4l2_plane plane = { 0 };
+	int ret;
+
+	buf.type = convert_type(arg->type);
+
+	if (buf.type == arg->type)
+		return SYS_IOCTL(fd, cmd, arg);
+
+	memcpy(&plane.m, &arg->m, sizeof(plane.m));
+	plane.length = arg->length;
+	plane.bytesused = arg->bytesused;
+
+	buf.m.planes = &plane;
+	buf.length = 1;
+
+	ret = SYS_IOCTL(fd, cmd, &buf);
+
+	arg->index = buf.index;
+	arg->memory = buf.memory;
+	arg->flags = buf.flags;
+	arg->field = buf.field;
+	arg->timestamp = buf.timestamp;
+	arg->timecode = buf.timecode;
+	arg->sequence = buf.sequence;
+
+	arg->length = plane.length;
+	arg->bytesused = plane.bytesused;
+	memcpy(&arg->m, &plane.m, sizeof(arg->m));
+
+	return ret;
+}
+
+static int querycap_ioctl(int fd, struct v4l2_capability *arg)
+{
+	int ret;
+
+	ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, arg);
+	if (ret < 0)
+		return ret;
+
+	arg->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+	arg->capabilities |= V4L2_CAP_VIDEO_CAPTURE;
+
+	return ret;
+}
+
+static void *plugin_init(int fd)
+{
+	struct v4l2_capability cap = { 0 };
+	struct exynos4_camera_plugin *plugin = NULL;
+	const char *sink_entity_name;
+	struct media_device *media;
+	struct media_entity *sink_entity;
+	char video_devname[32];
+	int ret;
+
+	ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
+	if (ret < 0) {
+		V4L2_EXYNOS4_ERR("Failed to query video capabilities.");
+		return NULL;
+	}
+
+	/* Check if this is Exynos4 media device */
+	if (strcmp((char *) cap.driver, EXYNOS4_FIMC_DRV) &&
+	    strcmp((char *) cap.driver, EXYNOS4_FIMC_LITE_DRV) &&
+	    strcmp((char *) cap.driver, EXYNOS4_FIMC_IS_ISP_DRV)) {
+		V4L2_EXYNOS4_ERR("Not an Exynos4 media device.");
+		return NULL;
+	}
+
+	/* Obtain the node name of the opened device */
+	ret = media_get_devname_by_fd(fd, video_devname);
+	if (ret < 0) {
+		V4L2_EXYNOS4_ERR("Failed to get video device node name.");
+		return NULL;
+	}
+
+	/*
+	 * Create the representation of a media device
+	 * containing the opened video device.
+	 */
+	media = media_device_new_by_entity_devname(video_devname);
+	if (media == NULL) {
+		V4L2_EXYNOS4_ERR("Failed to create media device.");
+		return NULL;
+	}
+
+#ifdef DEBUG
+	media_debug_set_handler(media, (void (*)(void *, ...))fprintf, stdout);
+#endif
+
+	/* Get the entity representing the opened video device node */
+	sink_entity = media_get_entity_by_devname(media, video_devname,
+						  strlen(video_devname));
+	if (sink_entity == NULL) {
+		V4L2_EXYNOS4_ERR("Failed to get sink entity name.");
+		goto err_get_sink_entity;
+	}
+
+	/*
+	 * Initialize sink_entity subdev fd with the one opened
+	 * by the libv4l core to avoid losing it on pipeline opening.
+	 */
+	v4l2_subdev_create_with_fd(sink_entity, fd);
+
+	sink_entity_name = media_entity_get_name(sink_entity);
+
+	/* Check if video entity is of capture type, not m2m */
+	if (!__capture_entity(sink_entity_name)) {
+		V4L2_EXYNOS4_ERR("Device not of capture type.");
+		goto err_get_sink_entity;
+	}
+
+	/* Parse media configuration file and apply its settings */
+	ret = mediatext_parse_setup_config(media, EXYNOS4_CAPTURE_CONF);
+	if (ret < 0) {
+		V4L2_EXYNOS4_ERR("Media config parser error.");
+		goto err_get_sink_entity;
+	}
+
+	/*
+	 * Discover the pipeline of sub-devices from a camera sensor
+	 * to the opened video device.
+	 */
+	ret = media_discover_pipeline_by_entity(media, sink_entity);
+	if (ret < 0) {
+		V4L2_EXYNOS4_ERR("Error discovering video pipeline.");
+		goto err_get_sink_entity;
+	}
+
+	/* Open all sub-devices in the discovered pipeline */
+	ret = v4l2_subdev_open_pipeline(media);
+	if (ret < 0) {
+		V4L2_EXYNOS4_ERR("Error opening video pipeline.");
+		goto err_get_sink_entity;
+	}
+
+	/* Allocate private data */
+	plugin = calloc(1, sizeof(*plugin));
+	if (!plugin)
+		goto err_validate_controls;
+
+	plugin->media = media;
+	plugin->sink_entity = sink_entity;
+
+	V4L2_EXYNOS4_LOG("Initialized exynos4-camera plugin.");
+
+	return plugin;
+
+err_validate_controls:
+	v4l2_subdev_release(sink_entity, false);
+	v4l2_subdev_release_pipeline(media);
+err_get_sink_entity:
+	if (media)
+		media_device_unref(media);
+	return NULL;
+}
+
+static void plugin_close(void *dev_ops_priv)
+{
+	struct exynos4_camera_plugin *plugin = dev_ops_priv;
+	struct media_device *media;
+
+	if (plugin == NULL)
+		return;
+
+	/* release sink entity sub-device, but don't close fd */
+	v4l2_subdev_release(plugin->sink_entity, false);
+
+	media = plugin->media;
+	v4l2_subdev_release_pipeline(media);
+	media_device_unref(media);
+
+	free(plugin);
+}
+
+static int plugin_ioctl(void *dev_ops_priv, int fd, unsigned long int cmd,
+							void *arg)
+{
+	struct exynos4_camera_plugin *plugin = dev_ops_priv;
+	struct media_device *media;
+
+	if (plugin == NULL || arg == NULL)
+		return -EINVAL;
+
+	media = plugin->media;
+
+	if (media == NULL)
+		return -EINVAL;
+
+	switch (cmd) {
+	case VIDIOC_S_CTRL:
+	case VIDIOC_G_CTRL:
+		return media_ioctl_ctrl(media, cmd, arg);
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+		return media_ioctl_ext_ctrl(media, cmd, arg);
+	case VIDIOC_QUERYCTRL:
+		return media_ioctl_queryctrl(media, arg);
+	case VIDIOC_QUERY_EXT_CTRL:
+		return media_ioctl_query_ext_ctrl(media, arg);
+	case VIDIOC_QUERYMENU:
+		return media_ioctl_querymenu(media, arg);
+	case VIDIOC_TRY_FMT:
+		return set_fmt_ioctl(media, cmd, arg,
+				     V4L2_SUBDEV_FORMAT_TRY);
+	case VIDIOC_S_FMT:
+		return set_fmt_ioctl(media, cmd, arg,
+				     V4L2_SUBDEV_FORMAT_ACTIVE);
+	case VIDIOC_G_FMT:
+		return get_fmt_ioctl(fd, cmd, arg);
+	case VIDIOC_QUERYCAP:
+		return querycap_ioctl(fd, arg);
+	case VIDIOC_QBUF:
+	case VIDIOC_DQBUF:
+	case VIDIOC_QUERYBUF:
+	case VIDIOC_PREPARE_BUF:
+		return buf_ioctl(fd, cmd, arg);
+	case VIDIOC_REQBUFS:
+		return SIMPLE_CONVERT_IOCTL(fd, cmd, arg,
+					    v4l2_requestbuffers);
+	case VIDIOC_ENUM_FMT:
+		return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_fmtdesc);
+	case VIDIOC_CROPCAP:
+		return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_cropcap);
+	case VIDIOC_STREAMON:
+	case VIDIOC_STREAMOFF:
+		{
+			int *arg_type = (int *) arg;
+			__u32 type;
+
+			type = convert_type(*arg_type);
+
+			if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+			    type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				V4L2_EXYNOS4_ERR("Invalid buffer type.");
+				return -EINVAL;
+			}
+
+			return SYS_IOCTL(fd, cmd, &type);
+		}
+
+	default:
+		return SYS_IOCTL(fd, cmd, arg);
+	}
+}
+
+PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
+	.init = &plugin_init,
+	.close = &plugin_close,
+	.ioctl = &plugin_ioctl,
+};
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH 01/15] mediactl: Introduce v4l2_subdev structure
  2016-01-18 16:17 ` [PATCH 01/15] mediactl: Introduce v4l2_subdev structure Jacek Anaszewski
@ 2016-02-12 12:42   ` Sakari Ailus
  2016-02-18 14:15     ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-12 12:42 UTC (permalink / raw)
  To: Jacek Anaszewski, linux-media
  Cc: laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

Thanks for continuing this work! And my apologies for reviewing only
now... please see the comments below.

Jacek Anaszewski wrote:
> Add struct v4l2_subdev - a representation of the v4l2 sub-device,
> related to the media entity. Add field 'sd', the pointer to
> the newly introduced structure, to the struct media_entity
> and move 'fd' property from struct media entity to struct v4l2_subdev.
> Avoid accessing sub-device file descriptor from libmediactl and
> make the v4l2_subdev_open capable of creating the v4l2_subdev
> if the 'sd' pointer is uninitialized.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/libmediactl.c   |    4 --
>  utils/media-ctl/libv4l2subdev.c |   82 +++++++++++++++++++++++++++++++--------
>  utils/media-ctl/mediactl-priv.h |    5 ++-
>  utils/media-ctl/v4l2subdev.h    |   38 ++++++++++++++++++
>  4 files changed, 107 insertions(+), 22 deletions(-)
> 
> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
> index 4a82d24..7e98440 100644
> --- a/utils/media-ctl/libmediactl.c
> +++ b/utils/media-ctl/libmediactl.c
> @@ -525,7 +525,6 @@ static int media_enum_entities(struct media_device *media)
>  
>  		entity = &media->entities[media->entities_count];
>  		memset(entity, 0, sizeof(*entity));
> -		entity->fd = -1;
>  		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
>  		entity->media = media;
>  
> @@ -719,8 +718,6 @@ void media_device_unref(struct media_device *media)
>  
>  		free(entity->pads);
>  		free(entity->links);
> -		if (entity->fd != -1)
> -			close(entity->fd);
>  	}
>  
>  	free(media->entities);
> @@ -747,7 +744,6 @@ int media_device_add_entity(struct media_device *media,
>  	entity = &media->entities[media->entities_count - 1];
>  	memset(entity, 0, sizeof *entity);
>  
> -	entity->fd = -1;
>  	entity->media = media;
>  	strncpy(entity->devname, devnode, sizeof entity->devname);
>  	entity->devname[sizeof entity->devname - 1] = '\0';
> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
> index 33c1ee6..3977ce5 100644
> --- a/utils/media-ctl/libv4l2subdev.c
> +++ b/utils/media-ctl/libv4l2subdev.c
> @@ -39,13 +39,61 @@
>  #include "tools.h"
>  #include "v4l2subdev.h"
>  
> +int v4l2_subdev_create(struct media_entity *entity)
> +{
> +	if (entity->sd)
> +		return 0;
> +
> +	entity->sd = calloc(1, sizeof(*entity->sd));
> +	if (entity->sd == NULL)
> +		return -ENOMEM;
> +
> +	entity->sd->fd = -1;
> +
> +	return 0;
> +}
> +
> +int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
> +{
> +	int ret;
> +
> +	if (entity->sd)
> +		return -EEXIST;
> +
> +	ret = v4l2_subdev_create(entity);
> +	if (ret < 0)
> +		return ret;
> +
> +	entity->sd->fd = fd;
> +
> +	return 0;
> +}
> +
> +void v4l2_subdev_release(struct media_entity *entity, bool close_fd)
> +{
> +	if (entity->sd == NULL)
> +		return;
> +
> +	if (close_fd)
> +		v4l2_subdev_close(entity);
> +
> +	free(entity->sd->v4l2_control_redir);
> +	free(entity->sd);
> +}
> +
>  int v4l2_subdev_open(struct media_entity *entity)
>  {
> -	if (entity->fd != -1)
> +	int ret;
> +
> +	ret = v4l2_subdev_create(entity);

The current users of v4l2_subdev_open() in libv4l2subdev do not
explicitly close the sub-devices they open; thus calling
v4l2_subdev_create() here creates a memory leak.

I wonder if it'd do harm to open all the associated devices in
media_device_open() and close them in media_device_close().

The sub-device objects could exist for the entire lifespan of the media
device object (in user space), and they could be used to store whatever
information is needed.

One would no longer need to call v4l2_subdev_open() directly either.

I'd like to have Laurent's opinion on this, too.

The power management currently is based on open file handles and this is
a bit of a problem, but we have to have a better solution on this (based
on latencies and perhaps PM QoS framework).

> +	if (ret < 0)
> +		return ret;
> +
> +	if (entity->sd->fd != -1)
>  		return 0;
>  
> -	entity->fd = open(entity->devname, O_RDWR);
> -	if (entity->fd == -1) {
> +	entity->sd->fd = open(entity->devname, O_RDWR);
> +	if (entity->sd->fd == -1) {
>  		int ret = -errno;
>  		media_dbg(entity->media,
>  			  "%s: Failed to open subdev device node %s\n", __func__,
> @@ -58,8 +106,8 @@ int v4l2_subdev_open(struct media_entity *entity)
>  
>  void v4l2_subdev_close(struct media_entity *entity)
>  {
> -	close(entity->fd);
> -	entity->fd = -1;
> +	close(entity->sd->fd);
> +	entity->sd->fd = -1;
>  }
>  
>  int v4l2_subdev_get_format(struct media_entity *entity,
> @@ -77,7 +125,7 @@ int v4l2_subdev_get_format(struct media_entity *entity,
>  	fmt.pad = pad;
>  	fmt.which = which;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -101,7 +149,7 @@ int v4l2_subdev_set_format(struct media_entity *entity,
>  	fmt.which = which;
>  	fmt.format = *format;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -128,7 +176,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
>  	u.sel.target = target;
>  	u.sel.which = which;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
>  	if (ret >= 0) {
>  		*rect = u.sel.r;
>  		return 0;
> @@ -140,7 +188,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
>  	u.crop.pad = pad;
>  	u.crop.which = which;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -168,7 +216,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
>  	u.sel.which = which;
>  	u.sel.r = *rect;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
>  	if (ret >= 0) {
>  		*rect = u.sel.r;
>  		return 0;
> @@ -181,7 +229,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
>  	u.crop.which = which;
>  	u.crop.rect = *rect;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -202,7 +250,7 @@ int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
>  	memset(caps, 0, sizeof(*caps));
>  	caps->pad = pad;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -220,7 +268,7 @@ int v4l2_subdev_query_dv_timings(struct media_entity *entity,
>  
>  	memset(timings, 0, sizeof(*timings));
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -238,7 +286,7 @@ int v4l2_subdev_get_dv_timings(struct media_entity *entity,
>  
>  	memset(timings, 0, sizeof(*timings));
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -254,7 +302,7 @@ int v4l2_subdev_set_dv_timings(struct media_entity *entity,
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -273,7 +321,7 @@ int v4l2_subdev_get_frame_interval(struct media_entity *entity,
>  
>  	memset(&ival, 0, sizeof(ival));
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
>  	if (ret < 0)
>  		return -errno;
>  
> @@ -294,7 +342,7 @@ int v4l2_subdev_set_frame_interval(struct media_entity *entity,
>  	memset(&ival, 0, sizeof(ival));
>  	ival.interval = *interval;
>  
> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
>  	if (ret < 0)
>  		return -errno;
>  
> diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
> index a0d3a55..f531c52 100644
> --- a/utils/media-ctl/mediactl-priv.h
> +++ b/utils/media-ctl/mediactl-priv.h
> @@ -26,6 +26,8 @@
>  
>  #include "mediactl.h"
>  
> +struct v4l2_subdev;
> +
>  struct media_entity {
>  	struct media_device *media;
>  	struct media_entity_desc info;
> @@ -34,8 +36,9 @@ struct media_entity {
>  	unsigned int max_links;
>  	unsigned int num_links;
>  
> +	struct v4l2_subdev *sd;
> +
>  	char devname[32];
> -	int fd;
>  };
>  
>  struct media_device {
> diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
> index 104e420..ba9b8c4 100644
> --- a/utils/media-ctl/v4l2subdev.h
> +++ b/utils/media-ctl/v4l2subdev.h
> @@ -27,6 +27,44 @@
>  struct media_device;
>  struct media_entity;
>  
> +struct v4l2_subdev {
> +	int fd;
> +};
> +
> +/**
> + * @brief Create a v4l2-subdev
> + * @param entity - sub-device media entity.
> + *
> + * Create the representation of the entity sub-device.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +int v4l2_subdev_create(struct media_entity *entity);
> +
> +/**
> + * @brief Create a representation of the already opened v4l2-subdev
> + * @param entity - sub-device media entity.
> + * @param fd - sub-device file descriptor.
> + *
> + * Create the representation of the sub-device that had been opened
> + * before the parent media device was created, and associate it
> + * with the media entity.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd);
> +
> +/**
> + * @brief Release a v4l2-subdev
> + * @param entity - sub-device media entity.
> + * @param close_fd - indicates whether subdev fd should be closed.
> + *
> + * Release the representation of the entity sub-device.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +void v4l2_subdev_release(struct media_entity *entity, bool close_fd);
> +

Is there a need to call these outside the library itself? Should they be
static instead?

>  /**
>   * @brief Open a sub-device.
>   * @param entity - sub-device media entity.
> 

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config
  2016-01-18 16:17 ` [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config Jacek Anaszewski
@ 2016-02-15 10:58   ` Sakari Ailus
  2016-02-15 11:39     ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 10:58 UTC (permalink / raw)
  To: Jacek Anaszewski, linux-media
  Cc: laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

Jacek Anaszewski wrote:
> Make struct v4l2_subdev capable of aggregating v4l2-ctrl-redir
> media device configuration entries. Added are also functions for
> validating the config and checking whether a v4l2 sub-device
> expects to receive ioctls related to the v4l2-control with given id.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/libv4l2subdev.c |   49 ++++++++++++++++++++++++++++++++++++++-
>  utils/media-ctl/v4l2subdev.h    |   30 ++++++++++++++++++++++++
>  2 files changed, 78 insertions(+), 1 deletion(-)
> 
> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
> index 3977ce5..069ded6 100644
> --- a/utils/media-ctl/libv4l2subdev.c
> +++ b/utils/media-ctl/libv4l2subdev.c
> @@ -26,7 +26,6 @@
>  #include <ctype.h>
>  #include <errno.h>
>  #include <fcntl.h>
> -#include <stdbool.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> @@ -50,7 +49,15 @@ int v4l2_subdev_create(struct media_entity *entity)
>  
>  	entity->sd->fd = -1;
>  
> +	entity->sd->v4l2_control_redir = malloc(sizeof(__u32));
> +	if (entity->sd->v4l2_control_redir == NULL)
> +		goto err_v4l2_control_redir_alloc;
> +
>  	return 0;
> +
> +err_v4l2_control_redir_alloc:
> +	free(entity->sd);
> +	return -ENOMEM;
>  }
>  
>  int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
> @@ -870,3 +877,43 @@ enum v4l2_field v4l2_subdev_string_to_field(const char *string,
>  
>  	return fields[i].field;
>  }
> +
> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
> +				   struct media_entity *entity,
> +				   __u32 ctrl_id)
> +{
> +	struct v4l2_queryctrl queryctrl = {};
> +	int ret;
> +
> +	ret = v4l2_subdev_open(entity);
> +	if (ret < 0)
> +		return ret;
> +
> +	queryctrl.id = ctrl_id;
> +
> +	ret = ioctl(entity->sd->fd, VIDIOC_QUERYCTRL, &queryctrl);
> +	if (ret < 0)
> +		return ret;
> +
> +	media_dbg(media, "Validated control \"%s\" (0x%8.8x) on entity %s\n",
> +		  queryctrl.name, queryctrl.id, entity->info.name);
> +
> +	return 0;
> +}
> +
> +bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
> +				  struct media_entity *entity,
> +				  int ctrl_id)
> +{
> +	struct v4l2_subdev *sd = entity->sd;
> +	int i;
> +
> +	if (!sd)
> +		return false;
> +
> +	for (i = 0; i < sd->v4l2_control_redir_num; ++i)
> +		if (sd->v4l2_control_redir[i] == ctrl_id)
> +			return true;
> +
> +	return false;
> +}
> diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
> index ba9b8c4..f395065 100644
> --- a/utils/media-ctl/v4l2subdev.h
> +++ b/utils/media-ctl/v4l2subdev.h
> @@ -23,12 +23,17 @@
>  #define __SUBDEV_H__
>  
>  #include <linux/v4l2-subdev.h>
> +#include <stdbool.h>
>  
>  struct media_device;
>  struct media_entity;
> +struct media_device;
>  
>  struct v4l2_subdev {
>  	int fd;
> +
> +	__u32 *v4l2_control_redir;
> +	unsigned int v4l2_control_redir_num;
>  };
>  
>  /**
> @@ -316,5 +321,30 @@ const char *v4l2_subdev_field_to_string(enum v4l2_field field);
>   */
>  enum v4l2_field v4l2_subdev_string_to_field(const char *string,
>  					    unsigned int length);
> +/**
> + * @brief Validate v4l2 control for a sub-device
> + * @param media - media device.
> + * @param entity - subdev-device media entity.
> + * @param ctrl_id - id of the v4l2 control to validate.
> + *
> + * Verify if the entity supports v4l2-control with given ctrl_id.
> + *
> + * @return 1 if the control is supported, 0 otherwise.
> + */
> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
> +				   struct media_entity *entity,
> +				   __u32 ctrl_id);
> +/**
> + * @brief Check if there was a v4l2_control redirection defined for the entity
> + * @param media - media device.
> + * @param entity - subdev-device media entity.
> + * @param ctrl_id - v4l2 control identifier.
> + *
> + * Check if there was a v4l2-ctrl-redir entry defined for the entity.
> + *
> + * @return true if the entry exists, false otherwise
> + */
> +bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
> +	struct media_entity *entity, int ctrl_id);
>  
>  #endif
> 

Where do you need this?

If you have an application that's aware of V4L2 sub-devices (and thus
multiple devices)), I'd expect it to set the controls on the sub-devices
the controls are implemented in rather than rely on them being redirected.

This would make perfect sense IMO when implementing plain V4L2 interface
support on top of drivers that expose MC/V4L2 subdev/V4L2 APIs. But I
wouldn't implement it in libv4l2subdev.

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config
  2016-02-15 10:58   ` Sakari Ailus
@ 2016-02-15 11:39     ` Jacek Anaszewski
  2016-02-15 12:22       ` Sakari Ailus
  0 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-15 11:39 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

Thanks for the review.

On 02/15/2016 11:58 AM, Sakari Ailus wrote:
> Hi Jacek,
>
> Jacek Anaszewski wrote:
>> Make struct v4l2_subdev capable of aggregating v4l2-ctrl-redir
>> media device configuration entries. Added are also functions for
>> validating the config and checking whether a v4l2 sub-device
>> expects to receive ioctls related to the v4l2-control with given id.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>   utils/media-ctl/libv4l2subdev.c |   49 ++++++++++++++++++++++++++++++++++++++-
>>   utils/media-ctl/v4l2subdev.h    |   30 ++++++++++++++++++++++++
>>   2 files changed, 78 insertions(+), 1 deletion(-)
>>
>> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
>> index 3977ce5..069ded6 100644
>> --- a/utils/media-ctl/libv4l2subdev.c
>> +++ b/utils/media-ctl/libv4l2subdev.c
>> @@ -26,7 +26,6 @@
>>   #include <ctype.h>
>>   #include <errno.h>
>>   #include <fcntl.h>
>> -#include <stdbool.h>
>>   #include <stdio.h>
>>   #include <stdlib.h>
>>   #include <string.h>
>> @@ -50,7 +49,15 @@ int v4l2_subdev_create(struct media_entity *entity)
>>
>>   	entity->sd->fd = -1;
>>
>> +	entity->sd->v4l2_control_redir = malloc(sizeof(__u32));
>> +	if (entity->sd->v4l2_control_redir == NULL)
>> +		goto err_v4l2_control_redir_alloc;
>> +
>>   	return 0;
>> +
>> +err_v4l2_control_redir_alloc:
>> +	free(entity->sd);
>> +	return -ENOMEM;
>>   }
>>
>>   int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
>> @@ -870,3 +877,43 @@ enum v4l2_field v4l2_subdev_string_to_field(const char *string,
>>
>>   	return fields[i].field;
>>   }
>> +
>> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
>> +				   struct media_entity *entity,
>> +				   __u32 ctrl_id)
>> +{
>> +	struct v4l2_queryctrl queryctrl = {};
>> +	int ret;
>> +
>> +	ret = v4l2_subdev_open(entity);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	queryctrl.id = ctrl_id;
>> +
>> +	ret = ioctl(entity->sd->fd, VIDIOC_QUERYCTRL, &queryctrl);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	media_dbg(media, "Validated control \"%s\" (0x%8.8x) on entity %s\n",
>> +		  queryctrl.name, queryctrl.id, entity->info.name);
>> +
>> +	return 0;
>> +}
>> +
>> +bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
>> +				  struct media_entity *entity,
>> +				  int ctrl_id)
>> +{
>> +	struct v4l2_subdev *sd = entity->sd;
>> +	int i;
>> +
>> +	if (!sd)
>> +		return false;
>> +
>> +	for (i = 0; i < sd->v4l2_control_redir_num; ++i)
>> +		if (sd->v4l2_control_redir[i] == ctrl_id)
>> +			return true;
>> +
>> +	return false;
>> +}
>> diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
>> index ba9b8c4..f395065 100644
>> --- a/utils/media-ctl/v4l2subdev.h
>> +++ b/utils/media-ctl/v4l2subdev.h
>> @@ -23,12 +23,17 @@
>>   #define __SUBDEV_H__
>>
>>   #include <linux/v4l2-subdev.h>
>> +#include <stdbool.h>
>>
>>   struct media_device;
>>   struct media_entity;
>> +struct media_device;
>>
>>   struct v4l2_subdev {
>>   	int fd;
>> +
>> +	__u32 *v4l2_control_redir;
>> +	unsigned int v4l2_control_redir_num;
>>   };
>>
>>   /**
>> @@ -316,5 +321,30 @@ const char *v4l2_subdev_field_to_string(enum v4l2_field field);
>>    */
>>   enum v4l2_field v4l2_subdev_string_to_field(const char *string,
>>   					    unsigned int length);
>> +/**
>> + * @brief Validate v4l2 control for a sub-device
>> + * @param media - media device.
>> + * @param entity - subdev-device media entity.
>> + * @param ctrl_id - id of the v4l2 control to validate.
>> + *
>> + * Verify if the entity supports v4l2-control with given ctrl_id.
>> + *
>> + * @return 1 if the control is supported, 0 otherwise.
>> + */
>> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
>> +				   struct media_entity *entity,
>> +				   __u32 ctrl_id);
>> +/**
>> + * @brief Check if there was a v4l2_control redirection defined for the entity
>> + * @param media - media device.
>> + * @param entity - subdev-device media entity.
>> + * @param ctrl_id - v4l2 control identifier.
>> + *
>> + * Check if there was a v4l2-ctrl-redir entry defined for the entity.
>> + *
>> + * @return true if the entry exists, false otherwise
>> + */
>> +bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
>> +	struct media_entity *entity, int ctrl_id);
>>
>>   #endif
>>
>
> Where do you need this?

It is used in v4l2_subdev_get_pipeline_entity_by_cid, which returns the
first entity in the pipeline the control setting is to be redirected to.
The v4l2_subdev_get_pipeline_entity_by_cid() is in turn required in
libv4l2media_ioctl.c, in the functions that apply control settings to
the pipeline. The actual sub-device to apply the settings on is being
selected basing on the v4l2-ctrl-redir config entry.

This is required in case more than one sub-device in the pipeline
supports a control and we want to choose specific hardware
implementation thereof. For example both S5C73M3 and fimc.0.capture
sub-devices support "Color Effects", but the effects differ visually -
e.g. Sepia realized by S5C73M3 is more "orange" than the one from
fimc.0.capture.

And we can set controls with GStreamer pipeline :

gst-launch-1.0 v4l2src device=/dev/video1 
extra-controls="c,color_effects=2" ! video/x-raw,width=960,height=920 ! 
fbdevsink

>
> If you have an application that's aware of V4L2 sub-devices (and thus
> multiple devices)), I'd expect it to set the controls on the sub-devices
> the controls are implemented in rather than rely on them being redirected.
>
> This would make perfect sense IMO when implementing plain V4L2 interface
> support on top of drivers that expose MC/V4L2 subdev/V4L2 APIs. But I
> wouldn't implement it in libv4l2subdev.
>


-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 05/15] mediactl: Add media device graph helpers
  2016-01-18 16:17 ` [PATCH 05/15] mediactl: Add media device graph helpers Jacek Anaszewski
@ 2016-02-15 12:02   ` Sakari Ailus
  2016-02-15 12:45     ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 12:02 UTC (permalink / raw)
  To: Jacek Anaszewski, linux-media
  Cc: laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

Jacek Anaszewski wrote:
> Add new graph helpers useful for video pipeline discovering.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/libmediactl.c |   48 +++++++++++++++++++++++++++++++++++++++++
>  utils/media-ctl/mediactl.h    |   36 +++++++++++++++++++++++++++++++
>  2 files changed, 84 insertions(+)
> 
> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
> index 61b5f50..0be1845 100644
> --- a/utils/media-ctl/libmediactl.c
> +++ b/utils/media-ctl/libmediactl.c
> @@ -35,6 +35,7 @@
>  #include <unistd.h>
>  
>  #include <linux/media.h>
> +#include <linux/kdev_t.h>
>  #include <linux/videodev2.h>
>  
>  #include "mediactl.h"
> @@ -87,6 +88,29 @@ struct media_entity *media_get_entity_by_name(struct media_device *media,
>  	return NULL;
>  }
>  
> +struct media_entity *media_get_entity_by_devname(struct media_device *media,
> +						 const char *devname,
> +						 size_t length)
> +{
> +	unsigned int i;
> +
> +	/* A match is impossible if the entity devname is longer than the
> +	 * maximum size we can get from the kernel.
> +	 */
> +	if (length >= FIELD_SIZEOF(struct media_entity, devname))
> +		return NULL;
> +
> +	for (i = 0; i < media->entities_count; ++i) {
> +		struct media_entity *entity = &media->entities[i];
> +
> +		if (strncmp(entity->devname, devname, length) == 0 &&
> +		    entity->devname[length] == '\0')
> +			return entity;
> +	}
> +
> +	return NULL;
> +}

Just out of curiosity: where do you need this? I.e. why do you need to
translate a device name to an entity?

> +
>  struct media_entity *media_get_entity_by_id(struct media_device *media,
>  					    __u32 id)
>  {
> @@ -145,6 +169,11 @@ const char *media_entity_get_devname(struct media_entity *entity)
>  	return entity->devname[0] ? entity->devname : NULL;
>  }
>  
> +const char *media_entity_get_name(struct media_entity *entity)
> +{
> +	return entity->info.name;
> +}

You should instead use media_get_info()->name . If you have an entity,
the return value will be valid.

> +
>  struct media_entity *media_get_default_entity(struct media_device *media,
>  					      unsigned int type)
>  {
> @@ -177,6 +206,25 @@ const struct media_entity_desc *media_entity_get_info(struct media_entity *entit
>  	return &entity->info;
>  }
>  
> +int media_get_backlinks_by_entity(struct media_entity *entity,

How about calling this media_entity_get_backlinks()?

> +				struct media_link **backlinks,
> +				int *num_backlinks)

unsigned int.

> +{
> +	int num_bklinks = 0, i;

Same here.

> +
> +	if (entity == NULL || backlinks == NULL || num_backlinks == NULL)
> +		return -EINVAL;
> +
> +	for (i = 0; i < entity->num_links; ++i)
> +		if ((entity->links[i].flags & MEDIA_LNK_FL_ENABLED) &&
> +		    (entity->links[i].sink->entity == entity))
> +			backlinks[num_bklinks++] = &entity->links[i];
> +
> +	*num_backlinks = num_bklinks;
> +
> +	return 0;
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Open/close
>   */
> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
> index 3faee71..9db40a8 100644
> --- a/utils/media-ctl/mediactl.h
> +++ b/utils/media-ctl/mediactl.h
> @@ -231,6 +231,15 @@ const struct media_link *media_entity_get_link(struct media_entity *entity,
>  const char *media_entity_get_devname(struct media_entity *entity);
>  
>  /**
> + * @brief Get the name for an entity
> + * @param entity - media entity.
> + *
> + * This function returns the name of the entity.
> + *
> + * @return A pointer to the string with entity name
> + */
> +const char *media_entity_get_name(struct media_entity *entity);
> +
>   * @brief Get the type of an entity.
>   * @param entity - the entity.
>   *
> @@ -255,6 +264,19 @@ struct media_entity *media_get_entity_by_name(struct media_device *media,
>  	const char *name, size_t length);
>  
>  /**
> + * @brief Find an entity by the corresponding device node name.
> + * @param media - media device.
> + * @param devname - device node name.
> + * @param length - size of @a devname.
> + *
> + * Search for an entity with a device node name equal to @a devname.
> + *
> + * @return A pointer to the entity if found, or NULL otherwise.
> + */
> +struct media_entity *media_get_entity_by_devname(struct media_device *media,
> +	const char *devname, size_t length);
> +
> +/**
>   * @brief Find an entity by its ID.
>   * @param media - media device.
>   * @param id - entity ID.
> @@ -434,4 +456,18 @@ int media_parse_setup_link(struct media_device *media,
>   */
>  int media_parse_setup_links(struct media_device *media, const char *p);
>  
> +/**
> + * @brief Get entity's enabled backlinks
> + * @param entity - media entity.
> + * @param backlinks - array of pointers to matching backlinks.
> + * @param num_backlinks - number of matching backlinks.
> + *
> + * Get links that are connected to the entity sink pads.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +int media_get_backlinks_by_entity(struct media_entity *entity,
> +				struct media_link **backlinks,
> +				int *num_backlinks);
> +
>  #endif
> 


-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config
  2016-02-15 11:39     ` Jacek Anaszewski
@ 2016-02-15 12:22       ` Sakari Ailus
  0 siblings, 0 replies; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 12:22 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

Jacek Anaszewski wrote:
> Hi Sakari,
> 
> Thanks for the review.
> 
> On 02/15/2016 11:58 AM, Sakari Ailus wrote:
>> Hi Jacek,
>>
>> Jacek Anaszewski wrote:
>>> Make struct v4l2_subdev capable of aggregating v4l2-ctrl-redir
>>> media device configuration entries. Added are also functions for
>>> validating the config and checking whether a v4l2 sub-device
>>> expects to receive ioctls related to the v4l2-control with given id.
>>>
>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>> ---
>>>   utils/media-ctl/libv4l2subdev.c |   49
>>> ++++++++++++++++++++++++++++++++++++++-
>>>   utils/media-ctl/v4l2subdev.h    |   30 ++++++++++++++++++++++++
>>>   2 files changed, 78 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/utils/media-ctl/libv4l2subdev.c
>>> b/utils/media-ctl/libv4l2subdev.c
>>> index 3977ce5..069ded6 100644
>>> --- a/utils/media-ctl/libv4l2subdev.c
>>> +++ b/utils/media-ctl/libv4l2subdev.c
>>> @@ -26,7 +26,6 @@
>>>   #include <ctype.h>
>>>   #include <errno.h>
>>>   #include <fcntl.h>
>>> -#include <stdbool.h>
>>>   #include <stdio.h>
>>>   #include <stdlib.h>
>>>   #include <string.h>
>>> @@ -50,7 +49,15 @@ int v4l2_subdev_create(struct media_entity *entity)
>>>
>>>       entity->sd->fd = -1;
>>>
>>> +    entity->sd->v4l2_control_redir = malloc(sizeof(__u32));
>>> +    if (entity->sd->v4l2_control_redir == NULL)
>>> +        goto err_v4l2_control_redir_alloc;
>>> +
>>>       return 0;
>>> +
>>> +err_v4l2_control_redir_alloc:
>>> +    free(entity->sd);
>>> +    return -ENOMEM;
>>>   }
>>>
>>>   int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
>>> @@ -870,3 +877,43 @@ enum v4l2_field
>>> v4l2_subdev_string_to_field(const char *string,
>>>
>>>       return fields[i].field;
>>>   }
>>> +
>>> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
>>> +                   struct media_entity *entity,
>>> +                   __u32 ctrl_id)
>>> +{
>>> +    struct v4l2_queryctrl queryctrl = {};
>>> +    int ret;
>>> +
>>> +    ret = v4l2_subdev_open(entity);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    queryctrl.id = ctrl_id;
>>> +
>>> +    ret = ioctl(entity->sd->fd, VIDIOC_QUERYCTRL, &queryctrl);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    media_dbg(media, "Validated control \"%s\" (0x%8.8x) on entity
>>> %s\n",
>>> +          queryctrl.name, queryctrl.id, entity->info.name);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
>>> +                  struct media_entity *entity,
>>> +                  int ctrl_id)
>>> +{
>>> +    struct v4l2_subdev *sd = entity->sd;
>>> +    int i;
>>> +
>>> +    if (!sd)
>>> +        return false;
>>> +
>>> +    for (i = 0; i < sd->v4l2_control_redir_num; ++i)
>>> +        if (sd->v4l2_control_redir[i] == ctrl_id)
>>> +            return true;
>>> +
>>> +    return false;
>>> +}
>>> diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
>>> index ba9b8c4..f395065 100644
>>> --- a/utils/media-ctl/v4l2subdev.h
>>> +++ b/utils/media-ctl/v4l2subdev.h
>>> @@ -23,12 +23,17 @@
>>>   #define __SUBDEV_H__
>>>
>>>   #include <linux/v4l2-subdev.h>
>>> +#include <stdbool.h>
>>>
>>>   struct media_device;
>>>   struct media_entity;
>>> +struct media_device;
>>>
>>>   struct v4l2_subdev {
>>>       int fd;
>>> +
>>> +    __u32 *v4l2_control_redir;
>>> +    unsigned int v4l2_control_redir_num;
>>>   };
>>>
>>>   /**
>>> @@ -316,5 +321,30 @@ const char *v4l2_subdev_field_to_string(enum
>>> v4l2_field field);
>>>    */
>>>   enum v4l2_field v4l2_subdev_string_to_field(const char *string,
>>>                           unsigned int length);
>>> +/**
>>> + * @brief Validate v4l2 control for a sub-device
>>> + * @param media - media device.
>>> + * @param entity - subdev-device media entity.
>>> + * @param ctrl_id - id of the v4l2 control to validate.
>>> + *
>>> + * Verify if the entity supports v4l2-control with given ctrl_id.
>>> + *
>>> + * @return 1 if the control is supported, 0 otherwise.
>>> + */
>>> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
>>> +                   struct media_entity *entity,
>>> +                   __u32 ctrl_id);
>>> +/**
>>> + * @brief Check if there was a v4l2_control redirection defined for
>>> the entity
>>> + * @param media - media device.
>>> + * @param entity - subdev-device media entity.
>>> + * @param ctrl_id - v4l2 control identifier.
>>> + *
>>> + * Check if there was a v4l2-ctrl-redir entry defined for the entity.
>>> + *
>>> + * @return true if the entry exists, false otherwise
>>> + */
>>> +bool v4l2_subdev_has_v4l2_control_redir(struct media_device *media,
>>> +    struct media_entity *entity, int ctrl_id);
>>>
>>>   #endif
>>>
>>
>> Where do you need this?
> 
> It is used in v4l2_subdev_get_pipeline_entity_by_cid, which returns the
> first entity in the pipeline the control setting is to be redirected to.
> The v4l2_subdev_get_pipeline_entity_by_cid() is in turn required in
> libv4l2media_ioctl.c, in the functions that apply control settings to
> the pipeline. The actual sub-device to apply the settings on is being
> selected basing on the v4l2-ctrl-redir config entry.
> 
> This is required in case more than one sub-device in the pipeline
> supports a control and we want to choose specific hardware
> implementation thereof. For example both S5C73M3 and fimc.0.capture
> sub-devices support "Color Effects", but the effects differ visually -
> e.g. Sepia realized by S5C73M3 is more "orange" than the one from
> fimc.0.capture.

Right.

libv4l2subdev still deals with sub-devices, and I don't think this
functionality belongs there. Instead, I'd put it in libv4l2media_ioctl.

> 
> And we can set controls with GStreamer pipeline :
> 
> gst-launch-1.0 v4l2src device=/dev/video1
> extra-controls="c,color_effects=2" ! video/x-raw,width=960,height=920 !
> fbdevsink
> 
>>
>> If you have an application that's aware of V4L2 sub-devices (and thus
>> multiple devices)), I'd expect it to set the controls on the sub-devices
>> the controls are implemented in rather than rely on them being
>> redirected.
>>
>> This would make perfect sense IMO when implementing plain V4L2 interface
>> support on top of drivers that expose MC/V4L2 subdev/V4L2 APIs. But I
>> wouldn't implement it in libv4l2subdev.
>>
> 
> 


-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-01-18 16:17 ` [PATCH 13/15] mediactl: Add media device ioctl API Jacek Anaszewski
@ 2016-02-15 12:41   ` Sakari Ailus
  2016-02-15 13:06     ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 12:41 UTC (permalink / raw)
  To: Jacek Anaszewski, linux-media
  Cc: laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

Jacek Anaszewski wrote:
> Ioctls executed on complex media devices need special handling.
> For instance some ioctls need to be targeted for specific sub-devices,
> depending on the media device configuration. The APIs being introduced
> address such requirements.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/Makefile.am          |    2 +-
>  utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
>  utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
>  3 files changed, 453 insertions(+), 1 deletion(-)
>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
> 
> diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
> index 3e883e0..7f18624 100644
> --- a/utils/media-ctl/Makefile.am
> +++ b/utils/media-ctl/Makefile.am
> @@ -1,6 +1,6 @@
>  noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
>  
> -libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
> +libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
>  libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
>  libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
>  
> diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
> new file mode 100644
> index 0000000..b186121
> --- /dev/null
> +++ b/utils/media-ctl/libv4l2media_ioctl.c
> @@ -0,0 +1,404 @@
> +/*
> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
> + *              http://www.samsung.com
> + *
> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + */
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <sys/syscall.h>
> +#include <unistd.h>
> +
> +#include <linux/videodev2.h>
> +
> +#include "libv4l2media_ioctl.h"
> +#include "mediactl-priv.h"
> +#include "mediactl.h"
> +#include "v4l2subdev.h"
> +
> +#define VIDIOC_CTRL(type)					\
> +	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
> +				   "VIDIOC_G_CTRL")
> +
> +#define VIDIOC_EXT_CTRL(type)					\
> +	((type) == VIDIOC_S_EXT_CTRLS ? 			\
> +		"VIDIOC_S_EXT_CTRLS"	:			\
> +		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
> +				    "VIDIOC_G_EXT_CTRLS" :	\
> +				    "VIDIOC_TRY_EXT_CTRLS"))
> +
> +#define SYS_IOCTL(fd, cmd, arg) \
> +	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
> +
> +
> +int media_ioctl_ctrl(struct media_device *media, int request,

unsigned int request

> +		     struct v4l2_control *arg)

I wonder if it'd make sense to always use v4l2_ext_control instead. You
can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.

As this is a user space library, I'd probably add a function to handle
S/G/TRY control each.

Have you considered binding the control to a video node rather than a
media device? We have many sensors on current media devices already, and
e.g. exposure time control can be found in multiple sub-devices.

> +{
> +	struct media_entity *entity = media->pipeline;
> +	struct v4l2_control ctrl = *arg;
> +	struct v4l2_queryctrl queryctrl;
> +	bool ctrl_found = 0;
> +	int ret;
> +
> +	/*
> +	 * The control has to be reset to the default value
> +	 * on all of the pipeline entities, prior setting a new
> +	 * value. This is required in cases when the control config
> +	 * is changed between subsequent calls to VIDIOC_S_CTRL,
> +	 * to avoid the situation when a control is set on more
> +	 * than one sub-device.
> +	 */
> +	if (request == VIDIOC_S_CTRL) {
> +		while (entity) {
> +			queryctrl.id = ctrl.id;
> +
> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYCTRL,
> +					&queryctrl);
> +			if (ret < 0) {
> +				entity = entity->next;
> +				continue;
> +			}
> +
> +			ctrl_found = true;
> +
> +			if (queryctrl.type & V4L2_CTRL_TYPE_BUTTON)
> +				break;
> +
> +			ctrl.value = queryctrl.default_value;
> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_S_CTRL, &ctrl);
> +			if (ret < 0)
> +				return -EINVAL;
> +
> +			entity = entity->next;
> +		}
> +
> +		ctrl.value = arg->value;
> +	}
> +
> +	if (!ctrl_found) {
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, ctrl.id);
> +
> +	if (entity) {
> +		ret = SYS_IOCTL(entity->sd->fd, request, &ctrl);
> +	} else {
> +		/* Walk the pipeline until the request succeeds */
> +		entity = media->pipeline;
> +
> +		ret = -ENOENT;
> +
> +		while (entity) {
> +			ret = SYS_IOCTL(entity->sd->fd, request, &ctrl);
> +			if (!ret)
> +				break;
> +
> +			entity = entity->next;
> +		}
> +	}
> +
> +exit:
> +	*arg = ctrl;
> +
> +	media_dbg(media, "%s [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
> +		  VIDIOC_CTRL(request), ctrl.id, ret ? NULL : queryctrl.name,
> +		  entity ? entity->info.name : NULL, ret);
> +
> +	return ret;
> +}
> +
> +static int media_ioctl_single_ext_ctrl(struct media_device *media,
> +				int request, struct v4l2_ext_controls *arg)
> +{
> +	struct media_entity *entity = media->pipeline;
> +	struct v4l2_ext_controls ctrls = *arg;
> +	struct v4l2_ext_control *ctrl;
> +	struct v4l2_query_ext_ctrl queryctrl;
> +	bool ctrl_found = 0;
> +	int ret = -EINVAL;
> +
> +	ctrl = &ctrls.controls[0];
> +
> +	/*
> +	 * The control has to be reset to the default value
> +	 * on all of the pipeline entities, prior setting a new
> +	 * value. This is required in cases when the control config
> +	 * is changed between subsequent calls to VIDIOC_S_EXT_CTRLS,
> +	 * to avoid the situation when a control is set on more
> +	 * than one sub-device.
> +	 */
> +	if (request == VIDIOC_S_EXT_CTRLS) {
> +		while (entity) {
> +			queryctrl.id = ctrl->id;
> +
> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERY_EXT_CTRL,
> +					&queryctrl);
> +			if (ret < 0) {
> +				entity = entity->next;
> +				continue;
> +			}
> +
> +			ctrl_found = true;
> +
> +			if (queryctrl.type & V4L2_CTRL_TYPE_BUTTON)
> +				break;
> +
> +			ctrl->value64 = queryctrl.default_value;
> +
> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_S_EXT_CTRLS,
> +					&ctrls);
> +			if (ret < 0)
> +				return -EINVAL;
> +
> +			entity = entity->next;
> +		}
> +
> +		ctrl->value64 = arg->controls[0].value64;
> +	}
> +
> +	if (!ctrl_found) {
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, ctrl->id);
> +
> +	if (entity) {
> +		ret = SYS_IOCTL(entity->sd->fd, request, &ctrls);
> +	} else {
> +		/* Walk the pipeline until the request succeeds */
> +		entity = media->pipeline;
> +
> +		while (entity) {
> +			ret = SYS_IOCTL(entity->sd->fd, request, &ctrls);
> +			if (!ret)
> +				break;
> +
> +			entity = entity->next;
> +		}
> +	}
> +
> +exit:
> +	*arg = ctrls;
> +
> +	media_dbg(media, "%s [id: 0x%8.8x, entity: %s] (%d)\n",
> +		  VIDIOC_EXT_CTRL(request), ctrl->id,
> +		  entity ? entity->info.name : NULL, ret);
> +
> +	return ret;
> +}
> +
> +int media_ioctl_ext_ctrl(struct media_device *media, int request,
> +			 struct v4l2_ext_controls *arg)
> +{
> +	struct v4l2_ext_controls out_ctrls = *arg, ctrls = *arg;
> +	int ret = -EINVAL, i;
> +
> +	ctrls.count = 1;
> +
> +	/*
> +	 * Split cluster to individual ioctl calls for each control
> +	 * from the array, to make possible redirection of every
> +	 * single control to different sub-device, according to the
> +	 * configuration settings.
> +	 */
> +	for (i = 0; i < arg->count; ++i) {
> +		ctrls.controls = &arg->controls[i];
> +
> +		ret = media_ioctl_single_ext_ctrl(media, request, &ctrls);
> +		out_ctrls.controls[i] = ctrls.controls[i];
> +		if (ret < 0) {
> +			if (ctrls.error_idx == 1)
> +				out_ctrls.error_idx = ctrls.count;
> +			else
> +				out_ctrls.error_idx = i;
> +			break;
> +		}
> +	}
> +
> +	*arg = out_ctrls;
> +	return ret;
> +}
> +
> +int sort_ctrls(const void * a, const void * b)
> +{
> +	const struct media_entity_to_cid *ctrl_a = a, *ctrl_b = b;
> +
> +	return ctrl_a->queryctrl.id - ctrl_b->queryctrl.id;
> +}
> +
> +int media_ioctl_queryctrl(struct media_device *media,
> +			  struct v4l2_queryctrl *arg)
> +{
> +	struct media_entity *entity = media->pipeline, *target_entity;
> +	struct v4l2_queryctrl queryctrl = *arg;
> +	int ret = -EINVAL, num_ctrls = 0;
> +	struct media_entity_to_cid *ctrls_found;
> +
> +	/*
> +	 * If id is or'ed with V4L2_CTRL_FLAG_NEXT_CTRL then the control to
> +	 * be found is the one with the next lowest id among all entities
> +	 * in the pipeline.
> +	 */
> +	if (queryctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) {
> +		ctrls_found = malloc(sizeof(*ctrls_found));
> +
> +		while (entity) {
> +			queryctrl = *arg;
> +
> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYCTRL,
> +					&queryctrl);
> +			if (!ret) {
> +				ctrls_found = realloc(ctrls_found,
> +					sizeof(*ctrls_found) * (num_ctrls + 1));
> +				ctrls_found[num_ctrls].queryctrl = queryctrl;
> +				ctrls_found[num_ctrls].entity = entity;
> +				++num_ctrls;
> +			}
> +
> +			entity = entity->next;
> +		}
> +
> +		if (num_ctrls == 0) {
> +			ret = -EINVAL;
> +			entity = NULL;
> +			goto done;
> +		}
> +
> +		qsort(ctrls_found, num_ctrls, sizeof(*ctrls_found), sort_ctrls);
> +
> +		queryctrl = ctrls_found[0].queryctrl;
> +		target_entity = ctrls_found[0].entity;
> +
> +		free(ctrls_found);
> +	}
> +
> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, queryctrl.id);
> +	if (entity)
> +		target_entity = entity;
> +
> +	ret = SYS_IOCTL(target_entity->sd->fd, VIDIOC_QUERYCTRL,
> +				&queryctrl);
> +
> +done:
> +	media_dbg(media,
> +		  "VIDIOC_QUERYCTRL [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
> +		  ret ? arg->id : queryctrl.id, ret ? NULL : queryctrl.name,
> +		  target_entity ? target_entity->info.name : NULL, ret);
> +
> +	*arg = queryctrl;
> +
> +	return ret;
> +}
> +
> +int media_ioctl_query_ext_ctrl(struct media_device *media,
> +			       struct v4l2_query_ext_ctrl *arg)
> +{
> +	struct media_entity *entity = media->pipeline, *target_entity;
> +	struct v4l2_query_ext_ctrl query_ext_ctrl = *arg;
> +	int ret = -EINVAL, num_ctrls = 0;
> +	struct media_entity_to_cid *ctrls_found;
> +
> +	/*
> +	 * If id is or'ed with V4L2_CTRL_FLAG_NEXT_CTRL then the control to
> +	 * be found is the one with the next lowest id among all entities
> +	 * in the pipeline.
> +	 */
> +	if (query_ext_ctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) {
> +		ctrls_found = malloc(sizeof(*ctrls_found));
> +
> +		while (entity) {
> +			query_ext_ctrl = *arg;
> +
> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERY_EXT_CTRL,
> +					&query_ext_ctrl.id);
> +			if (!ret) {
> +				ctrls_found = realloc(ctrls_found,
> +					sizeof(*ctrls_found) * (num_ctrls + 1));
> +				ctrls_found[num_ctrls].query_ext_ctrl =
> +								query_ext_ctrl;
> +				ctrls_found[num_ctrls].entity = entity;
> +				++num_ctrls;
> +			}
> +
> +			entity = entity->next;
> +		}
> +
> +		if (num_ctrls == 0) {
> +			ret = -EINVAL;
> +			entity = NULL;
> +			goto done;
> +		}
> +
> +		qsort(ctrls_found, num_ctrls, sizeof(*ctrls_found), sort_ctrls);
> +
> +		query_ext_ctrl = ctrls_found[0].query_ext_ctrl;
> +		target_entity = ctrls_found[0].entity;
> +
> +		free(ctrls_found);
> +	}
> +
> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, query_ext_ctrl.id);
> +	if (entity)
> +		target_entity = entity;
> +
> +	ret = SYS_IOCTL(target_entity->sd->fd, VIDIOC_QUERYCTRL,
> +				&query_ext_ctrl);
> +
> +done:
> +	media_dbg(media,
> +		  "VIDIOC_QUERY_EXT_CTRL [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
> +		  ret ? arg->id : query_ext_ctrl.id,
> +		  ret ? NULL : query_ext_ctrl.name,
> +		  target_entity ? target_entity->info.name : NULL, ret);
> +
> +	*arg = query_ext_ctrl;
> +
> +	return ret;
> +}
> +
> +int media_ioctl_querymenu(struct media_device *media,
> +			  struct v4l2_querymenu *arg)
> +{
> +	struct media_entity *entity = media->pipeline;
> +	struct v4l2_querymenu querymenu = *arg;
> +	int ret = -EINVAL;
> +
> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, querymenu.id);
> +	if (entity) {
> +		ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYMENU, &querymenu);
> +		goto exit;
> +	}
> +
> +	entity = media->pipeline;
> +
> +	while (entity) {
> +		ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYMENU, &querymenu);
> +		if (!ret)
> +			break;
> +
> +		entity = entity->next;
> +	}
> +
> +exit:
> +	*arg = querymenu;
> +
> +	media_dbg(media, "VIDIOC_QUERYMENU [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
> +		  querymenu.id, ret ? NULL : querymenu.name,
> +		  entity ? entity->info.name : NULL, ret);
> +
> +	return ret;
> +}
> diff --git a/utils/media-ctl/libv4l2media_ioctl.h b/utils/media-ctl/libv4l2media_ioctl.h
> new file mode 100644
> index 0000000..5501895
> --- /dev/null
> +++ b/utils/media-ctl/libv4l2media_ioctl.h
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
> + *              http://www.samsung.com
> + *
> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + */
> +
> +#ifndef __LIBV4L2MEDIA_IOCTL_H
> +#define __LIBV4L2MEDIA_IOCTL_H
> +
> +#include <linux/videodev2.h>
> +
> +struct media_device;
> +
> +struct media_entity_to_cid {
> +	struct media_entity *entity;
> +	union {
> +		struct v4l2_queryctrl queryctrl;
> +		struct v4l2_query_ext_ctrl query_ext_ctrl;
> +	};
> +};
> +
> +int media_ioctl_ctrl(struct media_device *media, int request,
> +			struct v4l2_control *arg);
> +
> +int media_ioctl_ext_ctrl(struct media_device *media, int request,
> +			struct v4l2_ext_controls *arg);
> +
> +int media_ioctl_queryctrl(struct media_device *media,
> +			struct v4l2_queryctrl *arg);
> +
> +int media_ioctl_query_ext_ctrl(struct media_device *media,
> +			struct v4l2_query_ext_ctrl *arg);
> +
> +int media_ioctl_querymenu(struct media_device *media,
> +			struct v4l2_querymenu *arg);
> +
> +#endif /* __LIBV4L2MEDIA_IOCTL_H */
> 


-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 05/15] mediactl: Add media device graph helpers
  2016-02-15 12:02   ` Sakari Ailus
@ 2016-02-15 12:45     ` Jacek Anaszewski
  2016-02-15 14:14       ` Sakari Ailus
  0 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-15 12:45 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

Thanks for the review.

On 02/15/2016 01:02 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> Jacek Anaszewski wrote:
>> Add new graph helpers useful for video pipeline discovering.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>   utils/media-ctl/libmediactl.c |   48 +++++++++++++++++++++++++++++++++++++++++
>>   utils/media-ctl/mediactl.h    |   36 +++++++++++++++++++++++++++++++
>>   2 files changed, 84 insertions(+)
>>
>> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
>> index 61b5f50..0be1845 100644
>> --- a/utils/media-ctl/libmediactl.c
>> +++ b/utils/media-ctl/libmediactl.c
>> @@ -35,6 +35,7 @@
>>   #include <unistd.h>
>>
>>   #include <linux/media.h>
>> +#include <linux/kdev_t.h>
>>   #include <linux/videodev2.h>
>>
>>   #include "mediactl.h"
>> @@ -87,6 +88,29 @@ struct media_entity *media_get_entity_by_name(struct media_device *media,
>>   	return NULL;
>>   }
>>
>> +struct media_entity *media_get_entity_by_devname(struct media_device *media,
>> +						 const char *devname,
>> +						 size_t length)
>> +{
>> +	unsigned int i;
>> +
>> +	/* A match is impossible if the entity devname is longer than the
>> +	 * maximum size we can get from the kernel.
>> +	 */
>> +	if (length >= FIELD_SIZEOF(struct media_entity, devname))
>> +		return NULL;
>> +
>> +	for (i = 0; i < media->entities_count; ++i) {
>> +		struct media_entity *entity = &media->entities[i];
>> +
>> +		if (strncmp(entity->devname, devname, length) == 0 &&
>> +		    entity->devname[length] == '\0')
>> +			return entity;
>> +	}
>> +
>> +	return NULL;
>> +}
>
> Just out of curiosity: where do you need this? I.e. why do you need to
> translate a device name to an entity?

It is needed in media_device_new_by_entity_devname() and directly in
libv4l-exynos4-camera.c, plugin_init(). Please especially refer to
the plugin_init(). You were asking about this in the review of v4
(over one year ago :) ), and I provided an explanation in the
following message [1].

>> +
>>   struct media_entity *media_get_entity_by_id(struct media_device *media,
>>   					    __u32 id)
>>   {
>> @@ -145,6 +169,11 @@ const char *media_entity_get_devname(struct media_entity *entity)
>>   	return entity->devname[0] ? entity->devname : NULL;
>>   }
>>
>> +const char *media_entity_get_name(struct media_entity *entity)
>> +{
>> +	return entity->info.name;
>> +}
>
> You should instead use media_get_info()->name . If you have an entity,
> the return value will be valid.

OK.

>> +
>>   struct media_entity *media_get_default_entity(struct media_device *media,
>>   					      unsigned int type)
>>   {
>> @@ -177,6 +206,25 @@ const struct media_entity_desc *media_entity_get_info(struct media_entity *entit
>>   	return &entity->info;
>>   }
>>
>> +int media_get_backlinks_by_entity(struct media_entity *entity,
>
> How about calling this media_entity_get_backlinks()?
>
>> +				struct media_link **backlinks,
>> +				int *num_backlinks)
>
> unsigned int.

OK.

>> +{
>> +	int num_bklinks = 0, i;
>
> Same here.

OK.

>> +
>> +	if (entity == NULL || backlinks == NULL || num_backlinks == NULL)
>> +		return -EINVAL;
>> +
>> +	for (i = 0; i < entity->num_links; ++i)
>> +		if ((entity->links[i].flags & MEDIA_LNK_FL_ENABLED) &&
>> +		    (entity->links[i].sink->entity == entity))
>> +			backlinks[num_bklinks++] = &entity->links[i];
>> +
>> +	*num_backlinks = num_bklinks;
>> +
>> +	return 0;
>> +}
>> +
>>   /* -----------------------------------------------------------------------------
>>    * Open/close
>>    */
>> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
>> index 3faee71..9db40a8 100644
>> --- a/utils/media-ctl/mediactl.h
>> +++ b/utils/media-ctl/mediactl.h
>> @@ -231,6 +231,15 @@ const struct media_link *media_entity_get_link(struct media_entity *entity,
>>   const char *media_entity_get_devname(struct media_entity *entity);
>>
>>   /**
>> + * @brief Get the name for an entity
>> + * @param entity - media entity.
>> + *
>> + * This function returns the name of the entity.
>> + *
>> + * @return A pointer to the string with entity name
>> + */
>> +const char *media_entity_get_name(struct media_entity *entity);
>> +
>>    * @brief Get the type of an entity.
>>    * @param entity - the entity.
>>    *
>> @@ -255,6 +264,19 @@ struct media_entity *media_get_entity_by_name(struct media_device *media,
>>   	const char *name, size_t length);
>>
>>   /**
>> + * @brief Find an entity by the corresponding device node name.
>> + * @param media - media device.
>> + * @param devname - device node name.
>> + * @param length - size of @a devname.
>> + *
>> + * Search for an entity with a device node name equal to @a devname.
>> + *
>> + * @return A pointer to the entity if found, or NULL otherwise.
>> + */
>> +struct media_entity *media_get_entity_by_devname(struct media_device *media,
>> +	const char *devname, size_t length);
>> +
>> +/**
>>    * @brief Find an entity by its ID.
>>    * @param media - media device.
>>    * @param id - entity ID.
>> @@ -434,4 +456,18 @@ int media_parse_setup_link(struct media_device *media,
>>    */
>>   int media_parse_setup_links(struct media_device *media, const char *p);
>>
>> +/**
>> + * @brief Get entity's enabled backlinks
>> + * @param entity - media entity.
>> + * @param backlinks - array of pointers to matching backlinks.
>> + * @param num_backlinks - number of matching backlinks.
>> + *
>> + * Get links that are connected to the entity sink pads.
>> + *
>> + * @return 0 on success, or a negative error code on failure.
>> + */
>> +int media_get_backlinks_by_entity(struct media_entity *entity,
>> +				struct media_link **backlinks,
>> +				int *num_backlinks);
>> +
>>   #endif
>>
>
>

[1] 
http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/88446

-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-02-15 12:41   ` Sakari Ailus
@ 2016-02-15 13:06     ` Jacek Anaszewski
  2016-02-18 12:09       ` Sakari Ailus
  0 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-15 13:06 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

Thanks for the review.

On 02/15/2016 01:41 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> Jacek Anaszewski wrote:
>> Ioctls executed on complex media devices need special handling.
>> For instance some ioctls need to be targeted for specific sub-devices,
>> depending on the media device configuration. The APIs being introduced
>> address such requirements.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>   utils/media-ctl/Makefile.am          |    2 +-
>>   utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
>>   utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
>>   3 files changed, 453 insertions(+), 1 deletion(-)
>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
>>
>> diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
>> index 3e883e0..7f18624 100644
>> --- a/utils/media-ctl/Makefile.am
>> +++ b/utils/media-ctl/Makefile.am
>> @@ -1,6 +1,6 @@
>>   noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
>>
>> -libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
>> +libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
>>   libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
>>   libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
>>
>> diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
>> new file mode 100644
>> index 0000000..b186121
>> --- /dev/null
>> +++ b/utils/media-ctl/libv4l2media_ioctl.c
>> @@ -0,0 +1,404 @@
>> +/*
>> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
>> + *              http://www.samsung.com
>> + *
>> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU Lesser General Public License as published by
>> + * the Free Software Foundation; either version 2.1 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + */
>> +
>> +#include <errno.h>
>> +#include <stdlib.h>
>> +#include <sys/syscall.h>
>> +#include <unistd.h>
>> +
>> +#include <linux/videodev2.h>
>> +
>> +#include "libv4l2media_ioctl.h"
>> +#include "mediactl-priv.h"
>> +#include "mediactl.h"
>> +#include "v4l2subdev.h"
>> +
>> +#define VIDIOC_CTRL(type)					\
>> +	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
>> +				   "VIDIOC_G_CTRL")
>> +
>> +#define VIDIOC_EXT_CTRL(type)					\
>> +	((type) == VIDIOC_S_EXT_CTRLS ? 			\
>> +		"VIDIOC_S_EXT_CTRLS"	:			\
>> +		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
>> +				    "VIDIOC_G_EXT_CTRLS" :	\
>> +				    "VIDIOC_TRY_EXT_CTRLS"))
>> +
>> +#define SYS_IOCTL(fd, cmd, arg) \
>> +	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
>> +
>> +
>> +int media_ioctl_ctrl(struct media_device *media, int request,
>
> unsigned int request

OK.

>
>> +		     struct v4l2_control *arg)
>
> I wonder if it'd make sense to always use v4l2_ext_control instead. You
> can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.

This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
For ext ctrls there is media_ioctl_ext_ctrl().

> As this is a user space library, I'd probably add a function to handle
> S/G/TRY control each.

There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.

> Have you considered binding the control to a video node rather than a
> media device? We have many sensors on current media devices already, and
> e.g. exposure time control can be found in multiple sub-devices.

Doesn't v4l2-ctrl-redir config entry address that?

>> +{
>> +	struct media_entity *entity = media->pipeline;
>> +	struct v4l2_control ctrl = *arg;
>> +	struct v4l2_queryctrl queryctrl;
>> +	bool ctrl_found = 0;
>> +	int ret;
>> +
>> +	/*
>> +	 * The control has to be reset to the default value
>> +	 * on all of the pipeline entities, prior setting a new
>> +	 * value. This is required in cases when the control config
>> +	 * is changed between subsequent calls to VIDIOC_S_CTRL,
>> +	 * to avoid the situation when a control is set on more
>> +	 * than one sub-device.
>> +	 */
>> +	if (request == VIDIOC_S_CTRL) {
>> +		while (entity) {
>> +			queryctrl.id = ctrl.id;
>> +
>> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYCTRL,
>> +					&queryctrl);
>> +			if (ret < 0) {
>> +				entity = entity->next;
>> +				continue;
>> +			}
>> +
>> +			ctrl_found = true;
>> +
>> +			if (queryctrl.type & V4L2_CTRL_TYPE_BUTTON)
>> +				break;
>> +
>> +			ctrl.value = queryctrl.default_value;
>> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_S_CTRL, &ctrl);
>> +			if (ret < 0)
>> +				return -EINVAL;
>> +
>> +			entity = entity->next;
>> +		}
>> +
>> +		ctrl.value = arg->value;
>> +	}
>> +
>> +	if (!ctrl_found) {
>> +		ret = -EINVAL;
>> +		goto exit;
>> +	}
>> +
>> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, ctrl.id);
>> +
>> +	if (entity) {
>> +		ret = SYS_IOCTL(entity->sd->fd, request, &ctrl);
>> +	} else {
>> +		/* Walk the pipeline until the request succeeds */
>> +		entity = media->pipeline;
>> +
>> +		ret = -ENOENT;
>> +
>> +		while (entity) {
>> +			ret = SYS_IOCTL(entity->sd->fd, request, &ctrl);
>> +			if (!ret)
>> +				break;
>> +
>> +			entity = entity->next;
>> +		}
>> +	}
>> +
>> +exit:
>> +	*arg = ctrl;
>> +
>> +	media_dbg(media, "%s [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
>> +		  VIDIOC_CTRL(request), ctrl.id, ret ? NULL : queryctrl.name,
>> +		  entity ? entity->info.name : NULL, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static int media_ioctl_single_ext_ctrl(struct media_device *media,
>> +				int request, struct v4l2_ext_controls *arg)
>> +{
>> +	struct media_entity *entity = media->pipeline;
>> +	struct v4l2_ext_controls ctrls = *arg;
>> +	struct v4l2_ext_control *ctrl;
>> +	struct v4l2_query_ext_ctrl queryctrl;
>> +	bool ctrl_found = 0;
>> +	int ret = -EINVAL;
>> +
>> +	ctrl = &ctrls.controls[0];
>> +
>> +	/*
>> +	 * The control has to be reset to the default value
>> +	 * on all of the pipeline entities, prior setting a new
>> +	 * value. This is required in cases when the control config
>> +	 * is changed between subsequent calls to VIDIOC_S_EXT_CTRLS,
>> +	 * to avoid the situation when a control is set on more
>> +	 * than one sub-device.
>> +	 */
>> +	if (request == VIDIOC_S_EXT_CTRLS) {
>> +		while (entity) {
>> +			queryctrl.id = ctrl->id;
>> +
>> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERY_EXT_CTRL,
>> +					&queryctrl);
>> +			if (ret < 0) {
>> +				entity = entity->next;
>> +				continue;
>> +			}
>> +
>> +			ctrl_found = true;
>> +
>> +			if (queryctrl.type & V4L2_CTRL_TYPE_BUTTON)
>> +				break;
>> +
>> +			ctrl->value64 = queryctrl.default_value;
>> +
>> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_S_EXT_CTRLS,
>> +					&ctrls);
>> +			if (ret < 0)
>> +				return -EINVAL;
>> +
>> +			entity = entity->next;
>> +		}
>> +
>> +		ctrl->value64 = arg->controls[0].value64;
>> +	}
>> +
>> +	if (!ctrl_found) {
>> +		ret = -EINVAL;
>> +		goto exit;
>> +	}
>> +
>> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, ctrl->id);
>> +
>> +	if (entity) {
>> +		ret = SYS_IOCTL(entity->sd->fd, request, &ctrls);
>> +	} else {
>> +		/* Walk the pipeline until the request succeeds */
>> +		entity = media->pipeline;
>> +
>> +		while (entity) {
>> +			ret = SYS_IOCTL(entity->sd->fd, request, &ctrls);
>> +			if (!ret)
>> +				break;
>> +
>> +			entity = entity->next;
>> +		}
>> +	}
>> +
>> +exit:
>> +	*arg = ctrls;
>> +
>> +	media_dbg(media, "%s [id: 0x%8.8x, entity: %s] (%d)\n",
>> +		  VIDIOC_EXT_CTRL(request), ctrl->id,
>> +		  entity ? entity->info.name : NULL, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +int media_ioctl_ext_ctrl(struct media_device *media, int request,
>> +			 struct v4l2_ext_controls *arg)
>> +{
>> +	struct v4l2_ext_controls out_ctrls = *arg, ctrls = *arg;
>> +	int ret = -EINVAL, i;
>> +
>> +	ctrls.count = 1;
>> +
>> +	/*
>> +	 * Split cluster to individual ioctl calls for each control
>> +	 * from the array, to make possible redirection of every
>> +	 * single control to different sub-device, according to the
>> +	 * configuration settings.
>> +	 */
>> +	for (i = 0; i < arg->count; ++i) {
>> +		ctrls.controls = &arg->controls[i];
>> +
>> +		ret = media_ioctl_single_ext_ctrl(media, request, &ctrls);
>> +		out_ctrls.controls[i] = ctrls.controls[i];
>> +		if (ret < 0) {
>> +			if (ctrls.error_idx == 1)
>> +				out_ctrls.error_idx = ctrls.count;
>> +			else
>> +				out_ctrls.error_idx = i;
>> +			break;
>> +		}
>> +	}
>> +
>> +	*arg = out_ctrls;
>> +	return ret;
>> +}
>> +
>> +int sort_ctrls(const void * a, const void * b)
>> +{
>> +	const struct media_entity_to_cid *ctrl_a = a, *ctrl_b = b;
>> +
>> +	return ctrl_a->queryctrl.id - ctrl_b->queryctrl.id;
>> +}
>> +
>> +int media_ioctl_queryctrl(struct media_device *media,
>> +			  struct v4l2_queryctrl *arg)
>> +{
>> +	struct media_entity *entity = media->pipeline, *target_entity;
>> +	struct v4l2_queryctrl queryctrl = *arg;
>> +	int ret = -EINVAL, num_ctrls = 0;
>> +	struct media_entity_to_cid *ctrls_found;
>> +
>> +	/*
>> +	 * If id is or'ed with V4L2_CTRL_FLAG_NEXT_CTRL then the control to
>> +	 * be found is the one with the next lowest id among all entities
>> +	 * in the pipeline.
>> +	 */
>> +	if (queryctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) {
>> +		ctrls_found = malloc(sizeof(*ctrls_found));
>> +
>> +		while (entity) {
>> +			queryctrl = *arg;
>> +
>> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYCTRL,
>> +					&queryctrl);
>> +			if (!ret) {
>> +				ctrls_found = realloc(ctrls_found,
>> +					sizeof(*ctrls_found) * (num_ctrls + 1));
>> +				ctrls_found[num_ctrls].queryctrl = queryctrl;
>> +				ctrls_found[num_ctrls].entity = entity;
>> +				++num_ctrls;
>> +			}
>> +
>> +			entity = entity->next;
>> +		}
>> +
>> +		if (num_ctrls == 0) {
>> +			ret = -EINVAL;
>> +			entity = NULL;
>> +			goto done;
>> +		}
>> +
>> +		qsort(ctrls_found, num_ctrls, sizeof(*ctrls_found), sort_ctrls);
>> +
>> +		queryctrl = ctrls_found[0].queryctrl;
>> +		target_entity = ctrls_found[0].entity;
>> +
>> +		free(ctrls_found);
>> +	}
>> +
>> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, queryctrl.id);
>> +	if (entity)
>> +		target_entity = entity;
>> +
>> +	ret = SYS_IOCTL(target_entity->sd->fd, VIDIOC_QUERYCTRL,
>> +				&queryctrl);
>> +
>> +done:
>> +	media_dbg(media,
>> +		  "VIDIOC_QUERYCTRL [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
>> +		  ret ? arg->id : queryctrl.id, ret ? NULL : queryctrl.name,
>> +		  target_entity ? target_entity->info.name : NULL, ret);
>> +
>> +	*arg = queryctrl;
>> +
>> +	return ret;
>> +}
>> +
>> +int media_ioctl_query_ext_ctrl(struct media_device *media,
>> +			       struct v4l2_query_ext_ctrl *arg)
>> +{
>> +	struct media_entity *entity = media->pipeline, *target_entity;
>> +	struct v4l2_query_ext_ctrl query_ext_ctrl = *arg;
>> +	int ret = -EINVAL, num_ctrls = 0;
>> +	struct media_entity_to_cid *ctrls_found;
>> +
>> +	/*
>> +	 * If id is or'ed with V4L2_CTRL_FLAG_NEXT_CTRL then the control to
>> +	 * be found is the one with the next lowest id among all entities
>> +	 * in the pipeline.
>> +	 */
>> +	if (query_ext_ctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) {
>> +		ctrls_found = malloc(sizeof(*ctrls_found));
>> +
>> +		while (entity) {
>> +			query_ext_ctrl = *arg;
>> +
>> +			ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERY_EXT_CTRL,
>> +					&query_ext_ctrl.id);
>> +			if (!ret) {
>> +				ctrls_found = realloc(ctrls_found,
>> +					sizeof(*ctrls_found) * (num_ctrls + 1));
>> +				ctrls_found[num_ctrls].query_ext_ctrl =
>> +								query_ext_ctrl;
>> +				ctrls_found[num_ctrls].entity = entity;
>> +				++num_ctrls;
>> +			}
>> +
>> +			entity = entity->next;
>> +		}
>> +
>> +		if (num_ctrls == 0) {
>> +			ret = -EINVAL;
>> +			entity = NULL;
>> +			goto done;
>> +		}
>> +
>> +		qsort(ctrls_found, num_ctrls, sizeof(*ctrls_found), sort_ctrls);
>> +
>> +		query_ext_ctrl = ctrls_found[0].query_ext_ctrl;
>> +		target_entity = ctrls_found[0].entity;
>> +
>> +		free(ctrls_found);
>> +	}
>> +
>> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, query_ext_ctrl.id);
>> +	if (entity)
>> +		target_entity = entity;
>> +
>> +	ret = SYS_IOCTL(target_entity->sd->fd, VIDIOC_QUERYCTRL,
>> +				&query_ext_ctrl);
>> +
>> +done:
>> +	media_dbg(media,
>> +		  "VIDIOC_QUERY_EXT_CTRL [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
>> +		  ret ? arg->id : query_ext_ctrl.id,
>> +		  ret ? NULL : query_ext_ctrl.name,
>> +		  target_entity ? target_entity->info.name : NULL, ret);
>> +
>> +	*arg = query_ext_ctrl;
>> +
>> +	return ret;
>> +}
>> +
>> +int media_ioctl_querymenu(struct media_device *media,
>> +			  struct v4l2_querymenu *arg)
>> +{
>> +	struct media_entity *entity = media->pipeline;
>> +	struct v4l2_querymenu querymenu = *arg;
>> +	int ret = -EINVAL;
>> +
>> +	entity = v4l2_subdev_get_pipeline_entity_by_cid(media, querymenu.id);
>> +	if (entity) {
>> +		ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYMENU, &querymenu);
>> +		goto exit;
>> +	}
>> +
>> +	entity = media->pipeline;
>> +
>> +	while (entity) {
>> +		ret = SYS_IOCTL(entity->sd->fd, VIDIOC_QUERYMENU, &querymenu);
>> +		if (!ret)
>> +			break;
>> +
>> +		entity = entity->next;
>> +	}
>> +
>> +exit:
>> +	*arg = querymenu;
>> +
>> +	media_dbg(media, "VIDIOC_QUERYMENU [id: 0x%8.8x, name: %s, entity: %s] (%d)\n",
>> +		  querymenu.id, ret ? NULL : querymenu.name,
>> +		  entity ? entity->info.name : NULL, ret);
>> +
>> +	return ret;
>> +}
>> diff --git a/utils/media-ctl/libv4l2media_ioctl.h b/utils/media-ctl/libv4l2media_ioctl.h
>> new file mode 100644
>> index 0000000..5501895
>> --- /dev/null
>> +++ b/utils/media-ctl/libv4l2media_ioctl.h
>> @@ -0,0 +1,48 @@
>> +/*
>> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
>> + *              http://www.samsung.com
>> + *
>> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU Lesser General Public License as published by
>> + * the Free Software Foundation; either version 2.1 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + */
>> +
>> +#ifndef __LIBV4L2MEDIA_IOCTL_H
>> +#define __LIBV4L2MEDIA_IOCTL_H
>> +
>> +#include <linux/videodev2.h>
>> +
>> +struct media_device;
>> +
>> +struct media_entity_to_cid {
>> +	struct media_entity *entity;
>> +	union {
>> +		struct v4l2_queryctrl queryctrl;
>> +		struct v4l2_query_ext_ctrl query_ext_ctrl;
>> +	};
>> +};
>> +
>> +int media_ioctl_ctrl(struct media_device *media, int request,
>> +			struct v4l2_control *arg);
>> +
>> +int media_ioctl_ext_ctrl(struct media_device *media, int request,
>> +			struct v4l2_ext_controls *arg);
>> +
>> +int media_ioctl_queryctrl(struct media_device *media,
>> +			struct v4l2_queryctrl *arg);
>> +
>> +int media_ioctl_query_ext_ctrl(struct media_device *media,
>> +			struct v4l2_query_ext_ctrl *arg);
>> +
>> +int media_ioctl_querymenu(struct media_device *media,
>> +			struct v4l2_querymenu *arg);
>> +
>> +#endif /* __LIBV4L2MEDIA_IOCTL_H */
>>
>
>


-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 05/15] mediactl: Add media device graph helpers
  2016-02-15 12:45     ` Jacek Anaszewski
@ 2016-02-15 14:14       ` Sakari Ailus
  2016-02-15 14:57         ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 14:14 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

Jacek Anaszewski wrote:
> Hi Sakari,
> 
> Thanks for the review.
> 
> On 02/15/2016 01:02 PM, Sakari Ailus wrote:
>> Hi Jacek,
>>
>> Jacek Anaszewski wrote:
>>> Add new graph helpers useful for video pipeline discovering.
>>>
>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>> ---
>>>   utils/media-ctl/libmediactl.c |   48
>>> +++++++++++++++++++++++++++++++++++++++++
>>>   utils/media-ctl/mediactl.h    |   36 +++++++++++++++++++++++++++++++
>>>   2 files changed, 84 insertions(+)
>>>
>>> diff --git a/utils/media-ctl/libmediactl.c
>>> b/utils/media-ctl/libmediactl.c
>>> index 61b5f50..0be1845 100644
>>> --- a/utils/media-ctl/libmediactl.c
>>> +++ b/utils/media-ctl/libmediactl.c
>>> @@ -35,6 +35,7 @@
>>>   #include <unistd.h>
>>>
>>>   #include <linux/media.h>
>>> +#include <linux/kdev_t.h>
>>>   #include <linux/videodev2.h>
>>>
>>>   #include "mediactl.h"
>>> @@ -87,6 +88,29 @@ struct media_entity
>>> *media_get_entity_by_name(struct media_device *media,
>>>       return NULL;
>>>   }
>>>
>>> +struct media_entity *media_get_entity_by_devname(struct media_device
>>> *media,
>>> +                         const char *devname,
>>> +                         size_t length)
>>> +{
>>> +    unsigned int i;
>>> +
>>> +    /* A match is impossible if the entity devname is longer than the
>>> +     * maximum size we can get from the kernel.
>>> +     */
>>> +    if (length >= FIELD_SIZEOF(struct media_entity, devname))
>>> +        return NULL;
>>> +
>>> +    for (i = 0; i < media->entities_count; ++i) {
>>> +        struct media_entity *entity = &media->entities[i];
>>> +
>>> +        if (strncmp(entity->devname, devname, length) == 0 &&
>>> +            entity->devname[length] == '\0')
>>> +            return entity;
>>> +    }
>>> +
>>> +    return NULL;
>>> +}
>>
>> Just out of curiosity: where do you need this? I.e. why do you need to
>> translate a device name to an entity?
> 
> It is needed in media_device_new_by_entity_devname() and directly in
> libv4l-exynos4-camera.c, plugin_init(). Please especially refer to
> the plugin_init(). You were asking about this in the review of v4
> (over one year ago :) ), and I provided an explanation in the
> following message [1].

That's a bit long review time indeed. :-P

You have the sub-device fd. Obtaining major and minor using fstat, you
can find the relevant sub-device in sysfs without having to open all the
media devices. Once you have that, you can use the sysfs link to the
media device, and obtain the media device major and minor.

E.g.

$ cat /sys/class/video4linux/v4l-subdev0/dev
81:20
$ cat /sys/class/video4linux/v4l-subdev0/device/media0/dev
248:0

Additionally, you avoid assuming your media devices will be /dev/media*.
In sysfs the files are always in the same locations independently of the
user space file system layout (with the exception of /sys itself).

> 
>>> +
>>>   struct media_entity *media_get_entity_by_id(struct media_device
>>> *media,
>>>                           __u32 id)
>>>   {
>>> @@ -145,6 +169,11 @@ const char *media_entity_get_devname(struct
>>> media_entity *entity)
>>>       return entity->devname[0] ? entity->devname : NULL;
>>>   }
>>>
>>> +const char *media_entity_get_name(struct media_entity *entity)
>>> +{
>>> +    return entity->info.name;
>>> +}
>>
>> You should instead use media_get_info()->name . If you have an entity,
>> the return value will be valid.
> 
> OK.
> 
>>> +
>>>   struct media_entity *media_get_default_entity(struct media_device
>>> *media,
>>>                             unsigned int type)
>>>   {
>>> @@ -177,6 +206,25 @@ const struct media_entity_desc
>>> *media_entity_get_info(struct media_entity *entit
>>>       return &entity->info;
>>>   }
>>>
>>> +int media_get_backlinks_by_entity(struct media_entity *entity,
>>
>> How about calling this media_entity_get_backlinks()?

^

>>
>>> +                struct media_link **backlinks,
>>> +                int *num_backlinks)
>>
>> unsigned int.
> 
> OK.
> 
>>> +{
>>> +    int num_bklinks = 0, i;
>>
>> Same here.
> 
> OK.
> 
>>> +
>>> +    if (entity == NULL || backlinks == NULL || num_backlinks == NULL)
>>> +        return -EINVAL;
>>> +
>>> +    for (i = 0; i < entity->num_links; ++i)
>>> +        if ((entity->links[i].flags & MEDIA_LNK_FL_ENABLED) &&
>>> +            (entity->links[i].sink->entity == entity))
>>> +            backlinks[num_bklinks++] = &entity->links[i];
>>> +
>>> +    *num_backlinks = num_bklinks;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>>   /*
>>> -----------------------------------------------------------------------------
>>>
>>>    * Open/close
>>>    */
>>> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
>>> index 3faee71..9db40a8 100644
>>> --- a/utils/media-ctl/mediactl.h
>>> +++ b/utils/media-ctl/mediactl.h
>>> @@ -231,6 +231,15 @@ const struct media_link
>>> *media_entity_get_link(struct media_entity *entity,
>>>   const char *media_entity_get_devname(struct media_entity *entity);
>>>
>>>   /**
>>> + * @brief Get the name for an entity
>>> + * @param entity - media entity.
>>> + *
>>> + * This function returns the name of the entity.
>>> + *
>>> + * @return A pointer to the string with entity name
>>> + */
>>> +const char *media_entity_get_name(struct media_entity *entity);
>>> +
>>>    * @brief Get the type of an entity.
>>>    * @param entity - the entity.
>>>    *
>>> @@ -255,6 +264,19 @@ struct media_entity
>>> *media_get_entity_by_name(struct media_device *media,
>>>       const char *name, size_t length);
>>>
>>>   /**
>>> + * @brief Find an entity by the corresponding device node name.
>>> + * @param media - media device.
>>> + * @param devname - device node name.
>>> + * @param length - size of @a devname.
>>> + *
>>> + * Search for an entity with a device node name equal to @a devname.
>>> + *
>>> + * @return A pointer to the entity if found, or NULL otherwise.
>>> + */
>>> +struct media_entity *media_get_entity_by_devname(struct media_device
>>> *media,
>>> +    const char *devname, size_t length);
>>> +
>>> +/**
>>>    * @brief Find an entity by its ID.
>>>    * @param media - media device.
>>>    * @param id - entity ID.
>>> @@ -434,4 +456,18 @@ int media_parse_setup_link(struct media_device
>>> *media,
>>>    */
>>>   int media_parse_setup_links(struct media_device *media, const char
>>> *p);
>>>
>>> +/**
>>> + * @brief Get entity's enabled backlinks
>>> + * @param entity - media entity.
>>> + * @param backlinks - array of pointers to matching backlinks.
>>> + * @param num_backlinks - number of matching backlinks.
>>> + *
>>> + * Get links that are connected to the entity sink pads.
>>> + *
>>> + * @return 0 on success, or a negative error code on failure.
>>> + */
>>> +int media_get_backlinks_by_entity(struct media_entity *entity,
>>> +                struct media_link **backlinks,
>>> +                int *num_backlinks);
>>> +
>>>   #endif
>>>
>>
>>
> 
> [1]
> http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/88446
> 
> 


-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 06/15] mediactl: Add media_device creation helpers
  2016-01-18 16:17 ` [PATCH 06/15] mediactl: Add media_device creation helpers Jacek Anaszewski
@ 2016-02-15 14:30   ` Sakari Ailus
  0 siblings, 0 replies; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 14:30 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Mon, Jan 18, 2016 at 05:17:31PM +0100, Jacek Anaszewski wrote:
> Add helper functions that allow for easy instantiation of media_device
> object basing on whether the media device contains video device with
> given node name.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/libmediactl.c |   75 +++++++++++++++++++++++++++++++++++++++++
>  utils/media-ctl/mediactl.h    |   30 +++++++++++++++++
>  2 files changed, 105 insertions(+)
> 
> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
> index 0be1845..3a45ecc 100644
> --- a/utils/media-ctl/libmediactl.c
> +++ b/utils/media-ctl/libmediactl.c
> @@ -734,6 +734,44 @@ struct media_device *media_device_new(const char *devnode)
>  	return media;
>  }
>  
> +struct media_device *media_device_new_by_entity_devname(char *entity_devname)

const char *...

> +{
> +	struct media_device *media;
> +	char media_devname[32];
> +	struct media_entity *entity;
> +	int i, ret;

unsigned int i

> +
> +	/* query all available media devices */
> +	for (i = 0;; ++i) {
> +		sprintf(media_devname, "/dev/media%d", i);
> +
> +		media = media_device_new(media_devname);
> +		if (media == NULL)
> +			return NULL;
> +
> +		ret = media_device_enumerate(media);
> +		if (ret < 0) {
> +			media_dbg(media, "Failed to enumerate %s (%d)\n",
> +				  media_devname, ret);
> +			goto err_dev_enum;
> +		}
> +
> +		/* Check if the media device contains entity with entity_devname */
> +		entity = media_get_entity_by_devname(media, entity_devname,
> +							strlen(entity_devname));
> +		if (entity)
> +			return media;
> +
> +		if (media)
> +			media_device_unref(media);
> +	}
> +
> +err_dev_enum:
> +	if (media)
> +		media_device_unref(media);
> +	return NULL;
> +}
> +
>  struct media_device *media_device_new_emulated(struct media_device_info *info)
>  {
>  	struct media_device *media;
> @@ -773,6 +811,43 @@ void media_device_unref(struct media_device *media)
>  	free(media);
>  }
>  
> +int media_get_devname_by_fd(int fd, char *node_name)
> +{
> +	struct udev *udev;
> +	struct media_entity tmp_entity;
> +	struct stat stat;
> +	int ret;
> +
> +	if (node_name == NULL)
> +		return -EINVAL;
> +
> +	ret = fstat(fd, &stat);
> +	if (ret < 0)
> +		return -EINVAL;

return -errno

> +
> +	tmp_entity.info.v4l.major = MAJOR(stat.st_rdev);
> +	tmp_entity.info.v4l.minor = MINOR(stat.st_rdev);
> +
> +	ret = media_udev_open(&udev);
> +	if (ret < 0)
> +		printf("Can't get udev context\n");

If this fails, you shouldn't call media_get_devname_udev() below, nor
media_udev_close().

> +
> +	/* Try to get the device name via udev */
> +	ret = media_get_devname_udev(udev, &tmp_entity);
> +	if (!ret)
> +		goto out;
> +
> +	ret = media_get_devname_sysfs(&tmp_entity);
> +	if (ret < 0)
> +		goto err_get_devname;
> +
> +out:
> +	strcpy(node_name, tmp_entity.devname);

You have to ensure node_name is long enough.

> +err_get_devname:
> +	media_udev_close(udev);
> +	return ret;
> +}
> +
>  int media_device_add_entity(struct media_device *media,
>  			    const struct media_entity_desc *desc,
>  			    const char *devnode)
> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
> index 9db40a8..1d62191 100644
> --- a/utils/media-ctl/mediactl.h
> +++ b/utils/media-ctl/mediactl.h
> @@ -76,6 +76,23 @@ struct media_device *media_device_new(const char *devnode);
>  struct media_device *media_device_new_emulated(struct media_device_info *info);
>  
>  /**
> + * @brief Create a new media device if it comprises entity with given devname
> + * @param entity_devname - device node name of the entity to be matched.
> + *
> + * Query all media devices available in the system to find the one comprising
> + * the entity with given devname. If the media device is matched then its
> + * instance is created and initialized with enumerated entities and links.
> + * The returned device can be accessed.
> + *
> + * Media devices are reference-counted, see media_device_ref() and
> + * media_device_unref() for more information.
> + *
> + * @return A pointer to the new media device or NULL if video_devname cannot
> + * be matched or memory cannot be allocated.
> + */
> +struct media_device *media_device_new_by_entity_devname(char *entity_devname);
> +
> +/**
>   * @brief Take a reference to the device.
>   * @param media - device instance.
>   *
> @@ -240,6 +257,19 @@ const char *media_entity_get_devname(struct media_entity *entity);
>   */
>  const char *media_entity_get_name(struct media_entity *entity);
>  
> +/**
> + * @brief Get the device node name by its file descriptor
> + * @param fd - file descriptor of a device.
> + * @param node_name - output device node name string.
> + *
> + * This function returns the full path and name to the device node corresponding
> + * to the given file descriptor.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +int media_get_devname_by_fd(int fd, char *node_name);
> +
> +/**
>   * @brief Get the type of an entity.
>   * @param entity - the entity.
>   *

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 05/15] mediactl: Add media device graph helpers
  2016-02-15 14:14       ` Sakari Ailus
@ 2016-02-15 14:57         ` Jacek Anaszewski
  0 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-15 14:57 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

On 02/15/2016 03:14 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> Jacek Anaszewski wrote:
>> Hi Sakari,
>>
>> Thanks for the review.
>>
>> On 02/15/2016 01:02 PM, Sakari Ailus wrote:
>>> Hi Jacek,
>>>
>>> Jacek Anaszewski wrote:
>>>> Add new graph helpers useful for video pipeline discovering.
>>>>
>>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>>> ---
>>>>    utils/media-ctl/libmediactl.c |   48
>>>> +++++++++++++++++++++++++++++++++++++++++
>>>>    utils/media-ctl/mediactl.h    |   36 +++++++++++++++++++++++++++++++
>>>>    2 files changed, 84 insertions(+)
>>>>
>>>> diff --git a/utils/media-ctl/libmediactl.c
>>>> b/utils/media-ctl/libmediactl.c
>>>> index 61b5f50..0be1845 100644
>>>> --- a/utils/media-ctl/libmediactl.c
>>>> +++ b/utils/media-ctl/libmediactl.c
>>>> @@ -35,6 +35,7 @@
>>>>    #include <unistd.h>
>>>>
>>>>    #include <linux/media.h>
>>>> +#include <linux/kdev_t.h>
>>>>    #include <linux/videodev2.h>
>>>>
>>>>    #include "mediactl.h"
>>>> @@ -87,6 +88,29 @@ struct media_entity
>>>> *media_get_entity_by_name(struct media_device *media,
>>>>        return NULL;
>>>>    }
>>>>
>>>> +struct media_entity *media_get_entity_by_devname(struct media_device
>>>> *media,
>>>> +                         const char *devname,
>>>> +                         size_t length)
>>>> +{
>>>> +    unsigned int i;
>>>> +
>>>> +    /* A match is impossible if the entity devname is longer than the
>>>> +     * maximum size we can get from the kernel.
>>>> +     */
>>>> +    if (length >= FIELD_SIZEOF(struct media_entity, devname))
>>>> +        return NULL;
>>>> +
>>>> +    for (i = 0; i < media->entities_count; ++i) {
>>>> +        struct media_entity *entity = &media->entities[i];
>>>> +
>>>> +        if (strncmp(entity->devname, devname, length) == 0 &&
>>>> +            entity->devname[length] == '\0')
>>>> +            return entity;
>>>> +    }
>>>> +
>>>> +    return NULL;
>>>> +}
>>>
>>> Just out of curiosity: where do you need this? I.e. why do you need to
>>> translate a device name to an entity?
>>
>> It is needed in media_device_new_by_entity_devname() and directly in
>> libv4l-exynos4-camera.c, plugin_init(). Please especially refer to
>> the plugin_init(). You were asking about this in the review of v4
>> (over one year ago :) ), and I provided an explanation in the
>> following message [1].
>
> That's a bit long review time indeed. :-P
>
> You have the sub-device fd. Obtaining major and minor using fstat, you
> can find the relevant sub-device in sysfs without having to open all the
> media devices. Once you have that, you can use the sysfs link to the
> media device, and obtain the media device major and minor.
>
> E.g.
>
> $ cat /sys/class/video4linux/v4l-subdev0/dev
> 81:20
> $ cat /sys/class/video4linux/v4l-subdev0/device/media0/dev
> 248:0
>
> Additionally, you avoid assuming your media devices will be /dev/media*.
> In sysfs the files are always in the same locations independently of the
> user space file system layout (with the exception of /sys itself).

Thanks for the hints. I'll change the code accordingly.

>>
>>>> +
>>>>    struct media_entity *media_get_entity_by_id(struct media_device
>>>> *media,
>>>>                            __u32 id)
>>>>    {
>>>> @@ -145,6 +169,11 @@ const char *media_entity_get_devname(struct
>>>> media_entity *entity)
>>>>        return entity->devname[0] ? entity->devname : NULL;
>>>>    }
>>>>
>>>> +const char *media_entity_get_name(struct media_entity *entity)
>>>> +{
>>>> +    return entity->info.name;
>>>> +}
>>>
>>> You should instead use media_get_info()->name . If you have an entity,
>>> the return value will be valid.
>>
>> OK.
>>
>>>> +
>>>>    struct media_entity *media_get_default_entity(struct media_device
>>>> *media,
>>>>                              unsigned int type)
>>>>    {
>>>> @@ -177,6 +206,25 @@ const struct media_entity_desc
>>>> *media_entity_get_info(struct media_entity *entit
>>>>        return &entity->info;
>>>>    }
>>>>
>>>> +int media_get_backlinks_by_entity(struct media_entity *entity,
>>>
>>> How about calling this media_entity_get_backlinks()?
>
> ^

Right, it's better.

>>>
>>>> +                struct media_link **backlinks,
>>>> +                int *num_backlinks)
>>>
>>> unsigned int.
>>
>> OK.
>>
>>>> +{
>>>> +    int num_bklinks = 0, i;
>>>
>>> Same here.
>>
>> OK.
>>
>>>> +
>>>> +    if (entity == NULL || backlinks == NULL || num_backlinks == NULL)
>>>> +        return -EINVAL;
>>>> +
>>>> +    for (i = 0; i < entity->num_links; ++i)
>>>> +        if ((entity->links[i].flags & MEDIA_LNK_FL_ENABLED) &&
>>>> +            (entity->links[i].sink->entity == entity))
>>>> +            backlinks[num_bklinks++] = &entity->links[i];
>>>> +
>>>> +    *num_backlinks = num_bklinks;
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>>    /*
>>>> -----------------------------------------------------------------------------
>>>>
>>>>     * Open/close
>>>>     */
>>>> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
>>>> index 3faee71..9db40a8 100644
>>>> --- a/utils/media-ctl/mediactl.h
>>>> +++ b/utils/media-ctl/mediactl.h
>>>> @@ -231,6 +231,15 @@ const struct media_link
>>>> *media_entity_get_link(struct media_entity *entity,
>>>>    const char *media_entity_get_devname(struct media_entity *entity);
>>>>
>>>>    /**
>>>> + * @brief Get the name for an entity
>>>> + * @param entity - media entity.
>>>> + *
>>>> + * This function returns the name of the entity.
>>>> + *
>>>> + * @return A pointer to the string with entity name
>>>> + */
>>>> +const char *media_entity_get_name(struct media_entity *entity);
>>>> +
>>>>     * @brief Get the type of an entity.
>>>>     * @param entity - the entity.
>>>>     *
>>>> @@ -255,6 +264,19 @@ struct media_entity
>>>> *media_get_entity_by_name(struct media_device *media,
>>>>        const char *name, size_t length);
>>>>
>>>>    /**
>>>> + * @brief Find an entity by the corresponding device node name.
>>>> + * @param media - media device.
>>>> + * @param devname - device node name.
>>>> + * @param length - size of @a devname.
>>>> + *
>>>> + * Search for an entity with a device node name equal to @a devname.
>>>> + *
>>>> + * @return A pointer to the entity if found, or NULL otherwise.
>>>> + */
>>>> +struct media_entity *media_get_entity_by_devname(struct media_device
>>>> *media,
>>>> +    const char *devname, size_t length);
>>>> +
>>>> +/**
>>>>     * @brief Find an entity by its ID.
>>>>     * @param media - media device.
>>>>     * @param id - entity ID.
>>>> @@ -434,4 +456,18 @@ int media_parse_setup_link(struct media_device
>>>> *media,
>>>>     */
>>>>    int media_parse_setup_links(struct media_device *media, const char
>>>> *p);
>>>>
>>>> +/**
>>>> + * @brief Get entity's enabled backlinks
>>>> + * @param entity - media entity.
>>>> + * @param backlinks - array of pointers to matching backlinks.
>>>> + * @param num_backlinks - number of matching backlinks.
>>>> + *
>>>> + * Get links that are connected to the entity sink pads.
>>>> + *
>>>> + * @return 0 on success, or a negative error code on failure.
>>>> + */
>>>> +int media_get_backlinks_by_entity(struct media_entity *entity,
>>>> +                struct media_link **backlinks,
>>>> +                int *num_backlinks);
>>>> +
>>>>    #endif
>>>>
>>>
>>>
>>
>> [1]
>> http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/88446
>>
>>
>
>


-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 07/15] mediactl: libv4l2subdev: add VYUY8_2X8 mbus code
  2016-01-18 16:17 ` [PATCH 07/15] mediactl: libv4l2subdev: add VYUY8_2X8 mbus code Jacek Anaszewski
@ 2016-02-15 15:55   ` Sakari Ailus
  0 siblings, 0 replies; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 15:55 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Mon, Jan 18, 2016 at 05:17:32PM +0100, Jacek Anaszewski wrote:
> The VYUY8_2X8 media bus format is the only one supported
> by the S5C73M3 camera sensor, that is a part of the media
> device on the Exynos4412-trats2 board.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/libv4l2subdev.c |    1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
> index 069ded6..5175188 100644
> --- a/utils/media-ctl/libv4l2subdev.c
> +++ b/utils/media-ctl/libv4l2subdev.c
> @@ -780,6 +780,7 @@ static struct {
>  	{ "YUYV", MEDIA_BUS_FMT_YUYV8_1X16 },
>  	{ "YUYV1_5X8", MEDIA_BUS_FMT_YUYV8_1_5X8 },
>  	{ "YUYV2X8", MEDIA_BUS_FMT_YUYV8_2X8 },
> +	{ "VYUY8_2X8", V4L2_MBUS_FMT_VYUY8_2X8 },
>  	{ "UYVY", MEDIA_BUS_FMT_UYVY8_1X16 },
>  	{ "UYVY1_5X8", MEDIA_BUS_FMT_UYVY8_1_5X8 },
>  	{ "UYVY2X8", MEDIA_BUS_FMT_UYVY8_2X8 },

I have a patch taking the codes directly from media-bus-fmt.h; it's here:

<URL:http://www.spinics.net/lists/linux-media/msg96651.html>

Could you use the definition from that one instead? (I think all you need to
do is to drop the patch.)

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 08/15] mediactl: Add support for media device pipelines
  2016-01-18 16:17 ` [PATCH 08/15] mediactl: Add support for media device pipelines Jacek Anaszewski
@ 2016-02-15 16:53   ` Sakari Ailus
  2016-02-16  9:19     ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-15 16:53 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Mon, Jan 18, 2016 at 05:17:33PM +0100, Jacek Anaszewski wrote:
> Add infrastructure for linking media entities and discovering
> media device pipelines.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  utils/media-ctl/libmediactl.c   |  117 +++++++++++++++++++++++++++++++++++++++
>  utils/media-ctl/mediactl-priv.h |    6 ++
>  utils/media-ctl/mediactl.h      |   71 ++++++++++++++++++++++++
>  3 files changed, 194 insertions(+)
> 
> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
> index 3a45ecc..9909c1c 100644
> --- a/utils/media-ctl/libmediactl.c
> +++ b/utils/media-ctl/libmediactl.c
> @@ -1109,3 +1109,120 @@ int media_parse_setup_links(struct media_device *media, const char *p)
>  
>  	return *end ? -EINVAL : 0;
>  }
> +
> +/* -----------------------------------------------------------------------------
> + * Pipeline operations
> + */
> +
> +int media_discover_pipeline_by_entity(struct media_device *media,
> +				      struct media_entity *entity)
> +{
> +	struct media_entity *pipe_head = NULL;
> +	struct media_pad *src_pad;
> +	struct media_link *link = NULL, *backlinks[10];
> +	int i, num_backlinks, ret;
> +
> +	if (entity == NULL)
> +		return -EINVAL;
> +
> +	for (;;) {
> +		/* Make recently discovered entity the pipeline head */
> +		if (pipe_head == NULL) {
> +			pipe_head = entity;
> +		} else {
> +			entity->next = pipe_head;
> +			pipe_head = entity;
> +		}
> +
> +		/* Cache a source pad used for linking the entity */
> +		if (link)
> +			entity->pipe_src_pad = link->source;
> +
> +		ret = media_get_backlinks_by_entity(entity,
> +						    backlinks,
> +						    &num_backlinks);
> +		if (ret < 0)
> +			return ret;
> +
> +		/* check if pipeline source entity has been reached */
> +		if (num_backlinks > 2) {
> +			media_dbg(media, "Unexpected number of busy sink pads (%d)\n", num_backlinks);
> +			return -EINVAL;
> +		} else if (num_backlinks == 2) {
> +			/*
> +			 * Allow two active pads only in case of
> +			 * S5C73M3-OIF entity.
> +			 */

This piece of code appears to be too device specific to me to fit into
libmediactl. Could it be put to the plugin instead?

When it comes to automatically finding out a possible pipeline --- I don't
think it's best fit for libmediactl. Nothing prevents adding a new library
for that though.

> +			if (strcmp(entity->info.name, "S5C73M3-OIF")) {
> +				media_dbg(media, "Ambiguous media device topology: two busy sink pads");
> +				return -EINVAL;
> +			}
> +			/*
> +			 * Two active links are allowed betwen S5C73M3-OIF and
> +			 * S5C73M3 entities. In such a case a route through pad
> +			 * with id == 0 has to be selected.
> +			 */
> +			for (i = 0; i < num_backlinks; i++)
> +				if (backlinks[i]->sink->index == 0)
> +					link = backlinks[i];
> +		} else if (num_backlinks == 1)
> +			link = backlinks[0];
> +		else
> +			break;
> +
> +		/* Cache a sink pad used for linking the entity */
> +		entity->pipe_sink_pad = link->sink;
> +
> +		media_dbg(media, "Discovered sink pad %d for the %s entity\n",
> +			  entity->pipe_sink_pad->index, media_entity_get_name(entity));
> +
> +		src_pad = media_entity_remote_source(link->sink);
> +		if (!src_pad)
> +			return -EINVAL;
> +
> +		entity = src_pad->entity;
> +	}
> +
> +	media->pipeline = pipe_head;
> +
> +	return 0;
> +}
> +
> +int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name)
> +{
> +	if (pipeline == NULL || entity_name == NULL)
> +		return -EINVAL;
> +
> +	while (pipeline) {
> +		if (!strncmp(pipeline->info.name, entity_name,
> +			     strlen(entity_name)))
> +			return 1;
> +		pipeline = pipeline->next;
> +	}
> +
> +	return 0;
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Media entity access
> + */
> +
> +struct media_entity *media_get_pipeline(struct media_device *media)
> +{
> +	return media->pipeline;
> +}
> +
> +int media_entity_get_src_pad_index(struct media_entity *entity)
> +{
> +	return entity->pipe_src_pad->index;
> +}
> +
> +int media_entity_get_sink_pad_index(struct media_entity *entity)
> +{
> +	return entity->pipe_sink_pad->index;
> +}
> +
> +struct media_entity *media_entity_get_next(struct media_entity *entity)
> +{
> +	return entity->next;
> +}
> diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
> index f531c52..3378880 100644
> --- a/utils/media-ctl/mediactl-priv.h
> +++ b/utils/media-ctl/mediactl-priv.h
> @@ -36,9 +36,14 @@ struct media_entity {
>  	unsigned int max_links;
>  	unsigned int num_links;
>  
> +	struct media_pad *pipe_src_pad;
> +	struct media_pad *pipe_sink_pad;

This suggests that a pipeline has to be linear. It's not uncommon to have
non-linear pipelines these days.

That said, supposing that the functionality is fully moved to another
library, then one needs to somehow solve associating information specific to
that library to entities.

> +
>  	struct v4l2_subdev *sd;
>  
>  	char devname[32];
> +
> +	struct media_entity *next;

If you stored the source / sink links instead, you could remove next (as
it's link->sink->entity).

>  };
>  
>  struct media_device {
> @@ -49,6 +54,7 @@ struct media_device {
>  	struct media_device_info info;
>  	struct media_entity *entities;
>  	unsigned int entities_count;
> +	struct media_entity *pipeline;

This makes the assumption that there's only a single pipeline within the
media device. Again, I don't think that's a sound generic assumption.

This should go to the plugin instead.

>  
>  	void (*debug_handler)(void *, ...);
>  	void *debug_priv;
> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
> index 1d62191..4570160 100644
> --- a/utils/media-ctl/mediactl.h
> +++ b/utils/media-ctl/mediactl.h
> @@ -500,4 +500,75 @@ int media_get_backlinks_by_entity(struct media_entity *entity,
>  				struct media_link **backlinks,
>  				int *num_backlinks);
>  
> +/**
> + * @brief Check presence of the entity in the pipeline
> + * @param pipeline - video pipeline within a media device.
> + * @param entity_name - name of the entity to search for.
> + *
> + * Check if the entity with entity_name belongs to
> + * the pipeline.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name);
> +
> +/**
> + * @brief Discover the video pipeline
> + * @param media - media device.
> + * @param entity - media entity.
> + *
> + * Discover the pipeline of sub-devices, by walking
> + * upstream starting from the passed sink entity until
> + * the camera sensor entity is encountered.
> + *
> + * @return 0 on success, or a negative error code on failure.
> + */
> +int media_discover_pipeline_by_entity(struct media_device *media,
> +				struct media_entity *entity);
> +
> +/**
> + * @brief Get source pad of the pipeline entity
> + * @param entity - media entity.
> + *
> + * This function returns the source pad of the entity.
> + *
> + * @return entity source pad, or NULL if the entity is not linked.
> + */
> +int media_entity_get_src_pad_index(struct media_entity *entity);
> +
> +/**
> + * @brief Get sink pad of the pipeline entity
> + * @param entity - media entity.
> + *
> + * This function returns the sink pad of the entity.
> + *
> + * @return entity sink pad, or NULL if the entity is not linked.
> + */
> +int media_entity_get_sink_pad_index(struct media_entity *entity);
> +
> +/**
> + * @brief Get next entity in the pipeline
> + * @param entity - media entity
> + *
> + * This function gets the entity connected to a source pad of this entity.
> + *
> + * @return next enetity in the pipeline,
> + *	   or NULL if the entity is not linked
> + */
> +struct media_entity *media_entity_get_next(struct media_entity *entity);
> +
> +/**
> + * @brief Get the video pipeline
> + * @param media - media device
> + *
> + * This function gets the pipeline of media entities. The pipeline
> + * source entity is a camera sensor and the sink one is the entity
> + * representing opened video device node. The pipeline has to be
> + * discovered with use of the function media_discover_pipeline_by_entity.
> + *
> + * @return first media_entity in the pipeline,
> + *	   or NULL if the pipeline hasn't been discovered
> + */
> +struct media_entity *media_get_pipeline(struct media_device *media);
> +
>  #endif

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 08/15] mediactl: Add support for media device pipelines
  2016-02-15 16:53   ` Sakari Ailus
@ 2016-02-16  9:19     ` Jacek Anaszewski
  0 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-16  9:19 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

On 02/15/2016 05:53 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> On Mon, Jan 18, 2016 at 05:17:33PM +0100, Jacek Anaszewski wrote:
>> Add infrastructure for linking media entities and discovering
>> media device pipelines.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>   utils/media-ctl/libmediactl.c   |  117 +++++++++++++++++++++++++++++++++++++++
>>   utils/media-ctl/mediactl-priv.h |    6 ++
>>   utils/media-ctl/mediactl.h      |   71 ++++++++++++++++++++++++
>>   3 files changed, 194 insertions(+)
>>
>> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
>> index 3a45ecc..9909c1c 100644
>> --- a/utils/media-ctl/libmediactl.c
>> +++ b/utils/media-ctl/libmediactl.c
>> @@ -1109,3 +1109,120 @@ int media_parse_setup_links(struct media_device *media, const char *p)
>>
>>   	return *end ? -EINVAL : 0;
>>   }
>> +
>> +/* -----------------------------------------------------------------------------
>> + * Pipeline operations
>> + */
>> +
>> +int media_discover_pipeline_by_entity(struct media_device *media,
>> +				      struct media_entity *entity)
>> +{
>> +	struct media_entity *pipe_head = NULL;
>> +	struct media_pad *src_pad;
>> +	struct media_link *link = NULL, *backlinks[10];
>> +	int i, num_backlinks, ret;
>> +
>> +	if (entity == NULL)
>> +		return -EINVAL;
>> +
>> +	for (;;) {
>> +		/* Make recently discovered entity the pipeline head */
>> +		if (pipe_head == NULL) {
>> +			pipe_head = entity;
>> +		} else {
>> +			entity->next = pipe_head;
>> +			pipe_head = entity;
>> +		}
>> +
>> +		/* Cache a source pad used for linking the entity */
>> +		if (link)
>> +			entity->pipe_src_pad = link->source;
>> +
>> +		ret = media_get_backlinks_by_entity(entity,
>> +						    backlinks,
>> +						    &num_backlinks);
>> +		if (ret < 0)
>> +			return ret;
>> +
>> +		/* check if pipeline source entity has been reached */
>> +		if (num_backlinks > 2) {
>> +			media_dbg(media, "Unexpected number of busy sink pads (%d)\n", num_backlinks);
>> +			return -EINVAL;
>> +		} else if (num_backlinks == 2) {
>> +			/*
>> +			 * Allow two active pads only in case of
>> +			 * S5C73M3-OIF entity.
>> +			 */
>
> This piece of code appears to be too device specific to me to fit into
> libmediactl. Could it be put to the plugin instead?
>
> When it comes to automatically finding out a possible pipeline --- I don't
> think it's best fit for libmediactl. Nothing prevents adding a new library
> for that though.

OK, I'll move it to the plugin.

>
>> +			if (strcmp(entity->info.name, "S5C73M3-OIF")) {
>> +				media_dbg(media, "Ambiguous media device topology: two busy sink pads");
>> +				return -EINVAL;
>> +			}
>> +			/*
>> +			 * Two active links are allowed betwen S5C73M3-OIF and
>> +			 * S5C73M3 entities. In such a case a route through pad
>> +			 * with id == 0 has to be selected.
>> +			 */
>> +			for (i = 0; i < num_backlinks; i++)
>> +				if (backlinks[i]->sink->index == 0)
>> +					link = backlinks[i];
>> +		} else if (num_backlinks == 1)
>> +			link = backlinks[0];
>> +		else
>> +			break;
>> +
>> +		/* Cache a sink pad used for linking the entity */
>> +		entity->pipe_sink_pad = link->sink;
>> +
>> +		media_dbg(media, "Discovered sink pad %d for the %s entity\n",
>> +			  entity->pipe_sink_pad->index, media_entity_get_name(entity));
>> +
>> +		src_pad = media_entity_remote_source(link->sink);
>> +		if (!src_pad)
>> +			return -EINVAL;
>> +
>> +		entity = src_pad->entity;
>> +	}
>> +
>> +	media->pipeline = pipe_head;
>> +
>> +	return 0;
>> +}
>> +
>> +int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name)
>> +{
>> +	if (pipeline == NULL || entity_name == NULL)
>> +		return -EINVAL;
>> +
>> +	while (pipeline) {
>> +		if (!strncmp(pipeline->info.name, entity_name,
>> +			     strlen(entity_name)))
>> +			return 1;
>> +		pipeline = pipeline->next;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/* -----------------------------------------------------------------------------
>> + * Media entity access
>> + */
>> +
>> +struct media_entity *media_get_pipeline(struct media_device *media)
>> +{
>> +	return media->pipeline;
>> +}
>> +
>> +int media_entity_get_src_pad_index(struct media_entity *entity)
>> +{
>> +	return entity->pipe_src_pad->index;
>> +}
>> +
>> +int media_entity_get_sink_pad_index(struct media_entity *entity)
>> +{
>> +	return entity->pipe_sink_pad->index;
>> +}
>> +
>> +struct media_entity *media_entity_get_next(struct media_entity *entity)
>> +{
>> +	return entity->next;
>> +}
>> diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
>> index f531c52..3378880 100644
>> --- a/utils/media-ctl/mediactl-priv.h
>> +++ b/utils/media-ctl/mediactl-priv.h
>> @@ -36,9 +36,14 @@ struct media_entity {
>>   	unsigned int max_links;
>>   	unsigned int num_links;
>>
>> +	struct media_pad *pipe_src_pad;
>> +	struct media_pad *pipe_sink_pad;
>
> This suggests that a pipeline has to be linear. It's not uncommon to have
> non-linear pipelines these days.
>
> That said, supposing that the functionality is fully moved to another
> library, then one needs to somehow solve associating information specific to
> that library to entities.

Will be moved too.

>> +
>>   	struct v4l2_subdev *sd;
>>
>>   	char devname[32];
>> +
>> +	struct media_entity *next;
>
> If you stored the source / sink links instead, you could remove next (as
> it's link->sink->entity).
>
>>   };
>>
>>   struct media_device {
>> @@ -49,6 +54,7 @@ struct media_device {
>>   	struct media_device_info info;
>>   	struct media_entity *entities;
>>   	unsigned int entities_count;
>> +	struct media_entity *pipeline;
>
> This makes the assumption that there's only a single pipeline within the
> media device. Again, I don't think that's a sound generic assumption.
>
> This should go to the plugin instead.

OK.

>>
>>   	void (*debug_handler)(void *, ...);
>>   	void *debug_priv;
>> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
>> index 1d62191..4570160 100644
>> --- a/utils/media-ctl/mediactl.h
>> +++ b/utils/media-ctl/mediactl.h
>> @@ -500,4 +500,75 @@ int media_get_backlinks_by_entity(struct media_entity *entity,
>>   				struct media_link **backlinks,
>>   				int *num_backlinks);
>>
>> +/**
>> + * @brief Check presence of the entity in the pipeline
>> + * @param pipeline - video pipeline within a media device.
>> + * @param entity_name - name of the entity to search for.
>> + *
>> + * Check if the entity with entity_name belongs to
>> + * the pipeline.
>> + *
>> + * @return 0 on success, or a negative error code on failure.
>> + */
>> +int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name);
>> +
>> +/**
>> + * @brief Discover the video pipeline
>> + * @param media - media device.
>> + * @param entity - media entity.
>> + *
>> + * Discover the pipeline of sub-devices, by walking
>> + * upstream starting from the passed sink entity until
>> + * the camera sensor entity is encountered.
>> + *
>> + * @return 0 on success, or a negative error code on failure.
>> + */
>> +int media_discover_pipeline_by_entity(struct media_device *media,
>> +				struct media_entity *entity);
>> +
>> +/**
>> + * @brief Get source pad of the pipeline entity
>> + * @param entity - media entity.
>> + *
>> + * This function returns the source pad of the entity.
>> + *
>> + * @return entity source pad, or NULL if the entity is not linked.
>> + */
>> +int media_entity_get_src_pad_index(struct media_entity *entity);
>> +
>> +/**
>> + * @brief Get sink pad of the pipeline entity
>> + * @param entity - media entity.
>> + *
>> + * This function returns the sink pad of the entity.
>> + *
>> + * @return entity sink pad, or NULL if the entity is not linked.
>> + */
>> +int media_entity_get_sink_pad_index(struct media_entity *entity);
>> +
>> +/**
>> + * @brief Get next entity in the pipeline
>> + * @param entity - media entity
>> + *
>> + * This function gets the entity connected to a source pad of this entity.
>> + *
>> + * @return next enetity in the pipeline,
>> + *	   or NULL if the entity is not linked
>> + */
>> +struct media_entity *media_entity_get_next(struct media_entity *entity);
>> +
>> +/**
>> + * @brief Get the video pipeline
>> + * @param media - media device
>> + *
>> + * This function gets the pipeline of media entities. The pipeline
>> + * source entity is a camera sensor and the sink one is the entity
>> + * representing opened video device node. The pipeline has to be
>> + * discovered with use of the function media_discover_pipeline_by_entity.
>> + *
>> + * @return first media_entity in the pipeline,
>> + *	   or NULL if the pipeline hasn't been discovered
>> + */
>> +struct media_entity *media_get_pipeline(struct media_device *media);
>> +
>>   #endif
>


-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-02-15 13:06     ` Jacek Anaszewski
@ 2016-02-18 12:09       ` Sakari Ailus
  2016-02-18 13:14         ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-02-18 12:09 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Mon, Feb 15, 2016 at 02:06:06PM +0100, Jacek Anaszewski wrote:
> Hi Sakari,
> 
> Thanks for the review.
> 
> On 02/15/2016 01:41 PM, Sakari Ailus wrote:
> >Hi Jacek,
> >
> >Jacek Anaszewski wrote:
> >>Ioctls executed on complex media devices need special handling.
> >>For instance some ioctls need to be targeted for specific sub-devices,
> >>depending on the media device configuration. The APIs being introduced
> >>address such requirements.
> >>
> >>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>---
> >>  utils/media-ctl/Makefile.am          |    2 +-
> >>  utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
> >>  utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
> >>  3 files changed, 453 insertions(+), 1 deletion(-)
> >>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
> >>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
> >>
> >>diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
> >>index 3e883e0..7f18624 100644
> >>--- a/utils/media-ctl/Makefile.am
> >>+++ b/utils/media-ctl/Makefile.am
> >>@@ -1,6 +1,6 @@
> >>  noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
> >>
> >>-libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
> >>+libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
> >>  libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
> >>  libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
> >>
> >>diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
> >>new file mode 100644
> >>index 0000000..b186121
> >>--- /dev/null
> >>+++ b/utils/media-ctl/libv4l2media_ioctl.c
> >>@@ -0,0 +1,404 @@
> >>+/*
> >>+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
> >>+ *              http://www.samsung.com
> >>+ *
> >>+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>+ *
> >>+ * This program is free software; you can redistribute it and/or modify
> >>+ * it under the terms of the GNU Lesser General Public License as published by
> >>+ * the Free Software Foundation; either version 2.1 of the License, or
> >>+ * (at your option) any later version.
> >>+ *
> >>+ * This program is distributed in the hope that it will be useful,
> >>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>+ * Lesser General Public License for more details.
> >>+ */
> >>+
> >>+#include <errno.h>
> >>+#include <stdlib.h>
> >>+#include <sys/syscall.h>
> >>+#include <unistd.h>
> >>+
> >>+#include <linux/videodev2.h>
> >>+
> >>+#include "libv4l2media_ioctl.h"
> >>+#include "mediactl-priv.h"
> >>+#include "mediactl.h"
> >>+#include "v4l2subdev.h"
> >>+
> >>+#define VIDIOC_CTRL(type)					\
> >>+	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
> >>+				   "VIDIOC_G_CTRL")
> >>+
> >>+#define VIDIOC_EXT_CTRL(type)					\
> >>+	((type) == VIDIOC_S_EXT_CTRLS ? 			\
> >>+		"VIDIOC_S_EXT_CTRLS"	:			\
> >>+		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
> >>+				    "VIDIOC_G_EXT_CTRLS" :	\
> >>+				    "VIDIOC_TRY_EXT_CTRLS"))
> >>+
> >>+#define SYS_IOCTL(fd, cmd, arg) \
> >>+	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
> >>+
> >>+
> >>+int media_ioctl_ctrl(struct media_device *media, int request,
> >
> >unsigned int request
> 
> OK.
> 
> >
> >>+		     struct v4l2_control *arg)
> >
> >I wonder if it'd make sense to always use v4l2_ext_control instead. You
> >can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.
> 
> This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
> For ext ctrls there is media_ioctl_ext_ctrl().

Is there any reason not to use extended control always?

In other words, do we have a driver that does support Media controller but
does not support extended controls?

> >As this is a user space library, I'd probably add a function to handle
> >S/G/TRY control each.
> 
> There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
> VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.
> 
> >Have you considered binding the control to a video node rather than a
> >media device? We have many sensors on current media devices already, and
> >e.g. exposure time control can be found in multiple sub-devices.
> 
> Doesn't v4l2-ctrl-redir config entry address that?

How does it work if you have, say, two video nodes where you can capture
images from a different sensor? I.e. your media graph could look like this:

	sensor0 -> CSI-2 0 -> video0

	sensor1 -> CSI-2 1 -> video1

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-02-18 12:09       ` Sakari Ailus
@ 2016-02-18 13:14         ` Jacek Anaszewski
  2016-03-21  0:07           ` Sakari Ailus
  0 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-18 13:14 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

On 02/18/2016 01:09 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> On Mon, Feb 15, 2016 at 02:06:06PM +0100, Jacek Anaszewski wrote:
>> Hi Sakari,
>>
>> Thanks for the review.
>>
>> On 02/15/2016 01:41 PM, Sakari Ailus wrote:
>>> Hi Jacek,
>>>
>>> Jacek Anaszewski wrote:
>>>> Ioctls executed on complex media devices need special handling.
>>>> For instance some ioctls need to be targeted for specific sub-devices,
>>>> depending on the media device configuration. The APIs being introduced
>>>> address such requirements.
>>>>
>>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>>> ---
>>>>   utils/media-ctl/Makefile.am          |    2 +-
>>>>   utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
>>>>   utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
>>>>   3 files changed, 453 insertions(+), 1 deletion(-)
>>>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
>>>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
>>>>
>>>> diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
>>>> index 3e883e0..7f18624 100644
>>>> --- a/utils/media-ctl/Makefile.am
>>>> +++ b/utils/media-ctl/Makefile.am
>>>> @@ -1,6 +1,6 @@
>>>>   noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
>>>>
>>>> -libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
>>>> +libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
>>>>   libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
>>>>   libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
>>>>
>>>> diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
>>>> new file mode 100644
>>>> index 0000000..b186121
>>>> --- /dev/null
>>>> +++ b/utils/media-ctl/libv4l2media_ioctl.c
>>>> @@ -0,0 +1,404 @@
>>>> +/*
>>>> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
>>>> + *              http://www.samsung.com
>>>> + *
>>>> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU Lesser General Public License as published by
>>>> + * the Free Software Foundation; either version 2.1 of the License, or
>>>> + * (at your option) any later version.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + */
>>>> +
>>>> +#include <errno.h>
>>>> +#include <stdlib.h>
>>>> +#include <sys/syscall.h>
>>>> +#include <unistd.h>
>>>> +
>>>> +#include <linux/videodev2.h>
>>>> +
>>>> +#include "libv4l2media_ioctl.h"
>>>> +#include "mediactl-priv.h"
>>>> +#include "mediactl.h"
>>>> +#include "v4l2subdev.h"
>>>> +
>>>> +#define VIDIOC_CTRL(type)					\
>>>> +	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
>>>> +				   "VIDIOC_G_CTRL")
>>>> +
>>>> +#define VIDIOC_EXT_CTRL(type)					\
>>>> +	((type) == VIDIOC_S_EXT_CTRLS ? 			\
>>>> +		"VIDIOC_S_EXT_CTRLS"	:			\
>>>> +		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
>>>> +				    "VIDIOC_G_EXT_CTRLS" :	\
>>>> +				    "VIDIOC_TRY_EXT_CTRLS"))
>>>> +
>>>> +#define SYS_IOCTL(fd, cmd, arg) \
>>>> +	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
>>>> +
>>>> +
>>>> +int media_ioctl_ctrl(struct media_device *media, int request,
>>>
>>> unsigned int request
>>
>> OK.
>>
>>>
>>>> +		     struct v4l2_control *arg)
>>>
>>> I wonder if it'd make sense to always use v4l2_ext_control instead. You
>>> can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.
>>
>> This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
>> For ext ctrls there is media_ioctl_ext_ctrl().
>
> Is there any reason not to use extended control always?
>
> In other words, do we have a driver that does support Media controller but
> does not support extended controls?

Shouldn't we support non-extended controls for backward compatibility
reasons? I am not aware of the policy in this matter.

>>> As this is a user space library, I'd probably add a function to handle
>>> S/G/TRY control each.
>>
>> There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
>> VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.
>>
>>> Have you considered binding the control to a video node rather than a
>>> media device? We have many sensors on current media devices already, and
>>> e.g. exposure time control can be found in multiple sub-devices.
>>
>> Doesn't v4l2-ctrl-redir config entry address that?
>
> How does it work if you have, say, two video nodes where you can capture
> images from a different sensor? I.e. your media graph could look like this:
>
> 	sensor0 -> CSI-2 0 -> video0
>
> 	sensor1 -> CSI-2 1 -> video1

Exemplary config settings for this case:

v4l2-ctrl-redir 0x0098091f -> "sensor0"
v4l2-ctrl-redir 0x0098091f -> "sensor1"

In media_ioctl_ctrl the v4l2_subdev_get_pipeline_entity_by_cid(media,
ctrl.id) is called which walks through the pipeline and checks if there
has been a v4l2 control redirection defined for given entity.

If no redirection is defined then the control is set on the first
entity in the pipeline that supports it. Effectively, for this
arrangement no redirection would be required if the control
is to be set on sensors. It would be required if we wanted
to bind the control to the videoN entity. Now I am wondering
if I should change the entry name to v4l2-ctrl-binding, or maybe
someone has better idea?

BTW, are there some unique identifiers added to the entity names if
more than one entity of a name is to be registered? E.g. what would
happen if I had two S5C73M3 sensors in a media device? I assumed that
entity names are unique.

-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 01/15] mediactl: Introduce v4l2_subdev structure
  2016-02-12 12:42   ` Sakari Ailus
@ 2016-02-18 14:15     ` Jacek Anaszewski
  2016-03-20 23:39       ` Sakari Ailus
  0 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-02-18 14:15 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

Thanks for the review.

On 02/12/2016 01:42 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> Thanks for continuing this work! And my apologies for reviewing only
> now... please see the comments below.
>
> Jacek Anaszewski wrote:
>> Add struct v4l2_subdev - a representation of the v4l2 sub-device,
>> related to the media entity. Add field 'sd', the pointer to
>> the newly introduced structure, to the struct media_entity
>> and move 'fd' property from struct media entity to struct v4l2_subdev.
>> Avoid accessing sub-device file descriptor from libmediactl and
>> make the v4l2_subdev_open capable of creating the v4l2_subdev
>> if the 'sd' pointer is uninitialized.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>   utils/media-ctl/libmediactl.c   |    4 --
>>   utils/media-ctl/libv4l2subdev.c |   82 +++++++++++++++++++++++++++++++--------
>>   utils/media-ctl/mediactl-priv.h |    5 ++-
>>   utils/media-ctl/v4l2subdev.h    |   38 ++++++++++++++++++
>>   4 files changed, 107 insertions(+), 22 deletions(-)
>>
>> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
>> index 4a82d24..7e98440 100644
>> --- a/utils/media-ctl/libmediactl.c
>> +++ b/utils/media-ctl/libmediactl.c
>> @@ -525,7 +525,6 @@ static int media_enum_entities(struct media_device *media)
>>
>>   		entity = &media->entities[media->entities_count];
>>   		memset(entity, 0, sizeof(*entity));
>> -		entity->fd = -1;
>>   		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
>>   		entity->media = media;
>>
>> @@ -719,8 +718,6 @@ void media_device_unref(struct media_device *media)
>>
>>   		free(entity->pads);
>>   		free(entity->links);
>> -		if (entity->fd != -1)
>> -			close(entity->fd);
>>   	}
>>
>>   	free(media->entities);
>> @@ -747,7 +744,6 @@ int media_device_add_entity(struct media_device *media,
>>   	entity = &media->entities[media->entities_count - 1];
>>   	memset(entity, 0, sizeof *entity);
>>
>> -	entity->fd = -1;
>>   	entity->media = media;
>>   	strncpy(entity->devname, devnode, sizeof entity->devname);
>>   	entity->devname[sizeof entity->devname - 1] = '\0';
>> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
>> index 33c1ee6..3977ce5 100644
>> --- a/utils/media-ctl/libv4l2subdev.c
>> +++ b/utils/media-ctl/libv4l2subdev.c
>> @@ -39,13 +39,61 @@
>>   #include "tools.h"
>>   #include "v4l2subdev.h"
>>
>> +int v4l2_subdev_create(struct media_entity *entity)
>> +{
>> +	if (entity->sd)
>> +		return 0;
>> +
>> +	entity->sd = calloc(1, sizeof(*entity->sd));
>> +	if (entity->sd == NULL)
>> +		return -ENOMEM;
>> +
>> +	entity->sd->fd = -1;
>> +
>> +	return 0;
>> +}
>> +
>> +int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
>> +{
>> +	int ret;
>> +
>> +	if (entity->sd)
>> +		return -EEXIST;
>> +
>> +	ret = v4l2_subdev_create(entity);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	entity->sd->fd = fd;
>> +
>> +	return 0;
>> +}
>> +
>> +void v4l2_subdev_release(struct media_entity *entity, bool close_fd)
>> +{
>> +	if (entity->sd == NULL)
>> +		return;
>> +
>> +	if (close_fd)
>> +		v4l2_subdev_close(entity);
>> +
>> +	free(entity->sd->v4l2_control_redir);
>> +	free(entity->sd);
>> +}
>> +
>>   int v4l2_subdev_open(struct media_entity *entity)
>>   {
>> -	if (entity->fd != -1)
>> +	int ret;
>> +
>> +	ret = v4l2_subdev_create(entity);
>
> The current users of v4l2_subdev_open() in libv4l2subdev do not
> explicitly close the sub-devices they open; thus calling
> v4l2_subdev_create() here creates a memory leak.

Currently in my use cases there is no memory leak since I assumed
that the one who instantiates struct media_device should take
care of releasing it properly. I added v4l2_subdev_open_pipeline()
and v4l2_subdev_release_pipeline() API that is called on plugin
init and close respectively.

Probably it would be good to remove v4l2_subdev_open from
v4l2_subdev_* prefixed API and return error if sd property
of passed struct media_entity is not initialized.

> I wonder if it'd do harm to open all the associated devices in
> media_device_open() and close them in media_device_close().

Opening all sub-devices within a media device would be waste
of resources since we only need the sub-devices that belong
to the pipeline connected to the opened video device. It would
also incur unnecessary additional power consumption as you
mentioned below.

> The sub-device objects could exist for the entire lifespan of the media
> device object (in user space), and they could be used to store whatever
> information is needed.
>
> One would no longer need to call v4l2_subdev_open() directly either.
>
> I'd like to have Laurent's opinion on this, too.
>
> The power management currently is based on open file handles and this is
> a bit of a problem, but we have to have a better solution on this (based
> on latencies and perhaps PM QoS framework).
>
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (entity->sd->fd != -1)
>>   		return 0;
>>
>> -	entity->fd = open(entity->devname, O_RDWR);
>> -	if (entity->fd == -1) {
>> +	entity->sd->fd = open(entity->devname, O_RDWR);
>> +	if (entity->sd->fd == -1) {
>>   		int ret = -errno;
>>   		media_dbg(entity->media,
>>   			  "%s: Failed to open subdev device node %s\n", __func__,
>> @@ -58,8 +106,8 @@ int v4l2_subdev_open(struct media_entity *entity)
>>
>>   void v4l2_subdev_close(struct media_entity *entity)
>>   {
>> -	close(entity->fd);
>> -	entity->fd = -1;
>> +	close(entity->sd->fd);
>> +	entity->sd->fd = -1;
>>   }
>>
>>   int v4l2_subdev_get_format(struct media_entity *entity,
>> @@ -77,7 +125,7 @@ int v4l2_subdev_get_format(struct media_entity *entity,
>>   	fmt.pad = pad;
>>   	fmt.which = which;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -101,7 +149,7 @@ int v4l2_subdev_set_format(struct media_entity *entity,
>>   	fmt.which = which;
>>   	fmt.format = *format;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -128,7 +176,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
>>   	u.sel.target = target;
>>   	u.sel.which = which;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
>>   	if (ret >= 0) {
>>   		*rect = u.sel.r;
>>   		return 0;
>> @@ -140,7 +188,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
>>   	u.crop.pad = pad;
>>   	u.crop.which = which;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -168,7 +216,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
>>   	u.sel.which = which;
>>   	u.sel.r = *rect;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
>>   	if (ret >= 0) {
>>   		*rect = u.sel.r;
>>   		return 0;
>> @@ -181,7 +229,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
>>   	u.crop.which = which;
>>   	u.crop.rect = *rect;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -202,7 +250,7 @@ int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
>>   	memset(caps, 0, sizeof(*caps));
>>   	caps->pad = pad;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -220,7 +268,7 @@ int v4l2_subdev_query_dv_timings(struct media_entity *entity,
>>
>>   	memset(timings, 0, sizeof(*timings));
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -238,7 +286,7 @@ int v4l2_subdev_get_dv_timings(struct media_entity *entity,
>>
>>   	memset(timings, 0, sizeof(*timings));
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -254,7 +302,7 @@ int v4l2_subdev_set_dv_timings(struct media_entity *entity,
>>   	if (ret < 0)
>>   		return ret;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -273,7 +321,7 @@ int v4l2_subdev_get_frame_interval(struct media_entity *entity,
>>
>>   	memset(&ival, 0, sizeof(ival));
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> @@ -294,7 +342,7 @@ int v4l2_subdev_set_frame_interval(struct media_entity *entity,
>>   	memset(&ival, 0, sizeof(ival));
>>   	ival.interval = *interval;
>>
>> -	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
>> +	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
>>   	if (ret < 0)
>>   		return -errno;
>>
>> diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
>> index a0d3a55..f531c52 100644
>> --- a/utils/media-ctl/mediactl-priv.h
>> +++ b/utils/media-ctl/mediactl-priv.h
>> @@ -26,6 +26,8 @@
>>
>>   #include "mediactl.h"
>>
>> +struct v4l2_subdev;
>> +
>>   struct media_entity {
>>   	struct media_device *media;
>>   	struct media_entity_desc info;
>> @@ -34,8 +36,9 @@ struct media_entity {
>>   	unsigned int max_links;
>>   	unsigned int num_links;
>>
>> +	struct v4l2_subdev *sd;
>> +
>>   	char devname[32];
>> -	int fd;
>>   };
>>
>>   struct media_device {
>> diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
>> index 104e420..ba9b8c4 100644
>> --- a/utils/media-ctl/v4l2subdev.h
>> +++ b/utils/media-ctl/v4l2subdev.h
>> @@ -27,6 +27,44 @@
>>   struct media_device;
>>   struct media_entity;
>>
>> +struct v4l2_subdev {
>> +	int fd;
>> +};
>> +
>> +/**
>> + * @brief Create a v4l2-subdev
>> + * @param entity - sub-device media entity.
>> + *
>> + * Create the representation of the entity sub-device.
>> + *
>> + * @return 0 on success, or a negative error code on failure.
>> + */
>> +int v4l2_subdev_create(struct media_entity *entity);
>> +
>> +/**
>> + * @brief Create a representation of the already opened v4l2-subdev
>> + * @param entity - sub-device media entity.
>> + * @param fd - sub-device file descriptor.
>> + *
>> + * Create the representation of the sub-device that had been opened
>> + * before the parent media device was created, and associate it
>> + * with the media entity.
>> + *
>> + * @return 0 on success, or a negative error code on failure.
>> + */
>> +int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd);
>> +
>> +/**
>> + * @brief Release a v4l2-subdev
>> + * @param entity - sub-device media entity.
>> + * @param close_fd - indicates whether subdev fd should be closed.
>> + *
>> + * Release the representation of the entity sub-device.
>> + *
>> + * @return 0 on success, or a negative error code on failure.
>> + */
>> +void v4l2_subdev_release(struct media_entity *entity, bool close_fd);
>> +
>
> Is there a need to call these outside the library itself? Should they be
> static instead?
>
>>   /**
>>    * @brief Open a sub-device.
>>    * @param entity - sub-device media entity.
>>
>


-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 01/15] mediactl: Introduce v4l2_subdev structure
  2016-02-18 14:15     ` Jacek Anaszewski
@ 2016-03-20 23:39       ` Sakari Ailus
  2016-03-22  9:26         ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-03-20 23:39 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Thu, Feb 18, 2016 at 03:15:32PM +0100, Jacek Anaszewski wrote:
> Hi Sakari,
> 
> Thanks for the review.
> 
> On 02/12/2016 01:42 PM, Sakari Ailus wrote:
> >Hi Jacek,
> >
> >Thanks for continuing this work! And my apologies for reviewing only
> >now... please see the comments below.
> >
> >Jacek Anaszewski wrote:
> >>Add struct v4l2_subdev - a representation of the v4l2 sub-device,
> >>related to the media entity. Add field 'sd', the pointer to
> >>the newly introduced structure, to the struct media_entity
> >>and move 'fd' property from struct media entity to struct v4l2_subdev.
> >>Avoid accessing sub-device file descriptor from libmediactl and
> >>make the v4l2_subdev_open capable of creating the v4l2_subdev
> >>if the 'sd' pointer is uninitialized.
> >>
> >>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>---
> >>  utils/media-ctl/libmediactl.c   |    4 --
> >>  utils/media-ctl/libv4l2subdev.c |   82 +++++++++++++++++++++++++++++++--------
> >>  utils/media-ctl/mediactl-priv.h |    5 ++-
> >>  utils/media-ctl/v4l2subdev.h    |   38 ++++++++++++++++++
> >>  4 files changed, 107 insertions(+), 22 deletions(-)
> >>
> >>diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
> >>index 4a82d24..7e98440 100644
> >>--- a/utils/media-ctl/libmediactl.c
> >>+++ b/utils/media-ctl/libmediactl.c
> >>@@ -525,7 +525,6 @@ static int media_enum_entities(struct media_device *media)
> >>
> >>  		entity = &media->entities[media->entities_count];
> >>  		memset(entity, 0, sizeof(*entity));
> >>-		entity->fd = -1;
> >>  		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
> >>  		entity->media = media;
> >>
> >>@@ -719,8 +718,6 @@ void media_device_unref(struct media_device *media)
> >>
> >>  		free(entity->pads);
> >>  		free(entity->links);
> >>-		if (entity->fd != -1)
> >>-			close(entity->fd);
> >>  	}
> >>
> >>  	free(media->entities);
> >>@@ -747,7 +744,6 @@ int media_device_add_entity(struct media_device *media,
> >>  	entity = &media->entities[media->entities_count - 1];
> >>  	memset(entity, 0, sizeof *entity);
> >>
> >>-	entity->fd = -1;
> >>  	entity->media = media;
> >>  	strncpy(entity->devname, devnode, sizeof entity->devname);
> >>  	entity->devname[sizeof entity->devname - 1] = '\0';
> >>diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
> >>index 33c1ee6..3977ce5 100644
> >>--- a/utils/media-ctl/libv4l2subdev.c
> >>+++ b/utils/media-ctl/libv4l2subdev.c
> >>@@ -39,13 +39,61 @@
> >>  #include "tools.h"
> >>  #include "v4l2subdev.h"
> >>
> >>+int v4l2_subdev_create(struct media_entity *entity)
> >>+{
> >>+	if (entity->sd)
> >>+		return 0;
> >>+
> >>+	entity->sd = calloc(1, sizeof(*entity->sd));
> >>+	if (entity->sd == NULL)
> >>+		return -ENOMEM;
> >>+
> >>+	entity->sd->fd = -1;
> >>+
> >>+	return 0;
> >>+}
> >>+
> >>+int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
> >>+{
> >>+	int ret;
> >>+
> >>+	if (entity->sd)
> >>+		return -EEXIST;
> >>+
> >>+	ret = v4l2_subdev_create(entity);
> >>+	if (ret < 0)
> >>+		return ret;
> >>+
> >>+	entity->sd->fd = fd;
> >>+
> >>+	return 0;
> >>+}
> >>+
> >>+void v4l2_subdev_release(struct media_entity *entity, bool close_fd)
> >>+{
> >>+	if (entity->sd == NULL)
> >>+		return;
> >>+
> >>+	if (close_fd)
> >>+		v4l2_subdev_close(entity);
> >>+
> >>+	free(entity->sd->v4l2_control_redir);
> >>+	free(entity->sd);
> >>+}
> >>+
> >>  int v4l2_subdev_open(struct media_entity *entity)
> >>  {
> >>-	if (entity->fd != -1)
> >>+	int ret;
> >>+
> >>+	ret = v4l2_subdev_create(entity);
> >
> >The current users of v4l2_subdev_open() in libv4l2subdev do not
> >explicitly close the sub-devices they open; thus calling
> >v4l2_subdev_create() here creates a memory leak.
> 
> Currently in my use cases there is no memory leak since I assumed
> that the one who instantiates struct media_device should take
> care of releasing it properly. I added v4l2_subdev_open_pipeline()
> and v4l2_subdev_release_pipeline() API that is called on plugin
> init and close respectively.

I'm referring to the use of the libv4l2subdev API as it's documented; the
media-ctl test program which also serves as a good example on the API.

Any sub-device IOCTL wrapper function will call v4l2_subdev_open() which
stores the file descriptor returned by open(2) to struct media_entity.fd.
v4l2_subdev_close() is not called explicitly. This is currently not
required.

The file handle is not leaked, as it is closed by media_device_unref() in
libmediactl.

This patch allocates memory for each sub-device in v4l2_subdev_create()
which is in turn called from v4l2_subdev_open(). As the calls to
v4l2_subdev_close() (which would release memory) are lacking, the memory is
leaked.

> 
> Probably it would be good to remove v4l2_subdev_open from
> v4l2_subdev_* prefixed API and return error if sd property
> of passed struct media_entity is not initialized.

The purpose of the libv4l2subdev library is to make accessing sub-devices
easier, and tossing that responsibility to the user is certainly not
advancing that goal.

I've been working on extending libmediatext library into an interactive test
program for V4L2, V4L2 sub-device and Media controller. What I've noticed
that libv4l2subdev does not currently bend really well for that purpose;
the data structure holding the media graph is sort of self-contained and
cannot be extended nor it can be used to refer to something else. That's a
bit aside from the topic of this patch, but I presume that you'd need to
associate information to media entities as well. For this reason I presume
that releasing the resources related to a media entity acquired for e.g.
IOCTL is not the right way to proceed.

Instead, I think the libraries (libmediactl and libv4l2subdev) need to
manage the resources (as has been done with file handles up to now).

How about adding a callback to release resources related to an entity, e.g.
as this:

	void (*release)(struct media_entity *entity);

It would be called by media_device_unref(). v4l2_subdev_close() prototype
already matches with that, so it could be used directly.

> 
> >I wonder if it'd do harm to open all the associated devices in
> >media_device_open() and close them in media_device_close().
> 
> Opening all sub-devices within a media device would be waste
> of resources since we only need the sub-devices that belong
> to the pipeline connected to the opened video device. It would
> also incur unnecessary additional power consumption as you
> mentioned below.
> 
> >The sub-device objects could exist for the entire lifespan of the media
> >device object (in user space), and they could be used to store whatever
> >information is needed.
> >
> >One would no longer need to call v4l2_subdev_open() directly either.
> >
> >I'd like to have Laurent's opinion on this, too.
> >
> >The power management currently is based on open file handles and this is
> >a bit of a problem, but we have to have a better solution on this (based
> >on latencies and perhaps PM QoS framework).
> >
> >>+	if (ret < 0)
> >>+		return ret;
> >>+
> >>+	if (entity->sd->fd != -1)
> >>  		return 0;
> >>
> >>-	entity->fd = open(entity->devname, O_RDWR);
> >>-	if (entity->fd == -1) {
> >>+	entity->sd->fd = open(entity->devname, O_RDWR);
> >>+	if (entity->sd->fd == -1) {
> >>  		int ret = -errno;
> >>  		media_dbg(entity->media,
> >>  			  "%s: Failed to open subdev device node %s\n", __func__,
> >>@@ -58,8 +106,8 @@ int v4l2_subdev_open(struct media_entity *entity)
> >>
> >>  void v4l2_subdev_close(struct media_entity *entity)
> >>  {
> >>-	close(entity->fd);
> >>-	entity->fd = -1;
> >>+	close(entity->sd->fd);
> >>+	entity->sd->fd = -1;
> >>  }
> >>
> >>  int v4l2_subdev_get_format(struct media_entity *entity,
> >>@@ -77,7 +125,7 @@ int v4l2_subdev_get_format(struct media_entity *entity,
> >>  	fmt.pad = pad;
> >>  	fmt.which = which;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -101,7 +149,7 @@ int v4l2_subdev_set_format(struct media_entity *entity,
> >>  	fmt.which = which;
> >>  	fmt.format = *format;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -128,7 +176,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
> >>  	u.sel.target = target;
> >>  	u.sel.which = which;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
> >>  	if (ret >= 0) {
> >>  		*rect = u.sel.r;
> >>  		return 0;
> >>@@ -140,7 +188,7 @@ int v4l2_subdev_get_selection(struct media_entity *entity,
> >>  	u.crop.pad = pad;
> >>  	u.crop.which = which;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -168,7 +216,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
> >>  	u.sel.which = which;
> >>  	u.sel.r = *rect;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
> >>  	if (ret >= 0) {
> >>  		*rect = u.sel.r;
> >>  		return 0;
> >>@@ -181,7 +229,7 @@ int v4l2_subdev_set_selection(struct media_entity *entity,
> >>  	u.crop.which = which;
> >>  	u.crop.rect = *rect;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -202,7 +250,7 @@ int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
> >>  	memset(caps, 0, sizeof(*caps));
> >>  	caps->pad = pad;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -220,7 +268,7 @@ int v4l2_subdev_query_dv_timings(struct media_entity *entity,
> >>
> >>  	memset(timings, 0, sizeof(*timings));
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -238,7 +286,7 @@ int v4l2_subdev_get_dv_timings(struct media_entity *entity,
> >>
> >>  	memset(timings, 0, sizeof(*timings));
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -254,7 +302,7 @@ int v4l2_subdev_set_dv_timings(struct media_entity *entity,
> >>  	if (ret < 0)
> >>  		return ret;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -273,7 +321,7 @@ int v4l2_subdev_get_frame_interval(struct media_entity *entity,
> >>
> >>  	memset(&ival, 0, sizeof(ival));
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>@@ -294,7 +342,7 @@ int v4l2_subdev_set_frame_interval(struct media_entity *entity,
> >>  	memset(&ival, 0, sizeof(ival));
> >>  	ival.interval = *interval;
> >>
> >>-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
> >>+	ret = ioctl(entity->sd->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
> >>  	if (ret < 0)
> >>  		return -errno;
> >>
> >>diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
> >>index a0d3a55..f531c52 100644
> >>--- a/utils/media-ctl/mediactl-priv.h
> >>+++ b/utils/media-ctl/mediactl-priv.h
> >>@@ -26,6 +26,8 @@
> >>
> >>  #include "mediactl.h"
> >>
> >>+struct v4l2_subdev;
> >>+
> >>  struct media_entity {
> >>  	struct media_device *media;
> >>  	struct media_entity_desc info;
> >>@@ -34,8 +36,9 @@ struct media_entity {
> >>  	unsigned int max_links;
> >>  	unsigned int num_links;
> >>
> >>+	struct v4l2_subdev *sd;
> >>+
> >>  	char devname[32];
> >>-	int fd;
> >>  };
> >>
> >>  struct media_device {
> >>diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
> >>index 104e420..ba9b8c4 100644
> >>--- a/utils/media-ctl/v4l2subdev.h
> >>+++ b/utils/media-ctl/v4l2subdev.h
> >>@@ -27,6 +27,44 @@
> >>  struct media_device;
> >>  struct media_entity;
> >>
> >>+struct v4l2_subdev {
> >>+	int fd;
> >>+};
> >>+
> >>+/**
> >>+ * @brief Create a v4l2-subdev
> >>+ * @param entity - sub-device media entity.
> >>+ *
> >>+ * Create the representation of the entity sub-device.
> >>+ *
> >>+ * @return 0 on success, or a negative error code on failure.
> >>+ */
> >>+int v4l2_subdev_create(struct media_entity *entity);
> >>+
> >>+/**
> >>+ * @brief Create a representation of the already opened v4l2-subdev
> >>+ * @param entity - sub-device media entity.
> >>+ * @param fd - sub-device file descriptor.
> >>+ *
> >>+ * Create the representation of the sub-device that had been opened
> >>+ * before the parent media device was created, and associate it
> >>+ * with the media entity.
> >>+ *
> >>+ * @return 0 on success, or a negative error code on failure.
> >>+ */
> >>+int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd);
> >>+
> >>+/**
> >>+ * @brief Release a v4l2-subdev
> >>+ * @param entity - sub-device media entity.
> >>+ * @param close_fd - indicates whether subdev fd should be closed.
> >>+ *
> >>+ * Release the representation of the entity sub-device.
> >>+ *
> >>+ * @return 0 on success, or a negative error code on failure.
> >>+ */
> >>+void v4l2_subdev_release(struct media_entity *entity, bool close_fd);
> >>+
> >
> >Is there a need to call these outside the library itself? Should they be
> >static instead?
> >
> >>  /**
> >>   * @brief Open a sub-device.
> >>   * @param entity - sub-device media entity.
> >>
> >
> 
> 

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-02-18 13:14         ` Jacek Anaszewski
@ 2016-03-21  0:07           ` Sakari Ailus
  2016-03-22  9:36             ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-03-21  0:07 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Thu, Feb 18, 2016 at 02:14:40PM +0100, Jacek Anaszewski wrote:
> Hi Sakari,
> 
> On 02/18/2016 01:09 PM, Sakari Ailus wrote:
> >Hi Jacek,
> >
> >On Mon, Feb 15, 2016 at 02:06:06PM +0100, Jacek Anaszewski wrote:
> >>Hi Sakari,
> >>
> >>Thanks for the review.
> >>
> >>On 02/15/2016 01:41 PM, Sakari Ailus wrote:
> >>>Hi Jacek,
> >>>
> >>>Jacek Anaszewski wrote:
> >>>>Ioctls executed on complex media devices need special handling.
> >>>>For instance some ioctls need to be targeted for specific sub-devices,
> >>>>depending on the media device configuration. The APIs being introduced
> >>>>address such requirements.
> >>>>
> >>>>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>>>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>>>---
> >>>>  utils/media-ctl/Makefile.am          |    2 +-
> >>>>  utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
> >>>>  utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
> >>>>  3 files changed, 453 insertions(+), 1 deletion(-)
> >>>>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
> >>>>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
> >>>>
> >>>>diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
> >>>>index 3e883e0..7f18624 100644
> >>>>--- a/utils/media-ctl/Makefile.am
> >>>>+++ b/utils/media-ctl/Makefile.am
> >>>>@@ -1,6 +1,6 @@
> >>>>  noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
> >>>>
> >>>>-libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
> >>>>+libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
> >>>>  libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
> >>>>  libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
> >>>>
> >>>>diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
> >>>>new file mode 100644
> >>>>index 0000000..b186121
> >>>>--- /dev/null
> >>>>+++ b/utils/media-ctl/libv4l2media_ioctl.c
> >>>>@@ -0,0 +1,404 @@
> >>>>+/*
> >>>>+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
> >>>>+ *              http://www.samsung.com
> >>>>+ *
> >>>>+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>>>+ *
> >>>>+ * This program is free software; you can redistribute it and/or modify
> >>>>+ * it under the terms of the GNU Lesser General Public License as published by
> >>>>+ * the Free Software Foundation; either version 2.1 of the License, or
> >>>>+ * (at your option) any later version.
> >>>>+ *
> >>>>+ * This program is distributed in the hope that it will be useful,
> >>>>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>>>+ * Lesser General Public License for more details.
> >>>>+ */
> >>>>+
> >>>>+#include <errno.h>
> >>>>+#include <stdlib.h>
> >>>>+#include <sys/syscall.h>
> >>>>+#include <unistd.h>
> >>>>+
> >>>>+#include <linux/videodev2.h>
> >>>>+
> >>>>+#include "libv4l2media_ioctl.h"
> >>>>+#include "mediactl-priv.h"
> >>>>+#include "mediactl.h"
> >>>>+#include "v4l2subdev.h"
> >>>>+
> >>>>+#define VIDIOC_CTRL(type)					\
> >>>>+	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
> >>>>+				   "VIDIOC_G_CTRL")
> >>>>+
> >>>>+#define VIDIOC_EXT_CTRL(type)					\
> >>>>+	((type) == VIDIOC_S_EXT_CTRLS ? 			\
> >>>>+		"VIDIOC_S_EXT_CTRLS"	:			\
> >>>>+		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
> >>>>+				    "VIDIOC_G_EXT_CTRLS" :	\
> >>>>+				    "VIDIOC_TRY_EXT_CTRLS"))
> >>>>+
> >>>>+#define SYS_IOCTL(fd, cmd, arg) \
> >>>>+	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
> >>>>+
> >>>>+
> >>>>+int media_ioctl_ctrl(struct media_device *media, int request,
> >>>
> >>>unsigned int request
> >>
> >>OK.
> >>
> >>>
> >>>>+		     struct v4l2_control *arg)
> >>>
> >>>I wonder if it'd make sense to always use v4l2_ext_control instead. You
> >>>can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.
> >>
> >>This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
> >>For ext ctrls there is media_ioctl_ext_ctrl().
> >
> >Is there any reason not to use extended control always?
> >
> >In other words, do we have a driver that does support Media controller but
> >does not support extended controls?
> 
> Shouldn't we support non-extended controls for backward compatibility
> reasons? I am not aware of the policy in this matter.

To put it bluntly, supporting the non-extended controls in this use is waste
of time IMHO.

> 
> >>>As this is a user space library, I'd probably add a function to handle
> >>>S/G/TRY control each.
> >>
> >>There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
> >>VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.
> >>
> >>>Have you considered binding the control to a video node rather than a
> >>>media device? We have many sensors on current media devices already, and
> >>>e.g. exposure time control can be found in multiple sub-devices.
> >>
> >>Doesn't v4l2-ctrl-redir config entry address that?
> >
> >How does it work if you have, say, two video nodes where you can capture
> >images from a different sensor? I.e. your media graph could look like this:
> >
> >	sensor0 -> CSI-2 0 -> video0
> >
> >	sensor1 -> CSI-2 1 -> video1
> 
> Exemplary config settings for this case:
> 
> v4l2-ctrl-redir 0x0098091f -> "sensor0"
> v4l2-ctrl-redir 0x0098091f -> "sensor1"
> 
> In media_ioctl_ctrl the v4l2_subdev_get_pipeline_entity_by_cid(media,
> ctrl.id) is called which walks through the pipeline and checks if there
> has been a v4l2 control redirection defined for given entity.

That's still based on media device, not video device. Two video devices may
be part of different pipelines, and a different sensor as well.

Redirecting the controls should be based on a video node, not media device.

> 
> If no redirection is defined then the control is set on the first
> entity in the pipeline that supports it. Effectively, for this
> arrangement no redirection would be required if the control
> is to be set on sensors. It would be required if we wanted
> to bind the control to the videoN entity. Now I am wondering
> if I should change the entry name to v4l2-ctrl-binding, or maybe
> someone has better idea?
> 
> BTW, are there some unique identifiers added to the entity names if
> more than one entity of a name is to be registered? E.g. what would
> happen if I had two S5C73M3 sensors in a media device? I assumed that
> entity names are unique.

Yes. Currently we've got away with the problem by adding the i2c address of
i2c devices to the entity name. The proper solution (there was a lengthy
discussion on it ~ a year ago, too late to try to find out exactly when)
would be to provide all the available information on the entity to the user
space using the property API (which we don't have yet). The entity name
remains unique in most situations but it's not necessarily stable.

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 01/15] mediactl: Introduce v4l2_subdev structure
  2016-03-20 23:39       ` Sakari Ailus
@ 2016-03-22  9:26         ` Jacek Anaszewski
  0 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-03-22  9:26 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

On 03/21/2016 12:39 AM, Sakari Ailus wrote:
> Hi Jacek,
>
> On Thu, Feb 18, 2016 at 03:15:32PM +0100, Jacek Anaszewski wrote:
>> Hi Sakari,
>>
>> Thanks for the review.
>>
>> On 02/12/2016 01:42 PM, Sakari Ailus wrote:
>>> Hi Jacek,
>>>
>>> Thanks for continuing this work! And my apologies for reviewing only
>>> now... please see the comments below.
>>>
>>> Jacek Anaszewski wrote:
>>>> Add struct v4l2_subdev - a representation of the v4l2 sub-device,
>>>> related to the media entity. Add field 'sd', the pointer to
>>>> the newly introduced structure, to the struct media_entity
>>>> and move 'fd' property from struct media entity to struct v4l2_subdev.
>>>> Avoid accessing sub-device file descriptor from libmediactl and
>>>> make the v4l2_subdev_open capable of creating the v4l2_subdev
>>>> if the 'sd' pointer is uninitialized.
>>>>
>>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>>> ---
>>>>   utils/media-ctl/libmediactl.c   |    4 --
>>>>   utils/media-ctl/libv4l2subdev.c |   82 +++++++++++++++++++++++++++++++--------
>>>>   utils/media-ctl/mediactl-priv.h |    5 ++-
>>>>   utils/media-ctl/v4l2subdev.h    |   38 ++++++++++++++++++
>>>>   4 files changed, 107 insertions(+), 22 deletions(-)
>>>>
>>>> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
>>>> index 4a82d24..7e98440 100644
>>>> --- a/utils/media-ctl/libmediactl.c
>>>> +++ b/utils/media-ctl/libmediactl.c
>>>> @@ -525,7 +525,6 @@ static int media_enum_entities(struct media_device *media)
>>>>
>>>>   		entity = &media->entities[media->entities_count];
>>>>   		memset(entity, 0, sizeof(*entity));
>>>> -		entity->fd = -1;
>>>>   		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
>>>>   		entity->media = media;
>>>>
>>>> @@ -719,8 +718,6 @@ void media_device_unref(struct media_device *media)
>>>>
>>>>   		free(entity->pads);
>>>>   		free(entity->links);
>>>> -		if (entity->fd != -1)
>>>> -			close(entity->fd);
>>>>   	}
>>>>
>>>>   	free(media->entities);
>>>> @@ -747,7 +744,6 @@ int media_device_add_entity(struct media_device *media,
>>>>   	entity = &media->entities[media->entities_count - 1];
>>>>   	memset(entity, 0, sizeof *entity);
>>>>
>>>> -	entity->fd = -1;
>>>>   	entity->media = media;
>>>>   	strncpy(entity->devname, devnode, sizeof entity->devname);
>>>>   	entity->devname[sizeof entity->devname - 1] = '\0';
>>>> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
>>>> index 33c1ee6..3977ce5 100644
>>>> --- a/utils/media-ctl/libv4l2subdev.c
>>>> +++ b/utils/media-ctl/libv4l2subdev.c
>>>> @@ -39,13 +39,61 @@
>>>>   #include "tools.h"
>>>>   #include "v4l2subdev.h"
>>>>
>>>> +int v4l2_subdev_create(struct media_entity *entity)
>>>> +{
>>>> +	if (entity->sd)
>>>> +		return 0;
>>>> +
>>>> +	entity->sd = calloc(1, sizeof(*entity->sd));
>>>> +	if (entity->sd == NULL)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	entity->sd->fd = -1;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +int v4l2_subdev_create_with_fd(struct media_entity *entity, int fd)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	if (entity->sd)
>>>> +		return -EEXIST;
>>>> +
>>>> +	ret = v4l2_subdev_create(entity);
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +
>>>> +	entity->sd->fd = fd;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +void v4l2_subdev_release(struct media_entity *entity, bool close_fd)
>>>> +{
>>>> +	if (entity->sd == NULL)
>>>> +		return;
>>>> +
>>>> +	if (close_fd)
>>>> +		v4l2_subdev_close(entity);
>>>> +
>>>> +	free(entity->sd->v4l2_control_redir);
>>>> +	free(entity->sd);
>>>> +}
>>>> +
>>>>   int v4l2_subdev_open(struct media_entity *entity)
>>>>   {
>>>> -	if (entity->fd != -1)
>>>> +	int ret;
>>>> +
>>>> +	ret = v4l2_subdev_create(entity);
>>>
>>> The current users of v4l2_subdev_open() in libv4l2subdev do not
>>> explicitly close the sub-devices they open; thus calling
>>> v4l2_subdev_create() here creates a memory leak.
>>
>> Currently in my use cases there is no memory leak since I assumed
>> that the one who instantiates struct media_device should take
>> care of releasing it properly. I added v4l2_subdev_open_pipeline()
>> and v4l2_subdev_release_pipeline() API that is called on plugin
>> init and close respectively.
>
> I'm referring to the use of the libv4l2subdev API as it's documented; the
> media-ctl test program which also serves as a good example on the API.
>
> Any sub-device IOCTL wrapper function will call v4l2_subdev_open() which
> stores the file descriptor returned by open(2) to struct media_entity.fd.
> v4l2_subdev_close() is not called explicitly. This is currently not
> required.
>
> The file handle is not leaked, as it is closed by media_device_unref() in
> libmediactl.
>
> This patch allocates memory for each sub-device in v4l2_subdev_create()
> which is in turn called from v4l2_subdev_open(). As the calls to
> v4l2_subdev_close() (which would release memory) are lacking, the memory is
> leaked.
>
>>
>> Probably it would be good to remove v4l2_subdev_open from
>> v4l2_subdev_* prefixed API and return error if sd property
>> of passed struct media_entity is not initialized.
>
> The purpose of the libv4l2subdev library is to make accessing sub-devices
> easier, and tossing that responsibility to the user is certainly not
> advancing that goal.
>
> I've been working on extending libmediatext library into an interactive test
> program for V4L2, V4L2 sub-device and Media controller. What I've noticed
> that libv4l2subdev does not currently bend really well for that purpose;
> the data structure holding the media graph is sort of self-contained and
> cannot be extended nor it can be used to refer to something else. That's a
> bit aside from the topic of this patch, but I presume that you'd need to
> associate information to media entities as well. For this reason I presume
> that releasing the resources related to a media entity acquired for e.g.
> IOCTL is not the right way to proceed.
>
> Instead, I think the libraries (libmediactl and libv4l2subdev) need to
> manage the resources (as has been done with file handles up to now).
>
> How about adding a callback to release resources related to an entity, e.g.
> as this:
>
> 	void (*release)(struct media_entity *entity);

Thanks for the comprehensive analysis and for this hint.
It sounds reasonable.

-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-03-21  0:07           ` Sakari Ailus
@ 2016-03-22  9:36             ` Jacek Anaszewski
  2016-03-23 16:24               ` Sakari Ailus
  0 siblings, 1 reply; 39+ messages in thread
From: Jacek Anaszewski @ 2016-03-22  9:36 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Sakari,

On 03/21/2016 01:07 AM, Sakari Ailus wrote:
> Hi Jacek,
>
> On Thu, Feb 18, 2016 at 02:14:40PM +0100, Jacek Anaszewski wrote:
>> Hi Sakari,
>>
>> On 02/18/2016 01:09 PM, Sakari Ailus wrote:
>>> Hi Jacek,
>>>
>>> On Mon, Feb 15, 2016 at 02:06:06PM +0100, Jacek Anaszewski wrote:
>>>> Hi Sakari,
>>>>
>>>> Thanks for the review.
>>>>
>>>> On 02/15/2016 01:41 PM, Sakari Ailus wrote:
>>>>> Hi Jacek,
>>>>>
>>>>> Jacek Anaszewski wrote:
>>>>>> Ioctls executed on complex media devices need special handling.
>>>>>> For instance some ioctls need to be targeted for specific sub-devices,
>>>>>> depending on the media device configuration. The APIs being introduced
>>>>>> address such requirements.
>>>>>>
>>>>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>>>>> ---
>>>>>>   utils/media-ctl/Makefile.am          |    2 +-
>>>>>>   utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
>>>>>>   utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
>>>>>>   3 files changed, 453 insertions(+), 1 deletion(-)
>>>>>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
>>>>>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
>>>>>>
>>>>>> diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
>>>>>> index 3e883e0..7f18624 100644
>>>>>> --- a/utils/media-ctl/Makefile.am
>>>>>> +++ b/utils/media-ctl/Makefile.am
>>>>>> @@ -1,6 +1,6 @@
>>>>>>   noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
>>>>>>
>>>>>> -libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
>>>>>> +libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
>>>>>>   libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
>>>>>>   libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
>>>>>>
>>>>>> diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
>>>>>> new file mode 100644
>>>>>> index 0000000..b186121
>>>>>> --- /dev/null
>>>>>> +++ b/utils/media-ctl/libv4l2media_ioctl.c
>>>>>> @@ -0,0 +1,404 @@
>>>>>> +/*
>>>>>> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
>>>>>> + *              http://www.samsung.com
>>>>>> + *
>>>>>> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>>>> + *
>>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>>> + * it under the terms of the GNU Lesser General Public License as published by
>>>>>> + * the Free Software Foundation; either version 2.1 of the License, or
>>>>>> + * (at your option) any later version.
>>>>>> + *
>>>>>> + * This program is distributed in the hope that it will be useful,
>>>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>>>> + * Lesser General Public License for more details.
>>>>>> + */
>>>>>> +
>>>>>> +#include <errno.h>
>>>>>> +#include <stdlib.h>
>>>>>> +#include <sys/syscall.h>
>>>>>> +#include <unistd.h>
>>>>>> +
>>>>>> +#include <linux/videodev2.h>
>>>>>> +
>>>>>> +#include "libv4l2media_ioctl.h"
>>>>>> +#include "mediactl-priv.h"
>>>>>> +#include "mediactl.h"
>>>>>> +#include "v4l2subdev.h"
>>>>>> +
>>>>>> +#define VIDIOC_CTRL(type)					\
>>>>>> +	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
>>>>>> +				   "VIDIOC_G_CTRL")
>>>>>> +
>>>>>> +#define VIDIOC_EXT_CTRL(type)					\
>>>>>> +	((type) == VIDIOC_S_EXT_CTRLS ? 			\
>>>>>> +		"VIDIOC_S_EXT_CTRLS"	:			\
>>>>>> +		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
>>>>>> +				    "VIDIOC_G_EXT_CTRLS" :	\
>>>>>> +				    "VIDIOC_TRY_EXT_CTRLS"))
>>>>>> +
>>>>>> +#define SYS_IOCTL(fd, cmd, arg) \
>>>>>> +	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
>>>>>> +
>>>>>> +
>>>>>> +int media_ioctl_ctrl(struct media_device *media, int request,
>>>>>
>>>>> unsigned int request
>>>>
>>>> OK.
>>>>
>>>>>
>>>>>> +		     struct v4l2_control *arg)
>>>>>
>>>>> I wonder if it'd make sense to always use v4l2_ext_control instead. You
>>>>> can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.
>>>>
>>>> This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
>>>> For ext ctrls there is media_ioctl_ext_ctrl().
>>>
>>> Is there any reason not to use extended control always?
>>>
>>> In other words, do we have a driver that does support Media controller but
>>> does not support extended controls?
>>
>> Shouldn't we support non-extended controls for backward compatibility
>> reasons? I am not aware of the policy in this matter.
>
> To put it bluntly, supporting the non-extended controls in this use is waste
> of time IMHO.

OK, I'll drop the non-ext controls related API then.

>>>>> As this is a user space library, I'd probably add a function to handle
>>>>> S/G/TRY control each.
>>>>
>>>> There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
>>>> VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.
>>>>
>>>>> Have you considered binding the control to a video node rather than a
>>>>> media device? We have many sensors on current media devices already, and
>>>>> e.g. exposure time control can be found in multiple sub-devices.
>>>>
>>>> Doesn't v4l2-ctrl-redir config entry address that?
>>>
>>> How does it work if you have, say, two video nodes where you can capture
>>> images from a different sensor? I.e. your media graph could look like this:
>>>
>>> 	sensor0 -> CSI-2 0 -> video0
>>>
>>> 	sensor1 -> CSI-2 1 -> video1
>>
>> Exemplary config settings for this case:
>>
>> v4l2-ctrl-redir 0x0098091f -> "sensor0"
>> v4l2-ctrl-redir 0x0098091f -> "sensor1"
>>
>> In media_ioctl_ctrl the v4l2_subdev_get_pipeline_entity_by_cid(media,
>> ctrl.id) is called which walks through the pipeline and checks if there
>> has been a v4l2 control redirection defined for given entity.
>
> That's still based on media device, not video device. Two video devices may
> be part of different pipelines, and a different sensor as well.
 >
> Redirecting the controls should be based on a video node, not media device.

Why do you consider it as based on a media device? I'd rather say that
it is based on media entity, so indirectly based on media device.
Is it what you have on mind?

>>
>> If no redirection is defined then the control is set on the first
>> entity in the pipeline that supports it. Effectively, for this
>> arrangement no redirection would be required if the control
>> is to be set on sensors. It would be required if we wanted
>> to bind the control to the videoN entity. Now I am wondering
>> if I should change the entry name to v4l2-ctrl-binding, or maybe
>> someone has better idea?
>>
>> BTW, are there some unique identifiers added to the entity names if
>> more than one entity of a name is to be registered? E.g. what would
>> happen if I had two S5C73M3 sensors in a media device? I assumed that
>> entity names are unique.
>
> Yes. Currently we've got away with the problem by adding the i2c address of
> i2c devices to the entity name. The proper solution (there was a lengthy
> discussion on it ~ a year ago, too late to try to find out exactly when)
> would be to provide all the available information on the entity to the user
> space using the property API (which we don't have yet). The entity name
> remains unique in most situations but it's not necessarily stable.
>

I assume that the fact that they're not stable mean that we cannot rely
on the entity name. Using sub-dev names and video device names seems
reasonable then.

-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-03-22  9:36             ` Jacek Anaszewski
@ 2016-03-23 16:24               ` Sakari Ailus
  2016-03-24 15:55                 ` Jacek Anaszewski
  0 siblings, 1 reply; 39+ messages in thread
From: Sakari Ailus @ 2016-03-23 16:24 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

Hi Jacek,

On Tue, Mar 22, 2016 at 10:36:05AM +0100, Jacek Anaszewski wrote:
> Hi Sakari,
> 
> On 03/21/2016 01:07 AM, Sakari Ailus wrote:
> >Hi Jacek,
> >
> >On Thu, Feb 18, 2016 at 02:14:40PM +0100, Jacek Anaszewski wrote:
> >>Hi Sakari,
> >>
> >>On 02/18/2016 01:09 PM, Sakari Ailus wrote:
> >>>Hi Jacek,
> >>>
> >>>On Mon, Feb 15, 2016 at 02:06:06PM +0100, Jacek Anaszewski wrote:
> >>>>Hi Sakari,
> >>>>
> >>>>Thanks for the review.
> >>>>
> >>>>On 02/15/2016 01:41 PM, Sakari Ailus wrote:
> >>>>>Hi Jacek,
> >>>>>
> >>>>>Jacek Anaszewski wrote:
> >>>>>>Ioctls executed on complex media devices need special handling.
> >>>>>>For instance some ioctls need to be targeted for specific sub-devices,
> >>>>>>depending on the media device configuration. The APIs being introduced
> >>>>>>address such requirements.
> >>>>>>
> >>>>>>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>>>>>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>>>>>---
> >>>>>>  utils/media-ctl/Makefile.am          |    2 +-
> >>>>>>  utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
> >>>>>>  utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
> >>>>>>  3 files changed, 453 insertions(+), 1 deletion(-)
> >>>>>>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
> >>>>>>  create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
> >>>>>>
> >>>>>>diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
> >>>>>>index 3e883e0..7f18624 100644
> >>>>>>--- a/utils/media-ctl/Makefile.am
> >>>>>>+++ b/utils/media-ctl/Makefile.am
> >>>>>>@@ -1,6 +1,6 @@
> >>>>>>  noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
> >>>>>>
> >>>>>>-libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
> >>>>>>+libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
> >>>>>>  libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
> >>>>>>  libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
> >>>>>>
> >>>>>>diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
> >>>>>>new file mode 100644
> >>>>>>index 0000000..b186121
> >>>>>>--- /dev/null
> >>>>>>+++ b/utils/media-ctl/libv4l2media_ioctl.c
> >>>>>>@@ -0,0 +1,404 @@
> >>>>>>+/*
> >>>>>>+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
> >>>>>>+ *              http://www.samsung.com
> >>>>>>+ *
> >>>>>>+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>>>>>+ *
> >>>>>>+ * This program is free software; you can redistribute it and/or modify
> >>>>>>+ * it under the terms of the GNU Lesser General Public License as published by
> >>>>>>+ * the Free Software Foundation; either version 2.1 of the License, or
> >>>>>>+ * (at your option) any later version.
> >>>>>>+ *
> >>>>>>+ * This program is distributed in the hope that it will be useful,
> >>>>>>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>>>>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>>>>>+ * Lesser General Public License for more details.
> >>>>>>+ */
> >>>>>>+
> >>>>>>+#include <errno.h>
> >>>>>>+#include <stdlib.h>
> >>>>>>+#include <sys/syscall.h>
> >>>>>>+#include <unistd.h>
> >>>>>>+
> >>>>>>+#include <linux/videodev2.h>
> >>>>>>+
> >>>>>>+#include "libv4l2media_ioctl.h"
> >>>>>>+#include "mediactl-priv.h"
> >>>>>>+#include "mediactl.h"
> >>>>>>+#include "v4l2subdev.h"
> >>>>>>+
> >>>>>>+#define VIDIOC_CTRL(type)					\
> >>>>>>+	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
> >>>>>>+				   "VIDIOC_G_CTRL")
> >>>>>>+
> >>>>>>+#define VIDIOC_EXT_CTRL(type)					\
> >>>>>>+	((type) == VIDIOC_S_EXT_CTRLS ? 			\
> >>>>>>+		"VIDIOC_S_EXT_CTRLS"	:			\
> >>>>>>+		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
> >>>>>>+				    "VIDIOC_G_EXT_CTRLS" :	\
> >>>>>>+				    "VIDIOC_TRY_EXT_CTRLS"))
> >>>>>>+
> >>>>>>+#define SYS_IOCTL(fd, cmd, arg) \
> >>>>>>+	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
> >>>>>>+
> >>>>>>+
> >>>>>>+int media_ioctl_ctrl(struct media_device *media, int request,
> >>>>>
> >>>>>unsigned int request
> >>>>
> >>>>OK.
> >>>>
> >>>>>
> >>>>>>+		     struct v4l2_control *arg)
> >>>>>
> >>>>>I wonder if it'd make sense to always use v4l2_ext_control instead. You
> >>>>>can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.
> >>>>
> >>>>This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
> >>>>For ext ctrls there is media_ioctl_ext_ctrl().
> >>>
> >>>Is there any reason not to use extended control always?
> >>>
> >>>In other words, do we have a driver that does support Media controller but
> >>>does not support extended controls?
> >>
> >>Shouldn't we support non-extended controls for backward compatibility
> >>reasons? I am not aware of the policy in this matter.
> >
> >To put it bluntly, supporting the non-extended controls in this use is waste
> >of time IMHO.
> 
> OK, I'll drop the non-ext controls related API then.
> 
> >>>>>As this is a user space library, I'd probably add a function to handle
> >>>>>S/G/TRY control each.
> >>>>
> >>>>There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
> >>>>VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.
> >>>>
> >>>>>Have you considered binding the control to a video node rather than a
> >>>>>media device? We have many sensors on current media devices already, and
> >>>>>e.g. exposure time control can be found in multiple sub-devices.
> >>>>
> >>>>Doesn't v4l2-ctrl-redir config entry address that?
> >>>
> >>>How does it work if you have, say, two video nodes where you can capture
> >>>images from a different sensor? I.e. your media graph could look like this:
> >>>
> >>>	sensor0 -> CSI-2 0 -> video0
> >>>
> >>>	sensor1 -> CSI-2 1 -> video1
> >>
> >>Exemplary config settings for this case:
> >>
> >>v4l2-ctrl-redir 0x0098091f -> "sensor0"
> >>v4l2-ctrl-redir 0x0098091f -> "sensor1"
> >>
> >>In media_ioctl_ctrl the v4l2_subdev_get_pipeline_entity_by_cid(media,
> >>ctrl.id) is called which walks through the pipeline and checks if there
> >>has been a v4l2 control redirection defined for given entity.
> >
> >That's still based on media device, not video device. Two video devices may
> >be part of different pipelines, and a different sensor as well.
> >
> >Redirecting the controls should be based on a video node, not media device.
> 
> Why do you consider it as based on a media device? I'd rather say that
> it is based on media entity, so indirectly based on media device.
> Is it what you have on mind?

The first argument of the functions in the patch is a pointer ot the media
device, not the media entity.

> 
> >>
> >>If no redirection is defined then the control is set on the first
> >>entity in the pipeline that supports it. Effectively, for this
> >>arrangement no redirection would be required if the control
> >>is to be set on sensors. It would be required if we wanted
> >>to bind the control to the videoN entity. Now I am wondering
> >>if I should change the entry name to v4l2-ctrl-binding, or maybe
> >>someone has better idea?
> >>
> >>BTW, are there some unique identifiers added to the entity names if
> >>more than one entity of a name is to be registered? E.g. what would
> >>happen if I had two S5C73M3 sensors in a media device? I assumed that
> >>entity names are unique.
> >
> >Yes. Currently we've got away with the problem by adding the i2c address of
> >i2c devices to the entity name. The proper solution (there was a lengthy
> >discussion on it ~ a year ago, too late to try to find out exactly when)
> >would be to provide all the available information on the entity to the user
> >space using the property API (which we don't have yet). The entity name
> >remains unique in most situations but it's not necessarily stable.
> >
> 
> I assume that the fact that they're not stable mean that we cannot rely
> on the entity name. Using sub-dev names and video device names seems
> reasonable then.

They're even less so, unfortunately; the device nodes depend e.g. on the
initialisation order an other devices. Please use the entity names, they're
the best option for now.

I wish I'll have some time to proceed the work on the property API. So many
things to do, but so little time. :-I

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 13/15] mediactl: Add media device ioctl API
  2016-03-23 16:24               ` Sakari Ailus
@ 2016-03-24 15:55                 ` Jacek Anaszewski
  0 siblings, 0 replies; 39+ messages in thread
From: Jacek Anaszewski @ 2016-03-24 15:55 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Sakari Ailus, linux-media, laurent.pinchart, gjasny, hdegoede, hverkuil

On 03/23/2016 05:24 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> On Tue, Mar 22, 2016 at 10:36:05AM +0100, Jacek Anaszewski wrote:
>> Hi Sakari,
>>
>> On 03/21/2016 01:07 AM, Sakari Ailus wrote:
>>> Hi Jacek,
>>>
>>> On Thu, Feb 18, 2016 at 02:14:40PM +0100, Jacek Anaszewski wrote:
>>>> Hi Sakari,
>>>>
>>>> On 02/18/2016 01:09 PM, Sakari Ailus wrote:
>>>>> Hi Jacek,
>>>>>
>>>>> On Mon, Feb 15, 2016 at 02:06:06PM +0100, Jacek Anaszewski wrote:
>>>>>> Hi Sakari,
>>>>>>
>>>>>> Thanks for the review.
>>>>>>
>>>>>> On 02/15/2016 01:41 PM, Sakari Ailus wrote:
>>>>>>> Hi Jacek,
>>>>>>>
>>>>>>> Jacek Anaszewski wrote:
>>>>>>>> Ioctls executed on complex media devices need special handling.
>>>>>>>> For instance some ioctls need to be targeted for specific sub-devices,
>>>>>>>> depending on the media device configuration. The APIs being introduced
>>>>>>>> address such requirements.
>>>>>>>>
>>>>>>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>>>>>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>>>>>>>> ---
>>>>>>>>   utils/media-ctl/Makefile.am          |    2 +-
>>>>>>>>   utils/media-ctl/libv4l2media_ioctl.c |  404 ++++++++++++++++++++++++++++++++++
>>>>>>>>   utils/media-ctl/libv4l2media_ioctl.h |   48 ++++
>>>>>>>>   3 files changed, 453 insertions(+), 1 deletion(-)
>>>>>>>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.c
>>>>>>>>   create mode 100644 utils/media-ctl/libv4l2media_ioctl.h
>>>>>>>>
>>>>>>>> diff --git a/utils/media-ctl/Makefile.am b/utils/media-ctl/Makefile.am
>>>>>>>> index 3e883e0..7f18624 100644
>>>>>>>> --- a/utils/media-ctl/Makefile.am
>>>>>>>> +++ b/utils/media-ctl/Makefile.am
>>>>>>>> @@ -1,6 +1,6 @@
>>>>>>>>   noinst_LTLIBRARIES = libmediactl.la libv4l2subdev.la libmediatext.la
>>>>>>>>
>>>>>>>> -libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h
>>>>>>>> +libmediactl_la_SOURCES = libmediactl.c mediactl-priv.h libv4l2media_ioctl.c libv4l2media_ioctl.h
>>>>>>>>   libmediactl_la_CFLAGS = -static $(LIBUDEV_CFLAGS)
>>>>>>>>   libmediactl_la_LDFLAGS = -static $(LIBUDEV_LIBS)
>>>>>>>>
>>>>>>>> diff --git a/utils/media-ctl/libv4l2media_ioctl.c b/utils/media-ctl/libv4l2media_ioctl.c
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..b186121
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/utils/media-ctl/libv4l2media_ioctl.c
>>>>>>>> @@ -0,0 +1,404 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
>>>>>>>> + *              http://www.samsung.com
>>>>>>>> + *
>>>>>>>> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>>>>>>>> + *
>>>>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>>>>> + * it under the terms of the GNU Lesser General Public License as published by
>>>>>>>> + * the Free Software Foundation; either version 2.1 of the License, or
>>>>>>>> + * (at your option) any later version.
>>>>>>>> + *
>>>>>>>> + * This program is distributed in the hope that it will be useful,
>>>>>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>>>>>> + * Lesser General Public License for more details.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include <errno.h>
>>>>>>>> +#include <stdlib.h>
>>>>>>>> +#include <sys/syscall.h>
>>>>>>>> +#include <unistd.h>
>>>>>>>> +
>>>>>>>> +#include <linux/videodev2.h>
>>>>>>>> +
>>>>>>>> +#include "libv4l2media_ioctl.h"
>>>>>>>> +#include "mediactl-priv.h"
>>>>>>>> +#include "mediactl.h"
>>>>>>>> +#include "v4l2subdev.h"
>>>>>>>> +
>>>>>>>> +#define VIDIOC_CTRL(type)					\
>>>>>>>> +	((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" :		\
>>>>>>>> +				   "VIDIOC_G_CTRL")
>>>>>>>> +
>>>>>>>> +#define VIDIOC_EXT_CTRL(type)					\
>>>>>>>> +	((type) == VIDIOC_S_EXT_CTRLS ? 			\
>>>>>>>> +		"VIDIOC_S_EXT_CTRLS"	:			\
>>>>>>>> +		 ((type) == VIDIOC_G_EXT_CTRLS ? 		\
>>>>>>>> +				    "VIDIOC_G_EXT_CTRLS" :	\
>>>>>>>> +				    "VIDIOC_TRY_EXT_CTRLS"))
>>>>>>>> +
>>>>>>>> +#define SYS_IOCTL(fd, cmd, arg) \
>>>>>>>> +	syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +int media_ioctl_ctrl(struct media_device *media, int request,
>>>>>>>
>>>>>>> unsigned int request
>>>>>>
>>>>>> OK.
>>>>>>
>>>>>>>
>>>>>>>> +		     struct v4l2_control *arg)
>>>>>>>
>>>>>>> I wonder if it'd make sense to always use v4l2_ext_control instead. You
>>>>>>> can't access 64-bit integer controls with VIDIOC_S_CTRL for instance.
>>>>>>
>>>>>> This function is meant to handle VIDIOC_S_CTRL/VIDIOC_G_CTRL ioctls.
>>>>>> For ext ctrls there is media_ioctl_ext_ctrl().
>>>>>
>>>>> Is there any reason not to use extended control always?
>>>>>
>>>>> In other words, do we have a driver that does support Media controller but
>>>>> does not support extended controls?
>>>>
>>>> Shouldn't we support non-extended controls for backward compatibility
>>>> reasons? I am not aware of the policy in this matter.
>>>
>>> To put it bluntly, supporting the non-extended controls in this use is waste
>>> of time IMHO.
>>
>> OK, I'll drop the non-ext controls related API then.
>>
>>>>>>> As this is a user space library, I'd probably add a function to handle
>>>>>>> S/G/TRY control each.
>>>>>>
>>>>>> There is media_ioctl_ext_ctrl() that handles VIDIOC_S_EXT_CTRLS,
>>>>>> VIDIOC_G_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS.
>>>>>>
>>>>>>> Have you considered binding the control to a video node rather than a
>>>>>>> media device? We have many sensors on current media devices already, and
>>>>>>> e.g. exposure time control can be found in multiple sub-devices.
>>>>>>
>>>>>> Doesn't v4l2-ctrl-redir config entry address that?
>>>>>
>>>>> How does it work if you have, say, two video nodes where you can capture
>>>>> images from a different sensor? I.e. your media graph could look like this:
>>>>>
>>>>> 	sensor0 -> CSI-2 0 -> video0
>>>>>
>>>>> 	sensor1 -> CSI-2 1 -> video1
>>>>
>>>> Exemplary config settings for this case:
>>>>
>>>> v4l2-ctrl-redir 0x0098091f -> "sensor0"
>>>> v4l2-ctrl-redir 0x0098091f -> "sensor1"
>>>>
>>>> In media_ioctl_ctrl the v4l2_subdev_get_pipeline_entity_by_cid(media,
>>>> ctrl.id) is called which walks through the pipeline and checks if there
>>>> has been a v4l2 control redirection defined for given entity.
>>>
>>> That's still based on media device, not video device. Two video devices may
>>> be part of different pipelines, and a different sensor as well.
>>>
>>> Redirecting the controls should be based on a video node, not media device.
>>
>> Why do you consider it as based on a media device? I'd rather say that
>> it is based on media entity, so indirectly based on media device.
>> Is it what you have on mind?
>
> The first argument of the functions in the patch is a pointer ot the media
> device, not the media entity.

OK, so could you precise what you mean by binding the control to video
node rather to a media device? How would you see the config and the API?
Maybe some config example would allow me to catch the gist of your idea.

>>
>>>>
>>>> If no redirection is defined then the control is set on the first
>>>> entity in the pipeline that supports it. Effectively, for this
>>>> arrangement no redirection would be required if the control
>>>> is to be set on sensors. It would be required if we wanted
>>>> to bind the control to the videoN entity. Now I am wondering
>>>> if I should change the entry name to v4l2-ctrl-binding, or maybe
>>>> someone has better idea?
>>>>
>>>> BTW, are there some unique identifiers added to the entity names if
>>>> more than one entity of a name is to be registered? E.g. what would
>>>> happen if I had two S5C73M3 sensors in a media device? I assumed that
>>>> entity names are unique.
>>>
>>> Yes. Currently we've got away with the problem by adding the i2c address of
>>> i2c devices to the entity name. The proper solution (there was a lengthy
>>> discussion on it ~ a year ago, too late to try to find out exactly when)
>>> would be to provide all the available information on the entity to the user
>>> space using the property API (which we don't have yet). The entity name
>>> remains unique in most situations but it's not necessarily stable.
>>>
>>
>> I assume that the fact that they're not stable mean that we cannot rely
>> on the entity name. Using sub-dev names and video device names seems
>> reasonable then.
>
> They're even less so, unfortunately; the device nodes depend e.g. on the
> initialisation order an other devices. Please use the entity names, they're
> the best option for now.

OK.

> I wish I'll have some time to proceed the work on the property API. So many
> things to do, but so little time. :-I
>

I know that feel :-|

-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2016-03-24 15:55 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-18 16:17 [PATCH 00/15] Add a plugin for Exynos4 camera Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 01/15] mediactl: Introduce v4l2_subdev structure Jacek Anaszewski
2016-02-12 12:42   ` Sakari Ailus
2016-02-18 14:15     ` Jacek Anaszewski
2016-03-20 23:39       ` Sakari Ailus
2016-03-22  9:26         ` Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 02/15] mediactl: Add support for v4l2-ctrl-redir config Jacek Anaszewski
2016-02-15 10:58   ` Sakari Ailus
2016-02-15 11:39     ` Jacek Anaszewski
2016-02-15 12:22       ` Sakari Ailus
2016-01-18 16:17 ` [PATCH 03/15] mediactl: Separate entity and pad parsing Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 04/15] mediatext: Add library Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 05/15] mediactl: Add media device graph helpers Jacek Anaszewski
2016-02-15 12:02   ` Sakari Ailus
2016-02-15 12:45     ` Jacek Anaszewski
2016-02-15 14:14       ` Sakari Ailus
2016-02-15 14:57         ` Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 06/15] mediactl: Add media_device creation helpers Jacek Anaszewski
2016-02-15 14:30   ` Sakari Ailus
2016-01-18 16:17 ` [PATCH 07/15] mediactl: libv4l2subdev: add VYUY8_2X8 mbus code Jacek Anaszewski
2016-02-15 15:55   ` Sakari Ailus
2016-01-18 16:17 ` [PATCH 08/15] mediactl: Add support for media device pipelines Jacek Anaszewski
2016-02-15 16:53   ` Sakari Ailus
2016-02-16  9:19     ` Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 09/15] mediactl: libv4l2subdev: Add colorspace logging Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 10/15] mediactl: libv4l2subdev: add support for comparing mbus formats Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 11/15] mediactl: libv4l2subdev: add support for setting pipeline format Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 12/15] mediactl: libv4l2subdev: add get_pipeline_entity_by_cid function Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 13/15] mediactl: Add media device ioctl API Jacek Anaszewski
2016-02-15 12:41   ` Sakari Ailus
2016-02-15 13:06     ` Jacek Anaszewski
2016-02-18 12:09       ` Sakari Ailus
2016-02-18 13:14         ` Jacek Anaszewski
2016-03-21  0:07           ` Sakari Ailus
2016-03-22  9:36             ` Jacek Anaszewski
2016-03-23 16:24               ` Sakari Ailus
2016-03-24 15:55                 ` Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 14/15] mediactl: libv4l2subdev: Enable opening/closing pipelines Jacek Anaszewski
2016-01-18 16:17 ` [PATCH 15/15] Add a libv4l plugin for Exynos4 camera Jacek Anaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).