* [v4l-utils RFC v3 01/11] mediactl: Introduce ctrl_to_subdev configuration
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 12:20 ` Sakari Ailus
2014-11-06 10:11 ` [v4l-utils RFC v3 02/11] mediactl: Separate entity and pad parsing Jacek Anaszewski
` (9 subsequent siblings)
10 siblings, 1 reply; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, Jacek Anaszewski
Add an infrastructure for a ctrl_to_subdev configuration
data. The ctrl_to_subdev config entry is designed for
conveying information about the target sub-device
in the media device pipeline for a v4l2 control related
ioctl calls.
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
utils/media-ctl/libmediactl.c | 26 ++++++++++++++++++++++++++
utils/media-ctl/libv4l2subdev.c | 31 +++++++++++++++++++++++++++++++
utils/media-ctl/mediactl-priv.h | 8 ++++++++
utils/media-ctl/mediactl.h | 16 ++++++++++++++++
utils/media-ctl/v4l2subdev.h | 15 +++++++++++++++
5 files changed, 96 insertions(+)
diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index ec360bd..795aaad 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -647,12 +647,20 @@ static struct media_device *__media_device_new(void)
if (media == NULL)
return NULL;
+ media->ctrl_to_subdev = malloc(sizeof(*media->ctrl_to_subdev));
+ if (!media->ctrl_to_subdev)
+ goto err_cts_alloc;
+
media->fd = -1;
media->refcount = 1;
media_debug_set_handler(media, NULL, NULL);
return media;
+
+err_cts_alloc:
+ free(media);
+ return NULL;
}
struct media_device *media_device_new(const char *devnode)
@@ -710,6 +718,7 @@ void media_device_unref(struct media_device *media)
free(media->entities);
free(media->devnode);
+ free(media->ctrl_to_subdev);
free(media);
}
@@ -955,3 +964,20 @@ int media_parse_setup_links(struct media_device *media, const char *p)
return *end ? -EINVAL : 0;
}
+
+/* -----------------------------------------------------------------------------
+ * Configuration access
+ */
+
+struct media_entity *media_config_get_entity_by_cid(struct media_device *media,
+ int cid)
+{
+ int i;
+
+ for (i = 0; i < media->ctrl_to_subdev_count; ++i) {
+ if (media->ctrl_to_subdev[i].ctrl_id == cid)
+ return media->ctrl_to_subdev[i].entity;
+ }
+
+ return NULL;
+}
diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 8015330..99ac6b2 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -755,3 +755,34 @@ enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
return mbus_formats[i].code;
}
+
+int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
+ struct media_entity *entity,
+ __u32 ctrl_id)
+{
+ struct v4l2_query_ext_ctrl queryctrl;
+ int ret;
+
+ ret = v4l2_subdev_open(entity);
+ if (ret < 0)
+ return ret;
+
+ /* Iterate through control ids */
+
+ queryctrl.id = ctrl_id;
+
+ ret = ioctl(entity->fd, VIDIOC_QUERY_EXT_CTRL, &queryctrl);
+ if (!ret) {
+ media_dbg(media, "Validated control \"%s\" (0x%8.8x) on entity %s\n",
+ queryctrl.name,
+ ctrl_id,
+ entity->info.name);
+ return 1;
+ }
+
+ media_dbg(media, "Control (0x%8.8x) not supported on entity %s\n",
+ queryctrl.name,
+ ctrl_id,
+ entity->info.name);
+ return 0;
+}
diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
index a0d3a55..b9e9b20 100644
--- a/utils/media-ctl/mediactl-priv.h
+++ b/utils/media-ctl/mediactl-priv.h
@@ -47,6 +47,9 @@ struct media_device {
struct media_entity *entities;
unsigned int entities_count;
+ struct media_v4l2_ctrl_to_subdev *ctrl_to_subdev;
+ unsigned int ctrl_to_subdev_count;
+
void (*debug_handler)(void *, ...);
void *debug_priv;
@@ -58,6 +61,11 @@ struct media_device {
} def;
};
+struct media_v4l2_ctrl_to_subdev {
+ __u32 ctrl_id;
+ struct media_entity *entity;
+};
+
#define media_dbg(media, ...) \
(media)->debug_handler((media)->debug_priv, __VA_ARGS__)
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 77ac182..e358242 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -420,4 +420,20 @@ int media_parse_setup_link(struct media_device *media,
*/
int media_parse_setup_links(struct media_device *media, const char *p);
+/**
+ * @brief Find target sub-device for the control
+ * @param media - media device.
+ * @param cid - v4l2 control identifier
+ *
+ * Check if there was a target sub-device defined
+ * for the control through a ctrl-to-subdev-conf config
+ * directive.
+ *
+ * @return associated entity if defined, or NULL when no
+ * config entry for the control was found
+ */
+struct media_entity *media_config_get_entity_by_cid(
+ struct media_device *media,
+ int cid);
+
#endif
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index 1cb53ff..3bc0412 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -255,4 +255,19 @@ const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code);
*/
enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(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 - v4l2 control identifier
+ *
+ * Verify if the entity supports v4l2-control with 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);
+
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [v4l-utils RFC v3 01/11] mediactl: Introduce ctrl_to_subdev configuration
2014-11-06 10:11 ` [v4l-utils RFC v3 01/11] mediactl: Introduce ctrl_to_subdev configuration Jacek Anaszewski
@ 2014-11-06 12:20 ` Sakari Ailus
0 siblings, 0 replies; 13+ messages in thread
From: Sakari Ailus @ 2014-11-06 12:20 UTC (permalink / raw)
To: Jacek Anaszewski
Cc: linux-media, m.chehab, gjasny, hdegoede, hans.verkuil,
b.zolnierkie, kyungmin.park
Hi Jacek,
Thanks for the update!
A few comments below.
On Thu, Nov 06, 2014 at 11:11:32AM +0100, Jacek Anaszewski wrote:
> Add an infrastructure for a ctrl_to_subdev configuration
> data. The ctrl_to_subdev config entry is designed for
> conveying information about the target sub-device
> in the media device pipeline for a v4l2 control related
> ioctl calls.
>
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> utils/media-ctl/libmediactl.c | 26 ++++++++++++++++++++++++++
> utils/media-ctl/libv4l2subdev.c | 31 +++++++++++++++++++++++++++++++
> utils/media-ctl/mediactl-priv.h | 8 ++++++++
> utils/media-ctl/mediactl.h | 16 ++++++++++++++++
> utils/media-ctl/v4l2subdev.h | 15 +++++++++++++++
> 5 files changed, 96 insertions(+)
>
> diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
> index ec360bd..795aaad 100644
> --- a/utils/media-ctl/libmediactl.c
> +++ b/utils/media-ctl/libmediactl.c
> @@ -647,12 +647,20 @@ static struct media_device *__media_device_new(void)
> if (media == NULL)
> return NULL;
>
> + media->ctrl_to_subdev = malloc(sizeof(*media->ctrl_to_subdev));
> + if (!media->ctrl_to_subdev)
> + goto err_cts_alloc;
> +
> media->fd = -1;
> media->refcount = 1;
>
> media_debug_set_handler(media, NULL, NULL);
>
> return media;
> +
> +err_cts_alloc:
> + free(media);
> + return NULL;
> }
>
> struct media_device *media_device_new(const char *devnode)
> @@ -710,6 +718,7 @@ void media_device_unref(struct media_device *media)
>
> free(media->entities);
> free(media->devnode);
> + free(media->ctrl_to_subdev);
> free(media);
> }
>
> @@ -955,3 +964,20 @@ int media_parse_setup_links(struct media_device *media, const char *p)
>
> return *end ? -EINVAL : 0;
> }
> +
> +/* -----------------------------------------------------------------------------
> + * Configuration access
> + */
> +
> +struct media_entity *media_config_get_entity_by_cid(struct media_device *media,
> + int cid)
> +{
> + int i;
> +
> + for (i = 0; i < media->ctrl_to_subdev_count; ++i) {
> + if (media->ctrl_to_subdev[i].ctrl_id == cid)
> + return media->ctrl_to_subdev[i].entity;
> + }
> +
> + return NULL;
> +}
> diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
> index 8015330..99ac6b2 100644
> --- a/utils/media-ctl/libv4l2subdev.c
> +++ b/utils/media-ctl/libv4l2subdev.c
> @@ -755,3 +755,34 @@ enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
>
> return mbus_formats[i].code;
> }
> +
> +int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
> + struct media_entity *entity,
> + __u32 ctrl_id)
> +{
> + struct v4l2_query_ext_ctrl queryctrl;
> + int ret;
> +
> + ret = v4l2_subdev_open(entity);
> + if (ret < 0)
> + return ret;
> +
> + /* Iterate through control ids */
> +
> + queryctrl.id = ctrl_id;
> +
> + ret = ioctl(entity->fd, VIDIOC_QUERY_EXT_CTRL, &queryctrl);
> + if (!ret) {
> + media_dbg(media, "Validated control \"%s\" (0x%8.8x) on entity %s\n",
> + queryctrl.name,
Could you align the line start to right of the opening parenthesis?
> + ctrl_id,
> + entity->info.name);
> + return 1;
> + }
> +
> + media_dbg(media, "Control (0x%8.8x) not supported on entity %s\n",
> + queryctrl.name,
> + ctrl_id,
> + entity->info.name);
> + return 0;
> +}
> diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
> index a0d3a55..b9e9b20 100644
> --- a/utils/media-ctl/mediactl-priv.h
> +++ b/utils/media-ctl/mediactl-priv.h
> @@ -47,6 +47,9 @@ struct media_device {
> struct media_entity *entities;
> unsigned int entities_count;
>
> + struct media_v4l2_ctrl_to_subdev *ctrl_to_subdev;
> + unsigned int ctrl_to_subdev_count;
The media device shouldn't have information related to subsystems that use
it.
Instead of making this specific to controls, could you instead add a V4L2
(sub-device) specific pointer to each media entity? Controls information
could be stored there.
I think we're going to need other information there as well.
> +
> void (*debug_handler)(void *, ...);
> void *debug_priv;
>
> @@ -58,6 +61,11 @@ struct media_device {
> } def;
> };
>
> +struct media_v4l2_ctrl_to_subdev {
> + __u32 ctrl_id;
> + struct media_entity *entity;
> +};
> +
> #define media_dbg(media, ...) \
> (media)->debug_handler((media)->debug_priv, __VA_ARGS__)
>
> diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
> index 77ac182..e358242 100644
> --- a/utils/media-ctl/mediactl.h
> +++ b/utils/media-ctl/mediactl.h
> @@ -420,4 +420,20 @@ int media_parse_setup_link(struct media_device *media,
> */
> int media_parse_setup_links(struct media_device *media, const char *p);
>
> +/**
> + * @brief Find target sub-device for the control
> + * @param media - media device.
> + * @param cid - v4l2 control identifier
> + *
> + * Check if there was a target sub-device defined
> + * for the control through a ctrl-to-subdev-conf config
> + * directive.
> + *
> + * @return associated entity if defined, or NULL when no
> + * config entry for the control was found
> + */
> +struct media_entity *media_config_get_entity_by_cid(
> + struct media_device *media,
> + int cid);
The two fit on a single line.
cid should be __u32 (or uint32_t).
> #endif
> diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
> index 1cb53ff..3bc0412 100644
> --- a/utils/media-ctl/v4l2subdev.h
> +++ b/utils/media-ctl/v4l2subdev.h
> @@ -255,4 +255,19 @@ const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code);
> */
> enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(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 - v4l2 control identifier
> + *
> + * Verify if the entity supports v4l2-control with 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);
> +
> #endif
--
Kind regards,
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply [flat|nested] 13+ messages in thread
* [v4l-utils RFC v3 02/11] mediactl: Separate entity and pad parsing
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 01/11] mediactl: Introduce ctrl_to_subdev configuration Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 03/11] mediatext: Add library Jacek Anaszewski
` (8 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park
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 795aaad..b549a90 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -779,10 +779,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;
@@ -819,7 +819,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 e358242..5246978 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] 13+ messages in thread* [v4l-utils RFC v3 03/11] mediatext: Add library
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 01/11] mediactl: Introduce ctrl_to_subdev configuration Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 02/11] mediactl: Separate entity and pad parsing Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 04/11] mediactl: Add media device graph helpers Jacek Anaszewski
` (7 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, Jacek Anaszewski, Teemu Tuominen
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 14924 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>
---
libmediatext.pc.in | 10 ++
utils/media-ctl/Makefile.am | 10 +-
utils/media-ctl/libmediatext.pc.in | 10 ++
utils/media-ctl/mediatext-test.c | 66 ++++++++
utils/media-ctl/mediatext.c | 303 ++++++++++++++++++++++++++++++++++++
utils/media-ctl/mediatext.h | 52 +++++++
6 files changed, 449 insertions(+), 2 deletions(-)
create mode 100644 libmediatext.pc.in
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/libmediatext.pc.in b/libmediatext.pc.in
new file mode 100644
index 0000000..6aa6353
--- /dev/null
+++ b/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/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..29ed38b
--- /dev/null
+++ b/utils/media-ctl/mediatext-test.c
@@ -0,0 +1,66 @@
+/*
+ * 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, "\tctrl-to-subdev-conf := ctrl_id -> \"entity\"\n");
+ return EXIT_FAILURE;
+ }
+
+ device = media_device_new(argv[1]);
+ if (!device)
+ return EXIT_FAILURE;
+
+ media_debug_set_handler(device, (void (*)(void *, ...))fprintf, stdout);
+
+ 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..dc0c80b
--- /dev/null
+++ b/utils/media-ctl/mediatext.c
@@ -0,0 +1,303 @@
+/*
+ * 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))
+ 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->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->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;
+}
+
+int parse_ctrl_to_subdev_conf(struct media_device *media, const struct parser *p,
+ char *string)
+{
+ struct media_entity *entity;
+ __u32 ctrl_id;
+ int cts_cnt, rval;
+
+ media_dbg(media, "Configuring v4l2-control target: %s\n", string);
+
+ rval = parse_v4l2_ctrl_id(media, p, string, &string, &ctrl_id);
+ if (rval < 0)
+ return -EINVAL;
+
+ 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;
+
+ if (!v4l2_subdev_validate_v4l2_ctrl(media, entity, ctrl_id)) {
+ media_dbg(media, "v4l2-control 0x%8.8x not available on entity %s\n",
+ ctrl_id, entity->info.name);
+ return -EINVAL;
+ }
+
+ cts_cnt = media->ctrl_to_subdev_count;
+ media->ctrl_to_subdev = realloc(media->ctrl_to_subdev,
+ sizeof(*media->ctrl_to_subdev) * (cts_cnt + 1));
+ if (!media->ctrl_to_subdev)
+ return -ENOMEM;
+
+ media->ctrl_to_subdev[cts_cnt].ctrl_id = ctrl_id;
+ media->ctrl_to_subdev[cts_cnt].entity = entity;
+ ++media->ctrl_to_subdev_count;
+
+ 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 },
+ { "ctrl-to-subdev-conf", parse_ctrl_to_subdev_conf },
+ { "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] 13+ messages in thread* [v4l-utils RFC v3 04/11] mediactl: Add media device graph helpers
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (2 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 03/11] mediatext: Add library Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 05/11] mediactl: Add media_device creation helpers Jacek Anaszewski
` (6 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, 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 | 184 +++++++++++++++++++++++++++++++++++++++++
utils/media-ctl/mediactl.h | 132 +++++++++++++++++++++++++++++
2 files changed, 316 insertions(+)
diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index b549a90..5b43aff 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"
@@ -45,6 +46,7 @@
* Graph access
*/
+
struct media_pad *media_entity_remote_source(struct media_pad *pad)
{
unsigned int i;
@@ -87,6 +89,28 @@ 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 ? entity->info.name : NULL;
+}
+
struct media_entity *media_get_default_entity(struct media_device *media,
unsigned int type)
{
@@ -177,6 +206,152 @@ const struct media_entity_desc *media_entity_get_info(struct media_entity *entit
return &entity->info;
}
+int media_get_link_by_sink_pad(struct media_device *media,
+ struct media_pad *pad,
+ struct media_link **link)
+{
+ struct media_link *cur_link = NULL;
+ int i, j;
+
+ if (pad == NULL || link == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < media->entities_count; ++i) {
+ for (j = 0; j < media->entities[i].num_links; ++j) {
+ cur_link = &media->entities[i].links[j];
+ if ((cur_link->flags & MEDIA_LNK_FL_ENABLED) &&
+ /* check if cur_link's sink entity matches the pad parent entity */
+ (cur_link->sink->entity->info.id == pad->entity->info.id) &&
+ /* check if cur_link's sink pad id matches */
+ (cur_link->sink->index == pad->index)) {
+ *link = cur_link;
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+int media_get_link_by_source_pad(struct media_entity *entity,
+ struct media_pad *pad,
+ struct media_link **link)
+{
+ int i;
+
+ if (entity == NULL || pad == NULL || link == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < entity->num_links; ++i) {
+ if ((entity->links[i].flags & MEDIA_LNK_FL_ENABLED) &&
+ (entity->links[i].source->index == pad->index)) {
+ *link = &entity->links[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int media_get_pads_by_entity(struct media_entity *entity, unsigned int type,
+ struct media_pad **pads, int *num_pads)
+{
+ struct media_pad *entity_pads;
+ int cnt_pads, i;
+
+ if (entity == NULL || pads == NULL || num_pads == NULL)
+ return -EINVAL;
+
+ entity_pads = malloc(sizeof(*entity_pads));
+ cnt_pads = 0;
+
+ for (i = 0; i < entity->info.pads; ++i) {
+ if (entity->pads[i].flags & type) {
+ entity_pads = realloc(entity_pads, (i + 1) *
+ sizeof(*entity_pads));
+ entity_pads[cnt_pads++] = entity->pads[i];
+ }
+ }
+
+ if (cnt_pads == 0)
+ free(entity_pads);
+
+ *pads = entity_pads;
+ *num_pads = cnt_pads;
+
+ return 0;
+}
+
+int media_get_busy_pads_by_entity(struct media_device *media,
+ struct media_entity *entity,
+ unsigned int type,
+ struct media_pad **busy_pads,
+ int *num_busy_pads)
+{
+ struct media_pad *bpads, *pads;
+ struct media_link *link;
+ int cnt_bpads = 0, num_pads, i, ret;
+
+ if (entity == NULL || busy_pads == NULL || num_busy_pads == NULL ||
+ (type == MEDIA_PAD_FL_SINK && media == NULL))
+ return -EINVAL;
+
+ ret = media_get_pads_by_entity(entity, type, &pads, &num_pads);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (num_pads == 0)
+ goto done;
+
+ bpads = malloc(sizeof(*pads));
+ if (bpads == NULL)
+ goto error_ret;
+
+ for (i = 0; i < num_pads; ++i) {
+ if (type == MEDIA_PAD_FL_SINK)
+ ret = media_get_link_by_sink_pad(media, &pads[i], &link);
+ else
+ ret = media_get_link_by_source_pad(entity, &pads[i], &link);
+ if (ret == 0) {
+ bpads = realloc(bpads, (i + 1) *
+ sizeof(*bpads));
+ bpads[cnt_bpads++] = pads[i];
+ }
+ }
+ if (num_pads > 0)
+ free(pads);
+
+ if (cnt_bpads == 0)
+ free(bpads);
+
+done:
+ *busy_pads = bpads;
+ *num_busy_pads = cnt_bpads;
+
+ return 0;
+
+error_ret:
+ return -EINVAL;
+}
+
+int media_get_pad_by_index(struct media_pad *pads, int num_pads,
+ int index, struct media_pad *out_pad)
+{
+ int i;
+
+ if (pads == NULL || out_pad == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < num_pads; ++i) {
+ if (pads[i].index == index) {
+ *out_pad = pads[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
/* -----------------------------------------------------------------------------
* Open/close
*/
@@ -1001,3 +1176,12 @@ struct media_entity *media_config_get_entity_by_cid(struct media_device *media,
return NULL;
}
+
+/* -----------------------------------------------------------------------------
+ * Media entity access
+ */
+
+int media_entity_get_fd(struct media_entity *entity)
+{
+ return entity->fd;
+}
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 5246978..8341c50 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -23,6 +23,7 @@
#define __MEDIA_H__
#include <linux/media.h>
+#include <sys/types.h>
struct media_link {
struct media_pad *source;
@@ -231,6 +232,16 @@ 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 +266,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.
@@ -450,4 +474,112 @@ struct media_entity *media_config_get_entity_by_cid(
struct media_device *media,
int cid);
+/**
+ * @brief Get entity's pads of a given type
+ * @param entity - media entity
+ * @param type - pad type (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
+ * @param pads - array of matching pads
+ * @param num_pads - number of matching pads
+ *
+ * Get only sink or source pads for an entity. The returned pads
+ * array has to be freed by the caller.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_pads_by_entity(struct media_entity *entity,
+ unsigned int type,
+ struct media_pad **pads,
+ int *num_pads);
+/**
+ * @brief Get occupied entity's pads of a given type
+ * @param media - media device
+ * @param entity - media entity
+ * @param type - pad type (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
+ * @param busy_pads - array of matching pads
+ * @param num_busy_pads - number of matching pads
+ *
+ * Get only sink or source pads for an entity, with active links.
+ * The returned pads array has to be freed by the caller.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_busy_pads_by_entity(struct media_device *media,
+ struct media_entity *entity,
+ unsigned int type,
+ struct media_pad **busy_pads,
+ int *num_busy_pads);
+
+/**
+ * @brief Get link for sink pad
+ * @param media - media device
+ * @param pad - pad to search the link for
+ * @param link - matching link
+ *
+ * Get the link connected to the entity's sink pad.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_link_by_sink_pad(struct media_device *media,
+ struct media_pad *pad,
+ struct media_link **link);
+
+/**
+ * @brief Get link for source pad
+ * @param entity - media entity
+ * @param pad - pad to search the link for
+ * @param link - matching link
+ *
+ * Get the link connected to the entity's source pad.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_link_by_source_pad(struct media_entity *entity,
+ struct media_pad *pad,
+ struct media_link **link);
+
+/**
+ * @brief Get pad with given index
+ * @param pads - array of pads
+ * @param num_pads - number of pads in the array
+ * @param index - index of a pad to search for
+ * @param out_pad - matching pad
+ *
+ * Get pad with given index from the given pads array.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_pad_by_index(struct media_pad *pads, int num_pads,
+ int index, struct media_pad *out_pad);
+
+/**
+ * @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 file descriptor of the entity
+ * @param entity - media entity
+ *
+ * This function gets the file descriptor of the opened
+ * video device node related to the entity.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_entity_get_fd(struct media_entity *entity);
+
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [v4l-utils RFC v3 05/11] mediactl: Add media_device creation helpers
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (3 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 04/11] mediactl: Add media device graph helpers Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 06/11] mediactl: Add subdev_fmt property to the media_entity Jacek Anaszewski
` (5 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, 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 | 29 ++++++++++++++++
2 files changed, 104 insertions(+)
diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 5b43aff..10f0491 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -855,6 +855,43 @@ 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];
+ int i, ret;
+
+ if (entity_devname == NULL)
+ return NULL;
+
+ /* 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 */
+ if (media_get_entity_by_devname(media, entity_devname, strlen(entity_devname)))
+ 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;
@@ -897,6 +934,44 @@ 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 8341c50..0dc7f95 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -77,6 +77,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 entity_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 device node name equal to entity_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 *video_devname);
+
+/**
* @brief Take a reference to the device.
* @param media - device instance.
*
@@ -242,6 +259,18 @@ 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] 13+ messages in thread* [v4l-utils RFC v3 06/11] mediactl: Add subdev_fmt property to the media_entity
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (4 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 05/11] mediactl: Add media_device creation helpers Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 07/11] mediactl: Add VYUY8_2X8 media bus format Jacek Anaszewski
` (4 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, Jacek Anaszewski
Add subdev_fmt field to the structure media_entity.
Added is also API for setting the media_entity
format and comparing two subdev formats.
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
utils/media-ctl/libmediactl.c | 6 ++++++
utils/media-ctl/libv4l2subdev.c | 34 ++++++++++++++++++++++++++++++++++
utils/media-ctl/mediactl-priv.h | 3 +++
utils/media-ctl/mediactl.h | 12 ++++++++++++
utils/media-ctl/v4l2subdev.h | 12 ++++++++++++
5 files changed, 67 insertions(+)
diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 10f0491..27e7329 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -1260,3 +1260,9 @@ int media_entity_get_fd(struct media_entity *entity)
{
return entity->fd;
}
+
+void media_entity_set_subdev_fmt(struct media_entity *entity,
+ struct v4l2_subdev_format *fmt)
+{
+ entity->subdev_fmt = *fmt;
+}
diff --git a/utils/media-ctl/libv4l2subdev.c b/utils/media-ctl/libv4l2subdev.c
index 99ac6b2..449565c 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -786,3 +786,37 @@ int v4l2_subdev_validate_v4l2_ctrl(struct media_device *media,
entity->info.name);
return 0;
}
+
+int 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\n");
+ return 0;
+ }
+
+ if (fmt1->height != fmt2->height) {
+ printf("height mismatch\n");
+ return 0;
+ }
+
+ if (fmt1->code != fmt2->code) {
+ printf("mbus code mismatch\n");
+ return 0;
+ }
+
+ if (fmt1->field != fmt2->field) {
+ printf("field mismatch\n");
+ return 0;
+ }
+
+ if (fmt1->colorspace != fmt2->colorspace) {
+ printf("colorspace mismatch\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
index b9e9b20..b2c466b 100644
--- a/utils/media-ctl/mediactl-priv.h
+++ b/utils/media-ctl/mediactl-priv.h
@@ -23,6 +23,7 @@
#define __MEDIA_PRIV_H__
#include <linux/media.h>
+#include <linux/v4l2-subdev.h>
#include "mediactl.h"
@@ -34,6 +35,8 @@ struct media_entity {
unsigned int max_links;
unsigned int num_links;
+ struct v4l2_subdev_format subdev_fmt;
+
char devname[32];
int fd;
};
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index 0dc7f95..d28b0a8 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -42,6 +42,7 @@ struct media_pad {
struct media_device;
struct media_entity;
+struct v4l2_subdev_format;
/**
* @brief Create a new media device.
@@ -611,4 +612,15 @@ int media_entity_get_sink_pad_index(struct media_entity *entity);
*/
int media_entity_get_fd(struct media_entity *entity);
+/**
+ * @brief Set sub-device format
+ * @param entity - media entity
+ * @param fmt - pointer to the sub-device format structure
+ *
+ * This function sets the format of the sub-device related
+ * to this entity.
+ */
+void media_entity_set_subdev_fmt(struct media_entity *entity,
+ struct v4l2_subdev_format *fmt);
+
#endif
diff --git a/utils/media-ctl/v4l2subdev.h b/utils/media-ctl/v4l2subdev.h
index 3bc0412..2c9d507 100644
--- a/utils/media-ctl/v4l2subdev.h
+++ b/utils/media-ctl/v4l2subdev.h
@@ -270,4 +270,16 @@ 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
+ */
+int v4l2_subdev_format_compare(struct v4l2_mbus_framefmt *fmt1,
+ struct v4l2_mbus_framefmt *fmt2);
+
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [v4l-utils RFC v3 07/11] mediactl: Add VYUY8_2X8 media bus format
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (5 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 06/11] mediactl: Add subdev_fmt property to the media_entity Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 08/11] mediactl: Add support for media device pipelines Jacek Anaszewski
` (3 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, 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 449565c..0c6aaef 100644
--- a/utils/media-ctl/libv4l2subdev.c
+++ b/utils/media-ctl/libv4l2subdev.c
@@ -705,6 +705,7 @@ static struct {
{ "YUYV", V4L2_MBUS_FMT_YUYV8_1X16 },
{ "YUYV1_5X8", V4L2_MBUS_FMT_YUYV8_1_5X8 },
{ "YUYV2X8", V4L2_MBUS_FMT_YUYV8_2X8 },
+ { "VYUY8_2X8", V4L2_MBUS_FMT_VYUY8_2X8 },
{ "UYVY", V4L2_MBUS_FMT_UYVY8_1X16 },
{ "UYVY1_5X8", V4L2_MBUS_FMT_UYVY8_1_5X8 },
{ "UYVY2X8", V4L2_MBUS_FMT_UYVY8_2X8 },
--
1.7.9.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [v4l-utils RFC v3 08/11] mediactl: Add support for media device pipelines
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (6 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 07/11] mediactl: Add VYUY8_2X8 media bus format Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 09/11] mediactl: Add media device ioctl API Jacek Anaszewski
` (2 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, Jacek Anaszewski
Add infrastructure for linking media entities,
discovering pipelines of media entities and
opening/closing all sub-devices in the pipeline
at one go.
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
utils/media-ctl/libmediactl.c | 166 +++++++++++++++++++++++++++++++++++++++
utils/media-ctl/mediactl-priv.h | 6 ++
utils/media-ctl/mediactl.h | 79 +++++++++++++++++++
3 files changed, 251 insertions(+)
diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 27e7329..75021e7 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -1253,9 +1253,165 @@ struct media_entity *media_config_get_entity_by_cid(struct media_device *media,
}
/* -----------------------------------------------------------------------------
+ * 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 *sink_pads, sink_pad, *src_pad;
+ struct media_link *link;
+ int num_sink_pads, ret;
+ struct media_pad *prev_link_src_pad = NULL;
+
+ if (entity == NULL)
+ return -EINVAL;
+
+ for (;;) {
+ if (pipe_head == NULL) {
+ pipe_head = entity;
+ } else {
+ entity->next = pipe_head;
+ pipe_head = entity;
+ }
+
+ entity->pipe_src_pad = prev_link_src_pad;
+
+ ret = media_get_busy_pads_by_entity(media, entity,
+ MEDIA_PAD_FL_SINK,
+ &sink_pads,
+ &num_sink_pads);
+ if (ret < 0)
+ return ret;
+
+ /* check if pipeline source entity has been reached */
+ if (num_sink_pads > 2) {
+ media_dbg(media, "Unexpected number of busy sink pads (%d)\n", num_sink_pads);
+ goto err_check_sink_pads;
+ } else if (num_sink_pads == 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");
+ goto err_check_sink_pads;
+ }
+ /*
+ * Two active links are allowed betwen S5C73M3-OIF and S5C73M3 entities.
+ * In such a case a route through pad 0 has to be selected.
+ */
+ ret = media_get_pad_by_index(sink_pads, num_sink_pads,
+ 0, &sink_pad);
+ if (ret < 0)
+ goto err_check_sink_pads;
+ } else if (num_sink_pads == 1) {
+ sink_pad = sink_pads[0];
+ } else {
+ break;
+ }
+ if (num_sink_pads > 0)
+ free(sink_pads);
+
+ ret = media_get_link_by_sink_pad(media, &sink_pad, &link);
+
+ prev_link_src_pad = link->source;
+ entity->pipe_sink_pad = link->sink;
+
+ src_pad = media_entity_remote_source(link->sink);
+ if (!src_pad)
+ return -EINVAL;
+
+ entity = src_pad->entity;
+ }
+
+ media->pipeline = pipe_head;
+
+ return 0;
+
+err_check_sink_pads:
+ free(sink_pads);
+ return -EINVAL;
+}
+
+int media_has_pipeline_entity(struct media_entity *pipeline, char *entity_name)
+{
+ if (pipeline == NULL || entity_name == NULL)
+ return -EINVAL;
+
+ while (pipeline) {
+ if (!strcmp(pipeline->info.name, entity_name))
+ return 1;
+ pipeline = pipeline->next;
+ }
+
+ return 0;
+}
+
+int media_open_pipeline_subdevs(struct media_device *media)
+{
+ struct media_entity *entity = media->pipeline;
+
+ if (entity == NULL)
+ return 0;
+
+ while (entity->next) {
+ media_dbg(media, "Opening sub-device: %s\n", entity->devname);
+ entity->fd = open(entity->devname, O_RDWR);
+
+ if (entity->fd < 0) {
+ media_dbg(media, "Could not open device %s", entity->devname);
+ goto err_open_subdev;
+ }
+
+ entity = entity->next;
+ }
+
+ return 0;
+
+err_open_subdev:
+ media_close_pipeline_subdevs(media);
+
+ return -EINVAL;
+}
+
+void media_close_pipeline_subdevs(struct media_device *media)
+{
+ struct media_entity *entity = media->pipeline;
+
+ if (entity == NULL)
+ return;
+
+ while (entity->next) {
+ if (entity->fd >= 0) {
+ media_dbg(media, "Closing sub-device: %s\n", entity->devname);
+ close(entity->fd);
+ } else {
+ break;
+ }
+
+ entity->fd = -1;
+ entity = entity->next;
+ }
+}
+
+/* -----------------------------------------------------------------------------
* 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;
+}
+
int media_entity_get_fd(struct media_entity *entity)
{
return entity->fd;
@@ -1266,3 +1422,13 @@ void media_entity_set_subdev_fmt(struct media_entity *entity,
{
entity->subdev_fmt = *fmt;
}
+
+struct media_entity *media_entity_get_next(struct media_entity *entity)
+{
+ return entity->next;
+}
+
+void media_entity_set_next(struct media_entity *entity, struct media_entity *next)
+{
+ entity->next = next;
+}
diff --git a/utils/media-ctl/mediactl-priv.h b/utils/media-ctl/mediactl-priv.h
index b2c466b..0866491 100644
--- a/utils/media-ctl/mediactl-priv.h
+++ b/utils/media-ctl/mediactl-priv.h
@@ -35,10 +35,15 @@ 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_format subdev_fmt;
char devname[32];
int fd;
+
+ 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;
struct media_v4l2_ctrl_to_subdev *ctrl_to_subdev;
unsigned int ctrl_to_subdev_count;
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index d28b0a8..459345a 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -582,6 +582,32 @@ int media_get_pad_by_index(struct media_pad *pads, int num_pads,
int index, struct media_pad *out_pad);
/**
+ * @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
*
@@ -623,4 +649,57 @@ int media_entity_get_fd(struct media_entity *entity);
void media_entity_set_subdev_fmt(struct media_entity *entity,
struct v4l2_subdev_format *fmt);
+/**
+ * @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 Set next entity in the pipeline
+ * @param entity - media entity
+ * @param next - the entity to add
+ *
+ * This function adds a new entity to the pipeline.
+ */
+void media_entity_set_next(struct media_entity *entity, struct media_entity *next);
+
+/**
+ * @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);
+
+/**
+ * @brief Open pipeline sub-devices
+ * @param media - media device
+ *
+ * Open all sub-devices in the pipeline.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_open_pipeline_subdevs(struct media_device *media);
+
+/**
+ * @brief Close pipeline sub-devices
+ * @param media - media device
+ *
+ * Close all sub-devices in the pipeline.
+ */
+void media_close_pipeline_subdevs(struct media_device *media);
+
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [v4l-utils RFC v3 09/11] mediactl: Add media device ioctl API
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (7 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 08/11] mediactl: Add support for media device pipelines Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 10/11] mediactl: Close only pipeline sub-devices Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 11/11] Add a libv4l plugin for Exynos4 camera Jacek Anaszewski
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, Jacek Anaszewski
Ioctls executed on complex media devices need special
handling. E.g. S_FMT requires negotiation for the whole
pipeline of sub-devices. On the other hand some ioctls
need to be targeted for specific sub-devices. The API
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 | 342 ++++++++++++++++++++++++++++++++++
utils/media-ctl/libv4l2media_ioctl.h | 47 +++++
3 files changed, 390 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..c2c5972
--- /dev/null
+++ b/utils/media-ctl/libv4l2media_ioctl.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2014 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 <linux/videodev2.h>
+#include <sys/ioctl.h>
+
+#include "libv4l2media_ioctl.h"
+#include "mediactl.h"
+
+int media_ioctl_set_fmt(struct media_device *media,
+ struct v4l2_format *fmt)
+{
+ struct v4l2_subdev_format sd_fmt = { 0 };
+ struct media_entity *pipeline = media->pipeline;
+ int ret;
+
+ while (pipeline) {
+ sd_fmt = pipeline->subdev_fmt;
+ sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_SUBDEV_S_FMT,
+ &sd_fmt);
+ if (ret < 0)
+ return ret;
+
+ pipeline = pipeline->next;
+
+ /* Last entity in the pipeline is not a sub-device */
+ if (pipeline->next == NULL)
+ break;
+ }
+
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_S_FMT, fmt);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int media_ioctl_ctrl(struct media_device *media, int request,
+ struct v4l2_control *arg)
+{
+ struct media_entity *pipeline = media->pipeline, *entity;
+ struct v4l2_control ctrl = *arg;
+ struct v4l2_queryctrl queryctrl;
+ int ret = -EINVAL;
+
+ /*
+ * 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 (pipeline) {
+ queryctrl.id = ctrl.id;
+
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_QUERYCTRL,
+ &queryctrl);
+ if (ret < 0) {
+ pipeline = pipeline->next;
+ continue;
+ }
+
+ ctrl.value = queryctrl.default_value;
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_S_CTRL, &ctrl);
+ if (ret < 0)
+ return -EINVAL;
+
+ pipeline = pipeline->next;
+ }
+
+ ctrl.value = arg->value;
+ }
+
+ entity = media_config_get_entity_by_cid(media, ctrl.id);
+ if (entity) {
+ ret = SYS_IOCTL(entity->fd, request, &ctrl);
+ media_dbg(media, "Ioctl result for user control 0x%8.8x on %s: %d\n",
+ ctrl.id, entity->info.name, ret);
+ goto exit;
+ }
+
+ media_dbg(media, "No config for control id 0x%8.8x\n", ctrl.id);
+
+ /* Walk the pipeline until the request succeeds */
+ pipeline = media->pipeline;
+
+ while (pipeline) {
+ ret = SYS_IOCTL(pipeline->fd, request, &ctrl);
+ if (!ret) {
+ media_dbg(media, "Ioctl succeeded for user control 0x%8.8x on %s\n",
+ ctrl.id, pipeline->info.name);
+ goto exit;
+ }
+
+ pipeline = pipeline->next;
+ }
+
+ media_dbg(media, "Setting control 0x%8.8x failed\n", ctrl.id);
+
+exit:
+ *arg = ctrl;
+ return ret;
+}
+
+static int media_ioctl_single_ext_ctrl(struct media_device *media,
+ int request, struct v4l2_ext_controls *arg)
+{
+ struct media_entity *pipeline = media->pipeline, *entity;
+ struct v4l2_ext_controls ctrls = *arg;
+ struct v4l2_ext_control *ctrl;
+ struct v4l2_query_ext_ctrl queryctrl;
+ 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 (pipeline) {
+ queryctrl.id = ctrl->id;
+
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_QUERY_EXT_CTRL,
+ &queryctrl);
+ if (ret < 0) {
+ pipeline = pipeline->next;
+ continue;
+ }
+
+ ctrl->value64 = queryctrl.default_value;
+
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_S_EXT_CTRLS, &ctrls);
+ if (ret < 0)
+ return -EINVAL;
+
+ pipeline = pipeline->next;
+ }
+
+ ctrl->value64 = arg->controls[0].value64;
+ }
+
+ entity = media_config_get_entity_by_cid(media, ctrl->id);
+ if (entity) {
+ ret = SYS_IOCTL(entity->fd, request, &ctrls);
+ media_dbg(media, "Ioctl result for extended control 0x%8.8x on %s: %d\n",
+ ctrl->id, entity->info.name, ret);
+ goto exit;
+ }
+
+ media_dbg(media, "No config for control id 0x%8.8x\n", ctrl->id);
+
+ /* Walk the pipeline until the request succeeds */
+ pipeline = media->pipeline;
+
+ while (pipeline) {
+ ret = SYS_IOCTL(pipeline->fd, request, &ctrls);
+ if (!ret) {
+ media_dbg(media, "Ioctl succeeded for extended control 0x%8.8x on %s\n",
+ ctrl->id, pipeline->info.name);
+ goto exit;
+ }
+
+
+ pipeline = pipeline->next;
+ }
+
+exit:
+ *arg = ctrls;
+ 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;
+ goto exit;
+ }
+ }
+
+exit:
+ *arg = out_ctrls;
+ return ret;
+}
+
+int media_ioctl_queryctrl(struct media_device *media,
+ struct v4l2_queryctrl *arg)
+{
+ struct media_entity *pipeline = media->pipeline, *entity;
+ struct v4l2_queryctrl queryctrl = *arg;
+ int ret = -EINVAL;
+
+ while (pipeline) {
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_QUERYCTRL, &queryctrl);
+ if (!ret) {
+ /*
+ * Control id might be or'ed with V4L2_CTRL_FLAG_NEXT_CTRL,
+ * therefore the check for the config settings must be
+ * done no sooner than after first successful ioctl execution
+ * on a pipeline sub-device.
+ */
+ entity = media_config_get_entity_by_cid(media, queryctrl.id);
+ /*
+ * If the control is in the config, then
+ * query the associated sub-device.
+ */
+ if (entity) {
+ media_dbg(media, "Queryctrl: \"%s\" control found in the config\n", queryctrl.name);
+ /* Check if the control hasn't been already queried */
+ if (entity->fd != pipeline->fd)
+ ret = SYS_IOCTL(entity->fd, VIDIOC_QUERYCTRL, &queryctrl);
+ }
+
+ media_dbg(media, "Queryctrl: \"%s\" control on %s (%d)\n",
+ queryctrl.name, entity ? entity->info.name :
+ pipeline->info.name,
+ ret);
+ break;
+ }
+
+ pipeline = pipeline->next;
+ }
+
+ *arg = queryctrl;
+ return ret;
+}
+
+int media_ioctl_query_ext_ctrl(struct media_device *media,
+ struct v4l2_query_ext_ctrl *arg)
+{
+ struct media_entity *pipeline = media->pipeline, *entity;
+ struct v4l2_query_ext_ctrl query_ext_ctrl = *arg;
+ int ret = -EINVAL;
+
+ while (pipeline) {
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_QUERY_EXT_CTRL, &query_ext_ctrl);
+ if (!ret) {
+ /*
+ * Control id might be or'ed with V4L2_CTRL_FLAG_NEXT_CTRL,
+ * therefore the check for the config settings must be
+ * done no sooner than after first successful ioctl execution
+ * on a pipeline sub-device.
+ */
+ entity = media_config_get_entity_by_cid(media, query_ext_ctrl.id);
+ /*
+ * If the control is in the config, then
+ * query the associated sub-device.
+ */
+ if (entity) {
+ media_dbg(media, "Query ext control: \"%s\" found in config\n", query_ext_ctrl.name);
+ /* Check if the control hasn't been already queried */
+ if (entity->fd != pipeline->fd)
+ ret = SYS_IOCTL(entity->fd, VIDIOC_QUERY_EXT_CTRL, &query_ext_ctrl);
+ }
+
+ media_dbg(media, "Query ext control: \"%s\" on %s (%d)\n",
+ query_ext_ctrl.name, entity ?
+ entity->info.name :
+ pipeline->info.name,
+ ret);
+ break;
+ }
+
+ pipeline = pipeline->next;
+ }
+
+ *arg = query_ext_ctrl;
+ return ret;
+}
+
+int media_ioctl_querymenu(struct media_device *media,
+ struct v4l2_querymenu *arg)
+{
+ struct media_entity *pipeline = media->pipeline, *entity;
+ struct v4l2_querymenu querymenu = *arg;
+ int ret = -EINVAL;
+
+ entity = media_config_get_entity_by_cid(media, querymenu.id);
+ if (entity) {
+ ret = SYS_IOCTL(entity->fd, VIDIOC_QUERYMENU, &querymenu);
+ media_dbg(media, "Querymenu result for the control 0x%8.8x on %s: %d\n",
+ querymenu.id, entity->info.name, ret);
+ goto exit;
+ }
+
+ while (pipeline) {
+ ret = SYS_IOCTL(pipeline->fd, VIDIOC_QUERYMENU, &querymenu);
+ if (!ret) {
+ media_dbg(media, "Querymenu succeeded for the control 0x%8.8x on %s\n",
+ querymenu.id, pipeline->info.name);
+ goto exit;
+ }
+
+ pipeline = pipeline->next;
+ }
+
+exit:
+ *arg = querymenu;
+ return ret;
+}
diff --git a/utils/media-ctl/libv4l2media_ioctl.h b/utils/media-ctl/libv4l2media_ioctl.h
new file mode 100644
index 0000000..9e52c03
--- /dev/null
+++ b/utils/media-ctl/libv4l2media_ioctl.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014 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>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "mediactl-priv.h"
+
+#define SYS_IOCTL(fd, cmd, arg) \
+ syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+
+int media_ioctl_set_fmt(struct media_device *media,
+ struct v4l2_format *fmt);
+
+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] 13+ messages in thread* [v4l-utils RFC v3 10/11] mediactl: Close only pipeline sub-devices
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (8 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 09/11] mediactl: Add media device ioctl API Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
2014-11-06 10:11 ` [v4l-utils RFC v3 11/11] Add a libv4l plugin for Exynos4 camera Jacek Anaszewski
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, Jacek Anaszewski
The function media_device_new_by_entity_devname queries
media devices available in the system for containment
if given media entity. If a verification is negative
the media_device is released with media_device_unref.
In the previous approach media_device_unref was closing
all media entities it contained, which was undesirable
behavior as there might exist other initialized plugins
which had opened the same media_device and initialized
a pipeline. With this patch only the sub-devices that
belong to the pipeline of current media_device instance
will be closed.
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
utils/media-ctl/libmediactl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 75021e7..fe38270 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -919,13 +919,13 @@ void media_device_unref(struct media_device *media)
if (media->refcount > 0)
return;
+ media_close_pipeline_subdevs(media);
+
for (i = 0; i < media->entities_count; ++i) {
struct media_entity *entity = &media->entities[i];
free(entity->pads);
free(entity->links);
- if (entity->fd != -1)
- close(entity->fd);
}
free(media->entities);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [v4l-utils RFC v3 11/11] Add a libv4l plugin for Exynos4 camera
2014-11-06 10:11 [v4l-utils RFC v3 00/11] Add a plugin for the Exynos4 camera Jacek Anaszewski
` (9 preceding siblings ...)
2014-11-06 10:11 ` [v4l-utils RFC v3 10/11] mediactl: Close only pipeline sub-devices Jacek Anaszewski
@ 2014-11-06 10:11 ` Jacek Anaszewski
10 siblings, 0 replies; 13+ messages in thread
From: Jacek Anaszewski @ 2014-11-06 10:11 UTC (permalink / raw)
To: linux-media
Cc: m.chehab, gjasny, hdegoede, hans.verkuil, b.zolnierkie,
sakari.ailus, kyungmin.park, 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 | 599 +++++++++++++++++++++
4 files changed, 610 insertions(+), 2 deletions(-)
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 c9b0524..ae653b9 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 3a0e19c..29455ab 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3,9 +3,10 @@ SUBDIRS = \
libv4l2 \
libv4l1 \
libv4l2rds \
- libv4l-mplane
+ libv4l-mplane \
+ libv4l-exynos4-camera
if LINUX_OS
SUBDIRS += \
libdvbv5
-endif
\ No newline at end of file
+endif
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..02b5a7d
--- /dev/null
+++ b/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 2014 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 <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;
+};
+
+#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 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; \
+ })
+
+#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_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 += 16;
+ mbus_fmt->height += 12;
+
+ return 0;
+}
+
+static int negotiate_pipeline_fmt(struct media_entity *pipeline,
+ struct v4l2_format *dev_fmt)
+{
+ struct media_entity *vid_pipe = pipeline;
+ struct v4l2_subdev_format subdev_fmt = { 0 };
+ struct v4l2_mbus_framefmt mbus_fmt = { 0 }, common_fmt;
+ int repeat_negotiation, cnt_negotiation = 0, ret;
+
+ 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;
+
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+
+ if (media_has_pipeline_entity(vid_pipe, EXYNOS4_FIMC_IS_ISP)) {
+ ret = __adjust_format_to_fimc_is_isp(&mbus_fmt);
+ if (ret < 0)
+ return ret;
+ }
+
+ subdev_fmt.format = mbus_fmt;
+
+ V4L2_EXYNOS4_DBG("Begin pipeline format negotiation...");
+
+ for (;;) {
+ repeat_negotiation = 0;
+ vid_pipe = pipeline;
+
+ subdev_fmt.pad = media_entity_get_src_pad_index(vid_pipe);
+
+ V4L2_EXYNOS4_DBG("Setting format on entity %s, pad: %d",
+ vid_pipe->info.name, subdev_fmt.pad);
+
+ ret = SYS_IOCTL(media_entity_get_fd(vid_pipe), VIDIOC_SUBDEV_S_FMT,
+ &subdev_fmt);
+ if (ret < 0)
+ return ret;
+
+ common_fmt = subdev_fmt.format;
+ media_entity_set_subdev_fmt(vid_pipe, &subdev_fmt);
+
+ vid_pipe = media_entity_get_next(vid_pipe);
+
+ while (vid_pipe) {
+ subdev_fmt.pad = media_entity_get_sink_pad_index(vid_pipe);
+
+ /* Set format on the entity src pad */
+ V4L2_EXYNOS4_DBG("Setting format on the entity pad %s:%d: mbus_code: %s, width: %d, height: %d",
+ vid_pipe->info.name, subdev_fmt.pad,
+ v4l2_subdev_pixelcode_to_string(subdev_fmt.format.code),
+ subdev_fmt.format.width, subdev_fmt.format.height);
+
+ ret = SYS_IOCTL(media_entity_get_fd(vid_pipe), VIDIOC_SUBDEV_S_FMT,
+ &subdev_fmt);
+ if (ret < 0)
+ return ret;
+
+ if (!v4l2_subdev_format_compare(&subdev_fmt.format, &common_fmt)) {
+ repeat_negotiation = 1;
+ break;
+ }
+
+ media_entity_set_subdev_fmt(vid_pipe, &subdev_fmt);
+
+ /*
+ * Do not check format on FIMC.[n] source pad
+ * and stop negotiation.
+ */
+ if (!strncmp(media_entity_get_name(vid_pipe),
+ EXYNOS4_FIMC_PREFIX,
+ strlen(EXYNOS4_FIMC_PREFIX)))
+ break;
+
+ subdev_fmt.pad = media_entity_get_src_pad_index(vid_pipe);
+
+ /* Get format on the entity sink pad */
+ ret = SYS_IOCTL(media_entity_get_fd(vid_pipe),
+ VIDIOC_SUBDEV_G_FMT, &subdev_fmt);
+ if (ret < 0)
+ return -EINVAL;
+
+ V4L2_EXYNOS4_DBG("Format propagated to the entity pad %s:%d: mbus_code: %s, width: %d, height: %d",
+ vid_pipe->info.name, subdev_fmt.pad,
+ v4l2_subdev_pixelcode_to_string(subdev_fmt.format.code),
+ subdev_fmt.format.width, subdev_fmt.format.height);
+
+ if (!strcmp(media_entity_get_name(vid_pipe),
+ EXYNOS4_FIMC_IS_ISP)) {
+ common_fmt.code = subdev_fmt.format.code;
+ common_fmt.colorspace =
+ subdev_fmt.format.colorspace;
+ common_fmt.width -= 16;
+ common_fmt.height -= 12;
+ }
+
+ if (!v4l2_subdev_format_compare(&subdev_fmt.format, &common_fmt)) {
+ repeat_negotiation = 1;
+ break;
+ }
+
+ media_entity_set_next(vid_pipe, media_entity_get_next(vid_pipe));
+
+ vid_pipe = media_entity_get_next(vid_pipe);
+
+ /*
+ * Stop if this is last element in the
+ * pipeline as it is not a sub-device.
+ */
+ if (media_entity_get_next(vid_pipe) == 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 = subdev_fmt.format.width;
+ dev_fmt->fmt.pix_mp.height = subdev_fmt.format.height;
+ dev_fmt->fmt.pix_mp.field = subdev_fmt.format.field;
+ dev_fmt->fmt.pix_mp.colorspace = subdev_fmt.format.colorspace;
+
+ V4L2_EXYNOS4_DBG("Pipeline format successfuly negotiated");
+
+ return 0;
+}
+
+static int convert_type(int 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 };
+ struct v4l2_format *org = arg;
+ int ret;
+
+ fmt.type = convert_type(arg->type);
+ if (fmt.type != arg->type) {
+ fmt.fmt.pix_mp.width = org->fmt.pix.width;
+ fmt.fmt.pix_mp.height = org->fmt.pix.height;
+ fmt.fmt.pix_mp.pixelformat = org->fmt.pix.pixelformat;
+ fmt.fmt.pix_mp.field = org->fmt.pix.field;
+ fmt.fmt.pix_mp.colorspace = org->fmt.pix.colorspace;
+ fmt.fmt.pix_mp.num_planes = 1;
+ fmt.fmt.pix_mp.flags = org->fmt.pix.flags;
+ fmt.fmt.pix_mp.plane_fmt[0].bytesperline = org->fmt.pix.bytesperline;
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage = org->fmt.pix.sizeimage;
+ } else {
+ fmt = *org;
+ }
+
+ ret = negotiate_pipeline_fmt(media_get_pipeline(media), &fmt);
+ if (ret < 0)
+ return ret;
+
+ if (set_mode == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ ret = media_ioctl_set_fmt(media, &fmt);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (fmt.type != arg->type) {
+ org->fmt.pix.width = fmt.fmt.pix_mp.width;
+ org->fmt.pix.height = fmt.fmt.pix_mp.height;
+ org->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat;
+ org->fmt.pix.field = fmt.fmt.pix_mp.field;
+ org->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace;
+ org->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ org->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+ org->fmt.pix.flags = fmt.fmt.pix_mp.flags;
+ } else {
+ *org = fmt;
+ }
+
+ return 0;
+}
+
+static int get_fmt_ioctl(int fd,
+ unsigned long int cmd,
+ struct v4l2_format *arg)
+{
+ struct v4l2_format fmt = { 0 };
+ struct v4l2_format *org = arg;
+ 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(&org->fmt.pix, 0, sizeof(org->fmt.pix));
+ org->fmt.pix.width = fmt.fmt.pix_mp.width;
+ org->fmt.pix.height = fmt.fmt.pix_mp.height;
+ org->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat;
+ org->fmt.pix.field = fmt.fmt.pix_mp.field;
+ org->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace;
+ org->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ org->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+ org->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ org->fmt.pix.flags = fmt.fmt.pix_mp.flags;
+
+ /*
+ * If the device doesn't support just one plane, there's
+ * nothing we can do, except return an error condition.
+ */
+ if (fmt.fmt.pix_mp.num_planes > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+
+ 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;
+ 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;
+
+ V4L2_EXYNOS4_ERR("fd: %d\n", fd);
+
+ memset(&plugin, 0, sizeof(plugin));
+
+ memset(&cap, 0, sizeof(cap));
+ 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 sinkd entity name.");
+ goto err_get_sink_entity;
+ }
+
+ /* The last entity in the pipeline represents video device node */
+ sink_entity->fd = 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 = media_open_pipeline_subdevs(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;
+
+ V4L2_EXYNOS4_LOG("Initialized exynos4-camera plugin.");
+
+ return plugin;
+
+err_validate_controls:
+ media_close_pipeline_subdevs(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;
+ struct media_device *media;
+
+ if (dev_ops_priv == NULL)
+ return;
+
+ plugin = (struct exynos4_camera_plugin *) dev_ops_priv;
+ media = plugin->media;
+
+ media_close_pipeline_subdevs(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;
+ int 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] 13+ messages in thread