linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [media-ctl PATCH 0/7] Move functionality to libraries, debug changes
@ 2011-10-07 15:34 Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 1/7] Rename files to match the names of the libraries Sakari Ailus
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:34 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

Hi,

This patchset moves the string parsing functionality to libraries from the
test program, making the libraries much more useful.

Printing informative messages is also left to debug handler; the libraries
won't print anything anymore. Error messages are also printed by media-ctl.

Regards,

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

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

* [media-ctl PATCH 1/7] Rename files to match the names of the libraries
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  2011-10-08 11:53   ` Laurent Pinchart
  2011-10-07 15:38 ` [media-ctl PATCH 2/7] Move link parsing from main.c to media.c, making it part of libmediactl Sakari Ailus
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

Rename media.* to mediactl.* and subdev.* v4l2subdev.*.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/Makefile.am  |    6 +-
 src/main.c       |    4 +-
 src/media.c      |  475 ------------------------------------------------------
 src/media.h      |  161 ------------------
 src/mediactl.c   |  475 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mediactl.h   |  161 ++++++++++++++++++
 src/subdev.c     |  188 ---------------------
 src/subdev.h     |  162 -------------------
 src/v4l2subdev.c |  188 +++++++++++++++++++++
 src/v4l2subdev.h |  162 +++++++++++++++++++
 10 files changed, 991 insertions(+), 991 deletions(-)
 delete mode 100644 src/media.c
 delete mode 100644 src/media.h
 create mode 100644 src/mediactl.c
 create mode 100644 src/mediactl.h
 delete mode 100644 src/subdev.c
 delete mode 100644 src/subdev.h
 create mode 100644 src/v4l2subdev.c
 create mode 100644 src/v4l2subdev.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 52628d2..2583464 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,8 +1,8 @@
 lib_LTLIBRARIES = libmediactl.la libv4l2subdev.la
-libmediactl_la_SOURCES = media.c
-libv4l2subdev_la_SOURCES = subdev.c
+libmediactl_la_SOURCES = mediactl.c
+libv4l2subdev_la_SOURCES = v4l2subdev.c
 mediactl_includedir=$(includedir)/mediactl
-mediactl_include_HEADERS = media.h subdev.h
+mediactl_include_HEADERS = mediactl.h v4l2subdev.h
 
 bin_PROGRAMS = media-ctl
 media_ctl_CFLAGS = $(LIBUDEV_CFLAGS)
diff --git a/src/main.c b/src/main.c
index b9b9150..55a6e2d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -36,9 +36,9 @@
 #include <linux/v4l2-subdev.h>
 #include <linux/videodev2.h>
 
-#include "media.h"
+#include "mediactl.h"
 #include "options.h"
-#include "subdev.h"
+#include "v4l2subdev.h"
 #include "tools.h"
 
 /* -----------------------------------------------------------------------------
diff --git a/src/media.c b/src/media.c
deleted file mode 100644
index f443d0c..0000000
--- a/src/media.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Media controller test application
- *
- * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- */
-
-#include "config.h"
-
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <linux/videodev2.h>
-#include <linux/media.h>
-
-#include "media.h"
-#include "tools.h"
-
-struct media_pad *media_entity_remote_source(struct media_pad *pad)
-{
-	unsigned int i;
-
-	if (!(pad->flags & MEDIA_PAD_FL_SINK))
-		return NULL;
-
-	for (i = 0; i < pad->entity->num_links; ++i) {
-		struct media_link *link = &pad->entity->links[i];
-
-		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
-			continue;
-
-		if (link->sink == pad)
-			return link->source;
-	}
-
-	return NULL;
-}
-
-struct media_entity *media_get_entity_by_name(struct media_device *media,
-					      const char *name, size_t length)
-{
-	unsigned int i;
-
-	for (i = 0; i < media->entities_count; ++i) {
-		struct media_entity *entity = &media->entities[i];
-
-		if (strncmp(entity->info.name, name, length) == 0)
-			return entity;
-	}
-
-	return NULL;
-}
-
-struct media_entity *media_get_entity_by_id(struct media_device *media,
-					    __u32 id)
-{
-	unsigned int i;
-
-	for (i = 0; i < media->entities_count; ++i) {
-		struct media_entity *entity = &media->entities[i];
-
-		if (entity->info.id == id)
-			return entity;
-	}
-
-	return NULL;
-}
-
-int media_setup_link(struct media_device *media,
-		     struct media_pad *source,
-		     struct media_pad *sink,
-		     __u32 flags)
-{
-	struct media_link *link;
-	struct media_link_desc ulink;
-	unsigned int i;
-	int ret;
-
-	for (i = 0; i < source->entity->num_links; i++) {
-		link = &source->entity->links[i];
-
-		if (link->source->entity == source->entity &&
-		    link->source->index == source->index &&
-		    link->sink->entity == sink->entity &&
-		    link->sink->index == sink->index)
-			break;
-	}
-
-	if (i == source->entity->num_links) {
-		printf("%s: Link not found\n", __func__);
-		return -EINVAL;
-	}
-
-	/* source pad */
-	ulink.source.entity = source->entity->info.id;
-	ulink.source.index = source->index;
-	ulink.source.flags = MEDIA_PAD_FL_SOURCE;
-
-	/* sink pad */
-	ulink.sink.entity = sink->entity->info.id;
-	ulink.sink.index = sink->index;
-	ulink.sink.flags = MEDIA_PAD_FL_SINK;
-
-	ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
-
-	ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
-	if (ret < 0) {
-		printf("%s: Unable to setup link (%s)\n", __func__,
-			strerror(errno));
-		return ret;
-	}
-
-	link->flags = ulink.flags;
-	link->twin->flags = ulink.flags;
-	return 0;
-}
-
-int media_reset_links(struct media_device *media)
-{
-	unsigned int i, j;
-	int ret;
-
-	for (i = 0; i < media->entities_count; ++i) {
-		struct media_entity *entity = &media->entities[i];
-
-		for (j = 0; j < entity->num_links; j++) {
-			struct media_link *link = &entity->links[j];
-
-			if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
-			    link->source->entity != entity)
-				continue;
-
-			ret = media_setup_link(media, link->source, link->sink,
-					       link->flags & ~MEDIA_LNK_FL_ENABLED);
-			if (ret < 0)
-				return ret;
-		}
-	}
-
-	return 0;
-}
-
-static struct media_link *media_entity_add_link(struct media_entity *entity)
-{
-	if (entity->num_links >= entity->max_links) {
-		struct media_link *links = entity->links;
-		unsigned int max_links = entity->max_links * 2;
-		unsigned int i;
-
-		links = realloc(links, max_links * sizeof *links);
-		if (links == NULL)
-			return NULL;
-
-		for (i = 0; i < entity->num_links; ++i)
-			links[i].twin->twin = &links[i];
-
-		entity->max_links = max_links;
-		entity->links = links;
-	}
-
-	return &entity->links[entity->num_links++];
-}
-
-static int media_enum_links(struct media_device *media)
-{
-	__u32 id;
-	int ret = 0;
-
-	for (id = 1; id <= media->entities_count; id++) {
-		struct media_entity *entity = &media->entities[id - 1];
-		struct media_links_enum links;
-		unsigned int i;
-
-		links.entity = entity->info.id;
-		links.pads = malloc(entity->info.pads * sizeof(struct media_pad_desc));
-		links.links = malloc(entity->info.links * sizeof(struct media_link_desc));
-
-		if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
-			printf("%s: Unable to enumerate pads and links (%s).\n",
-				__func__, strerror(errno));
-			free(links.pads);
-			free(links.links);
-			return -errno;
-		}
-
-		for (i = 0; i < entity->info.pads; ++i) {
-			entity->pads[i].entity = entity;
-			entity->pads[i].index = links.pads[i].index;
-			entity->pads[i].flags = links.pads[i].flags;
-		}
-
-		for (i = 0; i < entity->info.links; ++i) {
-			struct media_link_desc *link = &links.links[i];
-			struct media_link *fwdlink;
-			struct media_link *backlink;
-			struct media_entity *source;
-			struct media_entity *sink;
-
-			source = media_get_entity_by_id(media, link->source.entity);
-			sink = media_get_entity_by_id(media, link->sink.entity);
-
-			if (source == NULL || sink == NULL) {
-				printf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
-					id, i, link->source.entity, link->source.index,
-					link->sink.entity, link->sink.index);
-				ret = -EINVAL;
-			} else {
-				fwdlink = media_entity_add_link(source);
-				fwdlink->source = &source->pads[link->source.index];
-				fwdlink->sink = &sink->pads[link->sink.index];
-				fwdlink->flags = link->flags;
-
-				backlink = media_entity_add_link(sink);
-				backlink->source = &source->pads[link->source.index];
-				backlink->sink = &sink->pads[link->sink.index];
-				backlink->flags = link->flags;
-
-				fwdlink->twin = backlink;
-				backlink->twin = fwdlink;
-			}
-		}
-
-		free(links.pads);
-		free(links.links);
-	}
-
-	return ret;
-}
-
-#ifdef HAVE_LIBUDEV
-
-#include <libudev.h>
-
-static inline int media_udev_open(struct udev **udev)
-{
-	*udev = udev_new();
-	if (*udev == NULL)
-		return -ENOMEM;
-	return 0;
-}
-
-static inline void media_udev_close(struct udev *udev)
-{
-	if (udev != NULL)
-		udev_unref(udev);
-}
-
-static int media_get_devname_udev(struct udev *udev,
-		struct media_entity *entity, int verbose)
-{
-	struct udev_device *device;
-	dev_t devnum;
-	const char *p;
-	int ret = -ENODEV;
-
-	if (udev == NULL)
-		return -EINVAL;
-
-	devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
-	if (verbose)
-		printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
-	device = udev_device_new_from_devnum(udev, 'c', devnum);
-	if (device) {
-		p = udev_device_get_devnode(device);
-		if (p) {
-			strncpy(entity->devname, p, sizeof(entity->devname));
-			entity->devname[sizeof(entity->devname) - 1] = '\0';
-		}
-		ret = 0;
-	}
-
-	udev_device_unref(device);
-
-	return ret;
-}
-
-#else	/* HAVE_LIBUDEV */
-
-struct udev;
-
-static inline int media_udev_open(struct udev **udev) { return 0; }
-
-static inline void media_udev_close(struct udev *udev) { }
-
-static inline int media_get_devname_udev(struct udev *udev,
-		struct media_entity *entity, int verbose)
-{
-	return -ENOTSUP;
-}
-
-#endif	/* HAVE_LIBUDEV */
-
-static int media_get_devname_sysfs(struct media_entity *entity)
-{
-	struct stat devstat;
-	char devname[32];
-	char sysname[32];
-	char target[1024];
-	char *p;
-	int ret;
-
-	sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
-		entity->info.v4l.minor);
-	ret = readlink(sysname, target, sizeof(target));
-	if (ret < 0)
-		return -errno;
-
-	target[ret] = '\0';
-	p = strrchr(target, '/');
-	if (p == NULL)
-		return -EINVAL;
-
-	sprintf(devname, "/dev/%s", p + 1);
-	ret = stat(devname, &devstat);
-	if (ret < 0)
-		return -errno;
-
-	/* Sanity check: udev might have reordered the device nodes.
-	 * Make sure the major/minor match. We should really use
-	 * libudev.
-	 */
-	if (major(devstat.st_rdev) == entity->info.v4l.major &&
-	    minor(devstat.st_rdev) == entity->info.v4l.minor)
-		strcpy(entity->devname, devname);
-
-	return 0;
-}
-
-static int media_enum_entities(struct media_device *media, int verbose)
-{
-	struct media_entity *entity;
-	struct udev *udev;
-	unsigned int size;
-	__u32 id;
-	int ret;
-
-	ret = media_udev_open(&udev);
-	if (ret < 0)
-		printf("%s: Can't get udev context\n", __func__);
-
-	for (id = 0, ret = 0; ; id = entity->info.id) {
-		size = (media->entities_count + 1) * sizeof(*media->entities);
-		media->entities = realloc(media->entities, size);
-
-		entity = &media->entities[media->entities_count];
-		memset(entity, 0, sizeof(*entity));
-		entity->fd = -1;
-		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
-
-		ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
-		if (ret < 0) {
-			ret = errno != EINVAL ? -errno : 0;
-			break;
-		}
-
-		/* Number of links (for outbound links) plus number of pads (for
-		 * inbound links) is a good safe initial estimate of the total
-		 * number of links.
-		 */
-		entity->max_links = entity->info.pads + entity->info.links;
-
-		entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
-		entity->links = malloc(entity->max_links * sizeof(*entity->links));
-		if (entity->pads == NULL || entity->links == NULL) {
-			ret = -ENOMEM;
-			break;
-		}
-
-		media->entities_count++;
-
-		/* Find the corresponding device name. */
-		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
-		    media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
-			continue;
-
-		/* Try to get the device name via udev */
-		if (!media_get_devname_udev(udev, entity, verbose))
-			continue;
-
-		/* Fall back to get the device name via sysfs */
-		media_get_devname_sysfs(entity);
-	}
-
-	media_udev_close(udev);
-	return ret;
-}
-
-struct media_device *media_open(const char *name, int verbose)
-{
-	struct media_device *media;
-	int ret;
-
-	media = calloc(1, sizeof(*media));
-	if (media == NULL) {
-		printf("%s: unable to allocate memory\n", __func__);
-		return NULL;
-	}
-
-	if (verbose)
-		printf("Opening media device %s\n", name);
-	media->fd = open(name, O_RDWR);
-	if (media->fd < 0) {
-		media_close(media);
-		printf("%s: Can't open media device %s\n", __func__, name);
-		return NULL;
-	}
-
-	if (verbose)
-		printf("Enumerating entities\n");
-
-	ret = media_enum_entities(media, verbose);
-
-	if (ret < 0) {
-		printf("%s: Unable to enumerate entities for device %s (%s)\n",
-			__func__, name, strerror(-ret));
-		media_close(media);
-		return NULL;
-	}
-
-	if (verbose) {
-		printf("Found %u entities\n", media->entities_count);
-		printf("Enumerating pads and links\n");
-	}
-
-	ret = media_enum_links(media);
-	if (ret < 0) {
-		printf("%s: Unable to enumerate pads and linksfor device %s\n",
-			__func__, name);
-		media_close(media);
-		return NULL;
-	}
-
-	return media;
-}
-
-void media_close(struct media_device *media)
-{
-	unsigned int i;
-
-	if (media->fd != -1)
-		close(media->fd);
-
-	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);
-	free(media);
-}
-
diff --git a/src/media.h b/src/media.h
deleted file mode 100644
index b91a2ac..0000000
--- a/src/media.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Media controller test application
- *
- * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- */
-
-#ifndef __MEDIA_H__
-#define __MEDIA_H__
-
-#include <linux/media.h>
-
-struct media_link {
-	struct media_pad *source;
-	struct media_pad *sink;
-	struct media_link *twin;
-	__u32 flags;
-	__u32 padding[3];
-};
-
-struct media_pad {
-	struct media_entity *entity;
-	__u32 index;
-	__u32 flags;
-	__u32 padding[3];
-};
-
-struct media_entity {
-	struct media_entity_desc info;
-	struct media_pad *pads;
-	struct media_link *links;
-	unsigned int max_links;
-	unsigned int num_links;
-
-	char devname[32];
-	int fd;
-	__u32 padding[6];
-};
-
-struct media_device {
-	int fd;
-	struct media_entity *entities;
-	unsigned int entities_count;
-	__u32 padding[6];
-};
-
-/**
- * @brief Open a media device.
- * @param name - name (including path) of the device node.
- * @param verbose - whether to print verbose information on the standard output.
- *
- * Open the media device referenced by @a name and enumerate entities, pads and
- * links.
- *
- * @return A pointer to a newly allocated media_device structure instance on
- * success and NULL on failure. The returned pointer must be freed with
- * media_close when the device isn't needed anymore.
- */
-struct media_device *media_open(const char *name, int verbose);
-
-/**
- * @brief Close a media device.
- * @param media - device instance.
- *
- * Close the @a media device instance and free allocated resources. Access to the
- * device instance is forbidden after this function returns.
- */
-void media_close(struct media_device *media);
-
-/**
- * @brief Locate the pad at the other end of a link.
- * @param pad - sink pad at one end of the link.
- *
- * Locate the source pad connected to @a pad through an enabled link. As only one
- * link connected to a sink pad can be enabled at a time, the connected source
- * pad is guaranteed to be unique.
- *
- * @return A pointer to the connected source pad, or NULL if all links connected
- * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
- */
-struct media_pad *media_entity_remote_source(struct media_pad *pad);
-
-/**
- * @brief Get the type of an entity.
- * @param entity - the entity.
- *
- * @return The type of @a entity.
- */
-static inline unsigned int media_entity_type(struct media_entity *entity)
-{
-	return entity->info.type & MEDIA_ENT_TYPE_MASK;
-}
-
-/**
- * @brief Find an entity by its name.
- * @param media - media device.
- * @param name - entity name.
- * @param length - size of @a name.
- *
- * Search for an entity with a name equal to @a name.
- *
- * @return A pointer to the entity if found, or NULL otherwise.
- */
-struct media_entity *media_get_entity_by_name(struct media_device *media,
-	const char *name, size_t length);
-
-/**
- * @brief Find an entity by its ID.
- * @param media - media device.
- * @param id - entity ID.
- *
- * Search for an entity with an ID equal to @a id.
- *
- * @return A pointer to the entity if found, or NULL otherwise.
- */
-struct media_entity *media_get_entity_by_id(struct media_device *media,
-	__u32 id);
-
-/**
- * @brief Configure a link.
- * @param media - media device.
- * @param source - source pad at the link origin.
- * @param sink - sink pad at the link target.
- * @param flags - configuration flags.
- *
- * Locate the link between @a source and @a sink, and configure it by applying
- * the new @a flags.
- *
- * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int media_setup_link(struct media_device *media,
-	struct media_pad *source, struct media_pad *sink,
-	__u32 flags);
-
-/**
- * @brief Reset all links to the disabled state.
- * @param media - media device.
- *
- * Disable all links in the media device. This function is usually used after
- * opening a media device to reset all links to a known state.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int media_reset_links(struct media_device *media);
-
-#endif
-
diff --git a/src/mediactl.c b/src/mediactl.c
new file mode 100644
index 0000000..5c710c9
--- /dev/null
+++ b/src/mediactl.c
@@ -0,0 +1,475 @@
+/*
+ * Media controller test application
+ *
+ * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <linux/videodev2.h>
+#include <linux/media.h>
+
+#include "mediactl.h"
+#include "tools.h"
+
+struct media_pad *media_entity_remote_source(struct media_pad *pad)
+{
+	unsigned int i;
+
+	if (!(pad->flags & MEDIA_PAD_FL_SINK))
+		return NULL;
+
+	for (i = 0; i < pad->entity->num_links; ++i) {
+		struct media_link *link = &pad->entity->links[i];
+
+		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+			continue;
+
+		if (link->sink == pad)
+			return link->source;
+	}
+
+	return NULL;
+}
+
+struct media_entity *media_get_entity_by_name(struct media_device *media,
+					      const char *name, size_t length)
+{
+	unsigned int i;
+
+	for (i = 0; i < media->entities_count; ++i) {
+		struct media_entity *entity = &media->entities[i];
+
+		if (strncmp(entity->info.name, name, length) == 0)
+			return entity;
+	}
+
+	return NULL;
+}
+
+struct media_entity *media_get_entity_by_id(struct media_device *media,
+					    __u32 id)
+{
+	unsigned int i;
+
+	for (i = 0; i < media->entities_count; ++i) {
+		struct media_entity *entity = &media->entities[i];
+
+		if (entity->info.id == id)
+			return entity;
+	}
+
+	return NULL;
+}
+
+int media_setup_link(struct media_device *media,
+		     struct media_pad *source,
+		     struct media_pad *sink,
+		     __u32 flags)
+{
+	struct media_link *link;
+	struct media_link_desc ulink;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < source->entity->num_links; i++) {
+		link = &source->entity->links[i];
+
+		if (link->source->entity == source->entity &&
+		    link->source->index == source->index &&
+		    link->sink->entity == sink->entity &&
+		    link->sink->index == sink->index)
+			break;
+	}
+
+	if (i == source->entity->num_links) {
+		printf("%s: Link not found\n", __func__);
+		return -EINVAL;
+	}
+
+	/* source pad */
+	ulink.source.entity = source->entity->info.id;
+	ulink.source.index = source->index;
+	ulink.source.flags = MEDIA_PAD_FL_SOURCE;
+
+	/* sink pad */
+	ulink.sink.entity = sink->entity->info.id;
+	ulink.sink.index = sink->index;
+	ulink.sink.flags = MEDIA_PAD_FL_SINK;
+
+	ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
+
+	ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
+	if (ret < 0) {
+		printf("%s: Unable to setup link (%s)\n", __func__,
+			strerror(errno));
+		return ret;
+	}
+
+	link->flags = ulink.flags;
+	link->twin->flags = ulink.flags;
+	return 0;
+}
+
+int media_reset_links(struct media_device *media)
+{
+	unsigned int i, j;
+	int ret;
+
+	for (i = 0; i < media->entities_count; ++i) {
+		struct media_entity *entity = &media->entities[i];
+
+		for (j = 0; j < entity->num_links; j++) {
+			struct media_link *link = &entity->links[j];
+
+			if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
+			    link->source->entity != entity)
+				continue;
+
+			ret = media_setup_link(media, link->source, link->sink,
+					       link->flags & ~MEDIA_LNK_FL_ENABLED);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static struct media_link *media_entity_add_link(struct media_entity *entity)
+{
+	if (entity->num_links >= entity->max_links) {
+		struct media_link *links = entity->links;
+		unsigned int max_links = entity->max_links * 2;
+		unsigned int i;
+
+		links = realloc(links, max_links * sizeof *links);
+		if (links == NULL)
+			return NULL;
+
+		for (i = 0; i < entity->num_links; ++i)
+			links[i].twin->twin = &links[i];
+
+		entity->max_links = max_links;
+		entity->links = links;
+	}
+
+	return &entity->links[entity->num_links++];
+}
+
+static int media_enum_links(struct media_device *media)
+{
+	__u32 id;
+	int ret = 0;
+
+	for (id = 1; id <= media->entities_count; id++) {
+		struct media_entity *entity = &media->entities[id - 1];
+		struct media_links_enum links;
+		unsigned int i;
+
+		links.entity = entity->info.id;
+		links.pads = malloc(entity->info.pads * sizeof(struct media_pad_desc));
+		links.links = malloc(entity->info.links * sizeof(struct media_link_desc));
+
+		if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
+			printf("%s: Unable to enumerate pads and links (%s).\n",
+				__func__, strerror(errno));
+			free(links.pads);
+			free(links.links);
+			return -errno;
+		}
+
+		for (i = 0; i < entity->info.pads; ++i) {
+			entity->pads[i].entity = entity;
+			entity->pads[i].index = links.pads[i].index;
+			entity->pads[i].flags = links.pads[i].flags;
+		}
+
+		for (i = 0; i < entity->info.links; ++i) {
+			struct media_link_desc *link = &links.links[i];
+			struct media_link *fwdlink;
+			struct media_link *backlink;
+			struct media_entity *source;
+			struct media_entity *sink;
+
+			source = media_get_entity_by_id(media, link->source.entity);
+			sink = media_get_entity_by_id(media, link->sink.entity);
+
+			if (source == NULL || sink == NULL) {
+				printf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
+					id, i, link->source.entity, link->source.index,
+					link->sink.entity, link->sink.index);
+				ret = -EINVAL;
+			} else {
+				fwdlink = media_entity_add_link(source);
+				fwdlink->source = &source->pads[link->source.index];
+				fwdlink->sink = &sink->pads[link->sink.index];
+				fwdlink->flags = link->flags;
+
+				backlink = media_entity_add_link(sink);
+				backlink->source = &source->pads[link->source.index];
+				backlink->sink = &sink->pads[link->sink.index];
+				backlink->flags = link->flags;
+
+				fwdlink->twin = backlink;
+				backlink->twin = fwdlink;
+			}
+		}
+
+		free(links.pads);
+		free(links.links);
+	}
+
+	return ret;
+}
+
+#ifdef HAVE_LIBUDEV
+
+#include <libudev.h>
+
+static inline int media_udev_open(struct udev **udev)
+{
+	*udev = udev_new();
+	if (*udev == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static inline void media_udev_close(struct udev *udev)
+{
+	if (udev != NULL)
+		udev_unref(udev);
+}
+
+static int media_get_devname_udev(struct udev *udev,
+		struct media_entity *entity, int verbose)
+{
+	struct udev_device *device;
+	dev_t devnum;
+	const char *p;
+	int ret = -ENODEV;
+
+	if (udev == NULL)
+		return -EINVAL;
+
+	devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
+	if (verbose)
+		printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
+	device = udev_device_new_from_devnum(udev, 'c', devnum);
+	if (device) {
+		p = udev_device_get_devnode(device);
+		if (p) {
+			strncpy(entity->devname, p, sizeof(entity->devname));
+			entity->devname[sizeof(entity->devname) - 1] = '\0';
+		}
+		ret = 0;
+	}
+
+	udev_device_unref(device);
+
+	return ret;
+}
+
+#else	/* HAVE_LIBUDEV */
+
+struct udev;
+
+static inline int media_udev_open(struct udev **udev) { return 0; }
+
+static inline void media_udev_close(struct udev *udev) { }
+
+static inline int media_get_devname_udev(struct udev *udev,
+		struct media_entity *entity, int verbose)
+{
+	return -ENOTSUP;
+}
+
+#endif	/* HAVE_LIBUDEV */
+
+static int media_get_devname_sysfs(struct media_entity *entity)
+{
+	struct stat devstat;
+	char devname[32];
+	char sysname[32];
+	char target[1024];
+	char *p;
+	int ret;
+
+	sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
+		entity->info.v4l.minor);
+	ret = readlink(sysname, target, sizeof(target));
+	if (ret < 0)
+		return -errno;
+
+	target[ret] = '\0';
+	p = strrchr(target, '/');
+	if (p == NULL)
+		return -EINVAL;
+
+	sprintf(devname, "/dev/%s", p + 1);
+	ret = stat(devname, &devstat);
+	if (ret < 0)
+		return -errno;
+
+	/* Sanity check: udev might have reordered the device nodes.
+	 * Make sure the major/minor match. We should really use
+	 * libudev.
+	 */
+	if (major(devstat.st_rdev) == entity->info.v4l.major &&
+	    minor(devstat.st_rdev) == entity->info.v4l.minor)
+		strcpy(entity->devname, devname);
+
+	return 0;
+}
+
+static int media_enum_entities(struct media_device *media, int verbose)
+{
+	struct media_entity *entity;
+	struct udev *udev;
+	unsigned int size;
+	__u32 id;
+	int ret;
+
+	ret = media_udev_open(&udev);
+	if (ret < 0)
+		printf("%s: Can't get udev context\n", __func__);
+
+	for (id = 0, ret = 0; ; id = entity->info.id) {
+		size = (media->entities_count + 1) * sizeof(*media->entities);
+		media->entities = realloc(media->entities, size);
+
+		entity = &media->entities[media->entities_count];
+		memset(entity, 0, sizeof(*entity));
+		entity->fd = -1;
+		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
+
+		ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
+		if (ret < 0) {
+			ret = errno != EINVAL ? -errno : 0;
+			break;
+		}
+
+		/* Number of links (for outbound links) plus number of pads (for
+		 * inbound links) is a good safe initial estimate of the total
+		 * number of links.
+		 */
+		entity->max_links = entity->info.pads + entity->info.links;
+
+		entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
+		entity->links = malloc(entity->max_links * sizeof(*entity->links));
+		if (entity->pads == NULL || entity->links == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		media->entities_count++;
+
+		/* Find the corresponding device name. */
+		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
+		    media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			continue;
+
+		/* Try to get the device name via udev */
+		if (!media_get_devname_udev(udev, entity, verbose))
+			continue;
+
+		/* Fall back to get the device name via sysfs */
+		media_get_devname_sysfs(entity);
+	}
+
+	media_udev_close(udev);
+	return ret;
+}
+
+struct media_device *media_open(const char *name, int verbose)
+{
+	struct media_device *media;
+	int ret;
+
+	media = calloc(1, sizeof(*media));
+	if (media == NULL) {
+		printf("%s: unable to allocate memory\n", __func__);
+		return NULL;
+	}
+
+	if (verbose)
+		printf("Opening media device %s\n", name);
+	media->fd = open(name, O_RDWR);
+	if (media->fd < 0) {
+		media_close(media);
+		printf("%s: Can't open media device %s\n", __func__, name);
+		return NULL;
+	}
+
+	if (verbose)
+		printf("Enumerating entities\n");
+
+	ret = media_enum_entities(media, verbose);
+
+	if (ret < 0) {
+		printf("%s: Unable to enumerate entities for device %s (%s)\n",
+			__func__, name, strerror(-ret));
+		media_close(media);
+		return NULL;
+	}
+
+	if (verbose) {
+		printf("Found %u entities\n", media->entities_count);
+		printf("Enumerating pads and links\n");
+	}
+
+	ret = media_enum_links(media);
+	if (ret < 0) {
+		printf("%s: Unable to enumerate pads and linksfor device %s\n",
+			__func__, name);
+		media_close(media);
+		return NULL;
+	}
+
+	return media;
+}
+
+void media_close(struct media_device *media)
+{
+	unsigned int i;
+
+	if (media->fd != -1)
+		close(media->fd);
+
+	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);
+	free(media);
+}
+
diff --git a/src/mediactl.h b/src/mediactl.h
new file mode 100644
index 0000000..b91a2ac
--- /dev/null
+++ b/src/mediactl.h
@@ -0,0 +1,161 @@
+/*
+ * Media controller test application
+ *
+ * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __MEDIA_H__
+#define __MEDIA_H__
+
+#include <linux/media.h>
+
+struct media_link {
+	struct media_pad *source;
+	struct media_pad *sink;
+	struct media_link *twin;
+	__u32 flags;
+	__u32 padding[3];
+};
+
+struct media_pad {
+	struct media_entity *entity;
+	__u32 index;
+	__u32 flags;
+	__u32 padding[3];
+};
+
+struct media_entity {
+	struct media_entity_desc info;
+	struct media_pad *pads;
+	struct media_link *links;
+	unsigned int max_links;
+	unsigned int num_links;
+
+	char devname[32];
+	int fd;
+	__u32 padding[6];
+};
+
+struct media_device {
+	int fd;
+	struct media_entity *entities;
+	unsigned int entities_count;
+	__u32 padding[6];
+};
+
+/**
+ * @brief Open a media device.
+ * @param name - name (including path) of the device node.
+ * @param verbose - whether to print verbose information on the standard output.
+ *
+ * Open the media device referenced by @a name and enumerate entities, pads and
+ * links.
+ *
+ * @return A pointer to a newly allocated media_device structure instance on
+ * success and NULL on failure. The returned pointer must be freed with
+ * media_close when the device isn't needed anymore.
+ */
+struct media_device *media_open(const char *name, int verbose);
+
+/**
+ * @brief Close a media device.
+ * @param media - device instance.
+ *
+ * Close the @a media device instance and free allocated resources. Access to the
+ * device instance is forbidden after this function returns.
+ */
+void media_close(struct media_device *media);
+
+/**
+ * @brief Locate the pad at the other end of a link.
+ * @param pad - sink pad at one end of the link.
+ *
+ * Locate the source pad connected to @a pad through an enabled link. As only one
+ * link connected to a sink pad can be enabled at a time, the connected source
+ * pad is guaranteed to be unique.
+ *
+ * @return A pointer to the connected source pad, or NULL if all links connected
+ * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
+ */
+struct media_pad *media_entity_remote_source(struct media_pad *pad);
+
+/**
+ * @brief Get the type of an entity.
+ * @param entity - the entity.
+ *
+ * @return The type of @a entity.
+ */
+static inline unsigned int media_entity_type(struct media_entity *entity)
+{
+	return entity->info.type & MEDIA_ENT_TYPE_MASK;
+}
+
+/**
+ * @brief Find an entity by its name.
+ * @param media - media device.
+ * @param name - entity name.
+ * @param length - size of @a name.
+ *
+ * Search for an entity with a name equal to @a name.
+ *
+ * @return A pointer to the entity if found, or NULL otherwise.
+ */
+struct media_entity *media_get_entity_by_name(struct media_device *media,
+	const char *name, size_t length);
+
+/**
+ * @brief Find an entity by its ID.
+ * @param media - media device.
+ * @param id - entity ID.
+ *
+ * Search for an entity with an ID equal to @a id.
+ *
+ * @return A pointer to the entity if found, or NULL otherwise.
+ */
+struct media_entity *media_get_entity_by_id(struct media_device *media,
+	__u32 id);
+
+/**
+ * @brief Configure a link.
+ * @param media - media device.
+ * @param source - source pad at the link origin.
+ * @param sink - sink pad at the link target.
+ * @param flags - configuration flags.
+ *
+ * Locate the link between @a source and @a sink, and configure it by applying
+ * the new @a flags.
+ *
+ * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_setup_link(struct media_device *media,
+	struct media_pad *source, struct media_pad *sink,
+	__u32 flags);
+
+/**
+ * @brief Reset all links to the disabled state.
+ * @param media - media device.
+ *
+ * Disable all links in the media device. This function is usually used after
+ * opening a media device to reset all links to a known state.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_reset_links(struct media_device *media);
+
+#endif
+
diff --git a/src/subdev.c b/src/subdev.c
deleted file mode 100644
index f8ccfe3..0000000
--- a/src/subdev.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Media controller test application
- *
- * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- */
-
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <linux/v4l2-subdev.h>
-
-#include "media.h"
-#include "subdev.h"
-#include "tools.h"
-
-int v4l2_subdev_open(struct media_entity *entity)
-{
-	if (entity->fd != -1)
-		return 0;
-
-	entity->fd = open(entity->devname, O_RDWR);
-	if (entity->fd == -1) {
-		printf("%s: Failed to open subdev device node %s\n", __func__,
-			entity->devname);
-		return -errno;
-	}
-
-	return 0;
-}
-
-void v4l2_subdev_close(struct media_entity *entity)
-{
-	close(entity->fd);
-	entity->fd = -1;
-}
-
-int v4l2_subdev_get_format(struct media_entity *entity,
-	struct v4l2_mbus_framefmt *format, unsigned int pad,
-	enum v4l2_subdev_format_whence which)
-{
-	struct v4l2_subdev_format fmt;
-	int ret;
-
-	ret = v4l2_subdev_open(entity);
-	if (ret < 0)
-		return ret;
-
-	memset(&fmt, 0, sizeof(fmt));
-	fmt.pad = pad;
-	fmt.which = which;
-
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
-	if (ret < 0)
-		return -errno;
-
-	*format = fmt.format;
-	return 0;
-}
-
-int v4l2_subdev_set_format(struct media_entity *entity,
-	struct v4l2_mbus_framefmt *format, unsigned int pad,
-	enum v4l2_subdev_format_whence which)
-{
-	struct v4l2_subdev_format fmt;
-	int ret;
-
-	ret = v4l2_subdev_open(entity);
-	if (ret < 0)
-		return ret;
-
-	memset(&fmt, 0, sizeof(fmt));
-	fmt.pad = pad;
-	fmt.which = which;
-	fmt.format = *format;
-
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
-	if (ret < 0)
-		return -errno;
-
-	*format = fmt.format;
-	return 0;
-}
-
-int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
-			 unsigned int pad, enum v4l2_subdev_format_whence which)
-{
-	struct v4l2_subdev_crop crop;
-	int ret;
-
-	ret = v4l2_subdev_open(entity);
-	if (ret < 0)
-		return ret;
-
-	memset(&crop, 0, sizeof(crop));
-	crop.pad = pad;
-	crop.which = which;
-
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &crop);
-	if (ret < 0)
-		return -errno;
-
-	*rect = crop.rect;
-	return 0;
-}
-
-int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
-			 unsigned int pad, enum v4l2_subdev_format_whence which)
-{
-	struct v4l2_subdev_crop crop;
-	int ret;
-
-	ret = v4l2_subdev_open(entity);
-	if (ret < 0)
-		return ret;
-
-	memset(&crop, 0, sizeof(crop));
-	crop.pad = pad;
-	crop.which = which;
-	crop.rect = *rect;
-
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &crop);
-	if (ret < 0)
-		return -errno;
-
-	*rect = crop.rect;
-	return 0;
-}
-
-int v4l2_subdev_get_frame_interval(struct media_entity *entity,
-				   struct v4l2_fract *interval)
-{
-	struct v4l2_subdev_frame_interval ival;
-	int ret;
-
-	ret = v4l2_subdev_open(entity);
-	if (ret < 0)
-		return ret;
-
-	memset(&ival, 0, sizeof(ival));
-
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
-	if (ret < 0)
-		return -errno;
-
-	*interval = ival.interval;
-	return 0;
-}
-
-int v4l2_subdev_set_frame_interval(struct media_entity *entity,
-				   struct v4l2_fract *interval)
-{
-	struct v4l2_subdev_frame_interval ival;
-	int ret;
-
-	ret = v4l2_subdev_open(entity);
-	if (ret < 0)
-		return ret;
-
-	memset(&ival, 0, sizeof(ival));
-	ival.interval = *interval;
-
-	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
-	if (ret < 0)
-		return -errno;
-
-	*interval = ival.interval;
-	return 0;
-}
diff --git a/src/subdev.h b/src/subdev.h
deleted file mode 100644
index b5772e0..0000000
--- a/src/subdev.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Media controller test application
- *
- * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- */
-
-#ifndef __SUBDEV_H__
-#define __SUBDEV_H__
-
-#include <linux/v4l2-subdev.h>
-
-struct media_entity;
-
-/**
- * @brief Open a sub-device.
- * @param entity - sub-device media entity.
- *
- * Open the V4L2 subdev device node associated with @a entity. The file
- * descriptor is stored in the media_entity structure.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int v4l2_subdev_open(struct media_entity *entity);
-
-/**
- * @brief Close a sub-device.
- * @param entity - sub-device media entity.
- *
- * Close the V4L2 subdev device node associated with the @a entity and opened by
- * a previous call to v4l2_subdev_open() (either explicit or implicit).
- */
-void v4l2_subdev_close(struct media_entity *entity);
-
-/**
- * @brief Retrieve the format on a pad.
- * @param entity - subdev-device media entity.
- * @param format - format to be filled.
- * @param pad - pad number.
- * @param which - identifier of the format to get.
- *
- * Retrieve the current format on the @a entity @a pad and store it in the
- * @a format structure.
- *
- * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try format stored
- * in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current
- * active format.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int v4l2_subdev_get_format(struct media_entity *entity,
-	struct v4l2_mbus_framefmt *format, unsigned int pad,
-	enum v4l2_subdev_format_whence which);
-
-/**
- * @brief Set the format on a pad.
- * @param entity - subdev-device media entity.
- * @param format - format.
- * @param pad - pad number.
- * @param which - identifier of the format to set.
- *
- * Set the format on the @a entity @a pad to @a format. The driver is allowed to
- * modify the requested format, in which case @a format is updated with the
- * modifications.
- *
- * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try format stored in the
- * file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the device with an
- * active format.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int v4l2_subdev_set_format(struct media_entity *entity,
-	struct v4l2_mbus_framefmt *format, unsigned int pad,
-	enum v4l2_subdev_format_whence which);
-
-/**
- * @brief Retrieve the crop rectangle on a pad.
- * @param entity - subdev-device media entity.
- * @param rect - crop rectangle to be filled.
- * @param pad - pad number.
- * @param which - identifier of the format to get.
- *
- * Retrieve the current crop rectangleon the @a entity @a pad and store it in
- * the @a rect structure.
- *
- * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try crop rectangle
- * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the
- * current active crop rectangle.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
-	unsigned int pad, enum v4l2_subdev_format_whence which);
-
-/**
- * @brief Set the crop rectangle on a pad.
- * @param entity - subdev-device media entity.
- * @param rect - crop rectangle.
- * @param pad - pad number.
- * @param which - identifier of the format to set.
- *
- * Set the crop rectangle on the @a entity @a pad to @a rect. The driver is
- * allowed to modify the requested rectangle, in which case @a rect is updated
- * with the modifications.
- *
- * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try crop rectangle
- * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the
- * device with an active crop rectangle.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
-	unsigned int pad, enum v4l2_subdev_format_whence which);
-
-/**
- * @brief Retrieve the frame interval on a sub-device.
- * @param entity - subdev-device media entity.
- * @param interval - frame interval to be filled.
- *
- * Retrieve the current frame interval on subdev @a entity and store it in the
- * @a interval structure.
- *
- * Frame interval retrieving is usually supported only on devices at the
- * beginning of video pipelines, such as sensors.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-
-int v4l2_subdev_get_frame_interval(struct media_entity *entity,
-	struct v4l2_fract *interval);
-
-/**
- * @brief Set the frame interval on a sub-device.
- * @param entity - subdev-device media entity.
- * @param interval - frame interval.
- *
- * Set the frame interval on subdev @a entity to @a interval. The driver is
- * allowed to modify the requested frame interval, in which case @a interval is
- * updated with the modifications.
- *
- * Frame interval setting is usually supported only on devices at the beginning
- * of video pipelines, such as sensors.
- *
- * @return 0 on success, or a negative error code on failure.
- */
-int v4l2_subdev_set_frame_interval(struct media_entity *entity,
-	struct v4l2_fract *interval);
-
-#endif
-
diff --git a/src/v4l2subdev.c b/src/v4l2subdev.c
new file mode 100644
index 0000000..785209b
--- /dev/null
+++ b/src/v4l2subdev.c
@@ -0,0 +1,188 @@
+/*
+ * Media controller test application
+ *
+ * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/v4l2-subdev.h>
+
+#include "mediactl.h"
+#include "v4l2subdev.h"
+#include "tools.h"
+
+int v4l2_subdev_open(struct media_entity *entity)
+{
+	if (entity->fd != -1)
+		return 0;
+
+	entity->fd = open(entity->devname, O_RDWR);
+	if (entity->fd == -1) {
+		printf("%s: Failed to open subdev device node %s\n", __func__,
+			entity->devname);
+		return -errno;
+	}
+
+	return 0;
+}
+
+void v4l2_subdev_close(struct media_entity *entity)
+{
+	close(entity->fd);
+	entity->fd = -1;
+}
+
+int v4l2_subdev_get_format(struct media_entity *entity,
+	struct v4l2_mbus_framefmt *format, unsigned int pad,
+	enum v4l2_subdev_format_whence which)
+{
+	struct v4l2_subdev_format fmt;
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	memset(&fmt, 0, sizeof(fmt));
+	fmt.pad = pad;
+	fmt.which = which;
+
+	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
+	if (ret < 0)
+		return -errno;
+
+	*format = fmt.format;
+	return 0;
+}
+
+int v4l2_subdev_set_format(struct media_entity *entity,
+	struct v4l2_mbus_framefmt *format, unsigned int pad,
+	enum v4l2_subdev_format_whence which)
+{
+	struct v4l2_subdev_format fmt;
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	memset(&fmt, 0, sizeof(fmt));
+	fmt.pad = pad;
+	fmt.which = which;
+	fmt.format = *format;
+
+	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
+	if (ret < 0)
+		return -errno;
+
+	*format = fmt.format;
+	return 0;
+}
+
+int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
+			 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	struct v4l2_subdev_crop crop;
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	memset(&crop, 0, sizeof(crop));
+	crop.pad = pad;
+	crop.which = which;
+
+	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &crop);
+	if (ret < 0)
+		return -errno;
+
+	*rect = crop.rect;
+	return 0;
+}
+
+int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
+			 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	struct v4l2_subdev_crop crop;
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	memset(&crop, 0, sizeof(crop));
+	crop.pad = pad;
+	crop.which = which;
+	crop.rect = *rect;
+
+	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &crop);
+	if (ret < 0)
+		return -errno;
+
+	*rect = crop.rect;
+	return 0;
+}
+
+int v4l2_subdev_get_frame_interval(struct media_entity *entity,
+				   struct v4l2_fract *interval)
+{
+	struct v4l2_subdev_frame_interval ival;
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	memset(&ival, 0, sizeof(ival));
+
+	ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
+	if (ret < 0)
+		return -errno;
+
+	*interval = ival.interval;
+	return 0;
+}
+
+int v4l2_subdev_set_frame_interval(struct media_entity *entity,
+				   struct v4l2_fract *interval)
+{
+	struct v4l2_subdev_frame_interval ival;
+	int ret;
+
+	ret = v4l2_subdev_open(entity);
+	if (ret < 0)
+		return ret;
+
+	memset(&ival, 0, sizeof(ival));
+	ival.interval = *interval;
+
+	ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
+	if (ret < 0)
+		return -errno;
+
+	*interval = ival.interval;
+	return 0;
+}
diff --git a/src/v4l2subdev.h b/src/v4l2subdev.h
new file mode 100644
index 0000000..b5772e0
--- /dev/null
+++ b/src/v4l2subdev.h
@@ -0,0 +1,162 @@
+/*
+ * Media controller test application
+ *
+ * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __SUBDEV_H__
+#define __SUBDEV_H__
+
+#include <linux/v4l2-subdev.h>
+
+struct media_entity;
+
+/**
+ * @brief Open a sub-device.
+ * @param entity - sub-device media entity.
+ *
+ * Open the V4L2 subdev device node associated with @a entity. The file
+ * descriptor is stored in the media_entity structure.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_open(struct media_entity *entity);
+
+/**
+ * @brief Close a sub-device.
+ * @param entity - sub-device media entity.
+ *
+ * Close the V4L2 subdev device node associated with the @a entity and opened by
+ * a previous call to v4l2_subdev_open() (either explicit or implicit).
+ */
+void v4l2_subdev_close(struct media_entity *entity);
+
+/**
+ * @brief Retrieve the format on a pad.
+ * @param entity - subdev-device media entity.
+ * @param format - format to be filled.
+ * @param pad - pad number.
+ * @param which - identifier of the format to get.
+ *
+ * Retrieve the current format on the @a entity @a pad and store it in the
+ * @a format structure.
+ *
+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try format stored
+ * in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current
+ * active format.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_get_format(struct media_entity *entity,
+	struct v4l2_mbus_framefmt *format, unsigned int pad,
+	enum v4l2_subdev_format_whence which);
+
+/**
+ * @brief Set the format on a pad.
+ * @param entity - subdev-device media entity.
+ * @param format - format.
+ * @param pad - pad number.
+ * @param which - identifier of the format to set.
+ *
+ * Set the format on the @a entity @a pad to @a format. The driver is allowed to
+ * modify the requested format, in which case @a format is updated with the
+ * modifications.
+ *
+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try format stored in the
+ * file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the device with an
+ * active format.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_set_format(struct media_entity *entity,
+	struct v4l2_mbus_framefmt *format, unsigned int pad,
+	enum v4l2_subdev_format_whence which);
+
+/**
+ * @brief Retrieve the crop rectangle on a pad.
+ * @param entity - subdev-device media entity.
+ * @param rect - crop rectangle to be filled.
+ * @param pad - pad number.
+ * @param which - identifier of the format to get.
+ *
+ * Retrieve the current crop rectangleon the @a entity @a pad and store it in
+ * the @a rect structure.
+ *
+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try crop rectangle
+ * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the
+ * current active crop rectangle.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
+	unsigned int pad, enum v4l2_subdev_format_whence which);
+
+/**
+ * @brief Set the crop rectangle on a pad.
+ * @param entity - subdev-device media entity.
+ * @param rect - crop rectangle.
+ * @param pad - pad number.
+ * @param which - identifier of the format to set.
+ *
+ * Set the crop rectangle on the @a entity @a pad to @a rect. The driver is
+ * allowed to modify the requested rectangle, in which case @a rect is updated
+ * with the modifications.
+ *
+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try crop rectangle
+ * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the
+ * device with an active crop rectangle.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
+	unsigned int pad, enum v4l2_subdev_format_whence which);
+
+/**
+ * @brief Retrieve the frame interval on a sub-device.
+ * @param entity - subdev-device media entity.
+ * @param interval - frame interval to be filled.
+ *
+ * Retrieve the current frame interval on subdev @a entity and store it in the
+ * @a interval structure.
+ *
+ * Frame interval retrieving is usually supported only on devices at the
+ * beginning of video pipelines, such as sensors.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+
+int v4l2_subdev_get_frame_interval(struct media_entity *entity,
+	struct v4l2_fract *interval);
+
+/**
+ * @brief Set the frame interval on a sub-device.
+ * @param entity - subdev-device media entity.
+ * @param interval - frame interval.
+ *
+ * Set the frame interval on subdev @a entity to @a interval. The driver is
+ * allowed to modify the requested frame interval, in which case @a interval is
+ * updated with the modifications.
+ *
+ * Frame interval setting is usually supported only on devices at the beginning
+ * of video pipelines, such as sensors.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_set_frame_interval(struct media_entity *entity,
+	struct v4l2_fract *interval);
+
+#endif
+
-- 
1.7.2.5


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

* [media-ctl PATCH 2/7] Move link parsing from main.c to media.c, making it part of libmediactl
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 1/7] Rename files to match the names of the libraries Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 3/7] Move V4L2 subdev format parsing from main.c to subdev.c Sakari Ailus
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

This makes it possible to benefit from the link parsing code anywhere the
library is being used.

dprintf macro will later be replaced with proper debug support.

Also fix a case where -1 was returned on error and the user was expected to
check the value of errno. Negative error codes are now returned
consistently.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/main.c     |  139 +---------------------------------------------
 src/mediactl.c |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/mediactl.h |   57 +++++++++++++++++++-
 3 files changed, 212 insertions(+), 151 deletions(-)

diff --git a/src/main.c b/src/main.c
index 55a6e2d..02cdecd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -335,137 +335,6 @@ void media_print_topology(struct media_device *media, int dot)
 }
 
 /* -----------------------------------------------------------------------------
- * Links setup
- */
-
-static struct media_pad *parse_pad(struct media_device *media, const char *p, char **endp)
-{
-	unsigned int entity_id, pad;
-	struct media_entity *entity;
-	char *end;
-
-	for (; isspace(*p); ++p);
-
-	if (*p == '"') {
-		for (end = (char *)p + 1; *end && *end != '"'; ++end);
-		if (*end != '"')
-			return NULL;
-
-		entity = media_get_entity_by_name(media, p + 1, end - p - 1);
-		if (entity == NULL)
-			return NULL;
-
-		++end;
-	} else {
-		entity_id = strtoul(p, &end, 10);
-		entity = media_get_entity_by_id(media, entity_id);
-		if (entity == NULL)
-			return NULL;
-	}
-	for (; isspace(*end); ++end);
-
-	if (*end != ':')
-		return NULL;
-	for (p = end + 1; isspace(*p); ++p);
-
-	pad = strtoul(p, &end, 10);
-	for (p = end; isspace(*p); ++p);
-
-	if (pad >= entity->info.pads)
-		return NULL;
-
-	for (p = end; isspace(*p); ++p);
-	if (endp)
-		*endp = (char *)p;
-
-	return &entity->pads[pad];
-}
-
-static struct media_link *parse_link(struct media_device *media, const char *p, char **endp)
-{
-	struct media_link *link;
-	struct media_pad *source;
-	struct media_pad *sink;
-	unsigned int i;
-	char *end;
-
-	source = parse_pad(media, p, &end);
-	if (source == NULL)
-		return NULL;
-
-	if (end[0] != '-' || end[1] != '>')
-		return NULL;
-	p = end + 2;
-
-	sink = parse_pad(media, p, &end);
-	if (sink == NULL)
-		return NULL;
-
-	*endp = end;
-
-	for (i = 0; i < source->entity->num_links; i++) {
-		link = &source->entity->links[i];
-
-		if (link->source == source && link->sink == sink)
-			return link;
-	}
-
-	return NULL;
-}
-
-static int setup_link(struct media_device *media, const char *p, char **endp)
-{
-	struct media_link *link;
-	__u32 flags;
-	char *end;
-
-	link = parse_link(media, p, &end);
-	if (link == NULL) {
-		printf("Unable to parse link\n");
-		return -EINVAL;
-	}
-
-	p = end;
-	if (*p++ != '[') {
-		printf("Unable to parse link flags\n");
-		return -EINVAL;
-	}
-
-	flags = strtoul(p, &end, 10);
-	for (p = end; isspace(*p); p++);
-	if (*p++ != ']') {
-		printf("Unable to parse link flags\n");
-		return -EINVAL;
-	}
-
-	for (; isspace(*p); p++);
-	*endp = (char *)p;
-
-	printf("Setting up link %u:%u -> %u:%u [%u]\n",
-		link->source->entity->info.id, link->source->index,
-		link->sink->entity->info.id, link->sink->index,
-		flags);
-
-	return media_setup_link(media, link->source, link->sink, flags);
-}
-
-static int setup_links(struct media_device *media, const char *p)
-{
-	char *end;
-	int ret;
-
-	do {
-		ret = setup_link(media, p, &end);
-		if (ret < 0)
-			return ret;
-
-		p = end + 1;
-	} while (*end == ',');
-
-	return *end ? -EINVAL : 0;
-}
-
-/* -----------------------------------------------------------------------------
  * Formats setup
  */
 
@@ -558,7 +427,7 @@ static struct media_pad *parse_pad_format(struct media_device *media,
 
 	for (; isspace(*p); ++p);
 
-	pad = parse_pad(media, p, &end);
+	pad = media_parse_pad(media, p, &end);
 	if (pad == NULL)
 		return NULL;
 
@@ -775,7 +644,7 @@ int main(int argc, char **argv)
 	if (media_opts.pad) {
 		struct media_pad *pad;
 
-		pad = parse_pad(media, media_opts.pad, NULL);
+		pad = media_parse_pad(media, media_opts.pad, NULL);
 		if (pad == NULL) {
 			printf("Pad '%s' not found\n", media_opts.pad);
 			goto out;
@@ -797,7 +666,7 @@ int main(int argc, char **argv)
 	}
 
 	if (media_opts.links)
-		setup_links(media, media_opts.links);
+		media_parse_setup_links(media, media_opts.links);
 
 	if (media_opts.formats)
 		setup_formats(media, media_opts.formats);
@@ -814,7 +683,7 @@ int main(int argc, char **argv)
 			if (buffer[0] == '\n')
 				break;
 
-			setup_link(media, buffer, &end);
+			media_parse_setup_link(media, buffer, &end);
 		}
 	}
 
diff --git a/src/mediactl.c b/src/mediactl.c
index 5c710c9..dc5b022 100644
--- a/src/mediactl.c
+++ b/src/mediactl.c
@@ -36,6 +36,12 @@
 #include "mediactl.h"
 #include "tools.h"
 
+#ifdef DEBUG
+#define dprintf(...) printf(__VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
 struct media_pad *media_entity_remote_source(struct media_pad *pad)
 {
 	unsigned int i;
@@ -107,8 +113,8 @@ int media_setup_link(struct media_device *media,
 	}
 
 	if (i == source->entity->num_links) {
-		printf("%s: Link not found\n", __func__);
-		return -EINVAL;
+		dprintf("%s: Link not found\n", __func__);
+		return -ENOENT;
 	}
 
 	/* source pad */
@@ -124,10 +130,10 @@ int media_setup_link(struct media_device *media,
 	ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
 
 	ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
-	if (ret < 0) {
-		printf("%s: Unable to setup link (%s)\n", __func__,
+	if (ret == -1) {
+		dprintf("%s: Unable to setup link (%s)\n", __func__,
 			strerror(errno));
-		return ret;
+		return -errno;
 	}
 
 	link->flags = ulink.flags;
@@ -196,7 +202,7 @@ static int media_enum_links(struct media_device *media)
 		links.links = malloc(entity->info.links * sizeof(struct media_link_desc));
 
 		if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
-			printf("%s: Unable to enumerate pads and links (%s).\n",
+			dprintf("%s: Unable to enumerate pads and links (%s).\n",
 				__func__, strerror(errno));
 			free(links.pads);
 			free(links.links);
@@ -220,7 +226,7 @@ static int media_enum_links(struct media_device *media)
 			sink = media_get_entity_by_id(media, link->sink.entity);
 
 			if (source == NULL || sink == NULL) {
-				printf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
+				dprintf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
 					id, i, link->source.entity, link->source.index,
 					link->sink.entity, link->sink.index);
 				ret = -EINVAL;
@@ -412,39 +418,40 @@ struct media_device *media_open(const char *name, int verbose)
 
 	media = calloc(1, sizeof(*media));
 	if (media == NULL) {
-		printf("%s: unable to allocate memory\n", __func__);
+		dprintf("%s: unable to allocate memory\n", __func__);
 		return NULL;
 	}
 
 	if (verbose)
-		printf("Opening media device %s\n", name);
+		dprintf("Opening media device %s\n", name);
+
 	media->fd = open(name, O_RDWR);
 	if (media->fd < 0) {
 		media_close(media);
-		printf("%s: Can't open media device %s\n", __func__, name);
+		dprintf("%s: Can't open media device %s\n", __func__, name);
 		return NULL;
 	}
 
 	if (verbose)
-		printf("Enumerating entities\n");
+		dprintf("Enumerating entities\n");
 
 	ret = media_enum_entities(media, verbose);
 
 	if (ret < 0) {
-		printf("%s: Unable to enumerate entities for device %s (%s)\n",
+		dprintf("%s: Unable to enumerate entities for device %s (%s)\n",
 			__func__, name, strerror(-ret));
 		media_close(media);
 		return NULL;
 	}
 
 	if (verbose) {
-		printf("Found %u entities\n", media->entities_count);
-		printf("Enumerating pads and links\n");
+		dprintf("Found %u entities\n", media->entities_count);
+		dprintf("Enumerating pads and links\n");
 	}
 
 	ret = media_enum_links(media);
 	if (ret < 0) {
-		printf("%s: Unable to enumerate pads and linksfor device %s\n",
+		dprintf("%s: Unable to enumerate pads and linksfor device %s\n",
 			__func__, name);
 		media_close(media);
 		return NULL;
@@ -473,3 +480,133 @@ void media_close(struct media_device *media)
 	free(media);
 }
 
+struct media_pad *media_parse_pad(struct media_device *media,
+				  const char *p, char **endp)
+{
+	unsigned int entity_id, pad;
+	struct media_entity *entity;
+	char *end;
+
+	for (; isspace(*p); ++p);
+
+	if (*p == '"') {
+		for (end = (char *)p + 1; *end && *end != '"'; ++end);
+		if (*end != '"')
+			return NULL;
+
+		entity = media_get_entity_by_name(media, p + 1, end - p - 1);
+		if (entity == NULL)
+			return NULL;
+
+		++end;
+	} else {
+		entity_id = strtoul(p, &end, 10);
+		entity = media_get_entity_by_id(media, entity_id);
+		if (entity == NULL)
+			return NULL;
+	}
+	for (; isspace(*end); ++end);
+
+	if (*end != ':')
+		return NULL;
+	for (p = end + 1; isspace(*p); ++p);
+
+	pad = strtoul(p, &end, 10);
+	for (p = end; isspace(*p); ++p);
+
+	if (pad >= entity->info.pads)
+		return NULL;
+
+	for (p = end; isspace(*p); ++p);
+	if (endp)
+		*endp = (char *)p;
+
+	return &entity->pads[pad];
+}
+
+struct media_link *media_parse_link(struct media_device *media,
+				    const char *p, char **endp)
+{
+	struct media_link *link;
+	struct media_pad *source;
+	struct media_pad *sink;
+	unsigned int i;
+	char *end;
+
+	source = media_parse_pad(media, p, &end);
+	if (source == NULL)
+		return NULL;
+
+	if (end[0] != '-' || end[1] != '>')
+		return NULL;
+	p = end + 2;
+
+	sink = media_parse_pad(media, p, &end);
+	if (sink == NULL)
+		return NULL;
+
+	*endp = end;
+
+	for (i = 0; i < source->entity->num_links; i++) {
+		link = &source->entity->links[i];
+
+		if (link->source == source && link->sink == sink)
+			return link;
+	}
+
+	return NULL;
+}
+
+int media_parse_setup_link(struct media_device *media,
+			   const char *p, char **endp)
+{
+	struct media_link *link;
+	__u32 flags;
+	char *end;
+
+	link = media_parse_link(media, p, &end);
+	if (link == NULL) {
+		dprintf("Unable to parse link\n");
+		return -EINVAL;
+	}
+
+	p = end;
+	if (*p++ != '[') {
+		dprintf("Unable to parse link flags\n");
+		return -EINVAL;
+	}
+
+	flags = strtoul(p, &end, 10);
+	for (p = end; isspace(*p); p++);
+	if (*p++ != ']') {
+		dprintf("Unable to parse link flags\n");
+		return -EINVAL;
+	}
+
+	for (; isspace(*p); p++);
+	*endp = (char *)p;
+
+	dprintf("Setting up link %u:%u -> %u:%u [%u]\n",
+		link->source->entity->info.id, link->source->index,
+		link->sink->entity->info.id, link->sink->index,
+		flags);
+
+	return media_setup_link(media, link->source, link->sink, flags);
+}
+
+int media_parse_setup_links(struct media_device *media, const char *p)
+{
+	char *end;
+	int ret;
+
+	do {
+		ret = media_parse_setup_link(media, p, &end);
+		if (ret < 0)
+			return ret;
+
+		p = end + 1;
+	} while (*end == ',');
+
+	return *end ? -EINVAL : 0;
+}
+
diff --git a/src/mediactl.h b/src/mediactl.h
index b91a2ac..5627cd7 100644
--- a/src/mediactl.h
+++ b/src/mediactl.h
@@ -140,7 +140,9 @@ struct media_entity *media_get_entity_by_id(struct media_device *media,
  *
  * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
  *
- * @return 0 on success, or a negative error code on failure.
+ * @return 0 on success, -1 on failure:
+ *	   -ENOENT: link not found
+ *	   - other error codes returned by MEDIA_IOC_SETUP_LINK
  */
 int media_setup_link(struct media_device *media,
 	struct media_pad *source, struct media_pad *sink,
@@ -157,5 +159,58 @@ int media_setup_link(struct media_device *media,
  */
 int media_reset_links(struct media_device *media);
 
+/**
+ * @brief Parse string to a pad 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 a pad and return its struct
+ * media_pad instance.
+ *
+ * @return Pointer to struct media_pad on success, NULL on failure.
+ */
+struct media_pad *media_parse_pad(struct media_device *media,
+				  const char *p, char **endp);
+
+/**
+ * @brief Parse string to a link on the media device.
+ * @param media - media device.
+ * @param p - input string
+ * @param endp - pointer to p where parsing ended
+ *
+ * Parse NULL terminated string p describing a link and return its struct
+ * media_link instance.
+ *
+ * @return Pointer to struct media_link on success, NULL on failure.
+ */
+struct media_link *media_parse_link(struct media_device *media,
+				    const char *p, char **endp);
+
+/**
+ * @brief Parse string to a link on the media device and set it up.
+ * @param media - media device.
+ * @param p - input string
+ *
+ * Parse NULL terminated string p describing a link and its configuration
+ * and configure the link.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_parse_setup_link(struct media_device *media,
+			   const char *p, char **endp);
+
+/**
+ * @brief Parse string to link(s) on the media device and set it up.
+ * @param media - media device.
+ * @param p - input string
+ *
+ * Parse NULL terminated string p describing link(s) separated by
+ * commas (,) and configure the link(s).
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_parse_setup_links(struct media_device *media, const char *p);
+
 #endif
 
-- 
1.7.2.5


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

* [media-ctl PATCH 3/7] Move V4L2 subdev format parsing from main.c to subdev.c
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 1/7] Rename files to match the names of the libraries Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 2/7] Move link parsing from main.c to media.c, making it part of libmediactl Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 4/7] libv4l2subdev and libmediactl are not test programs Sakari Ailus
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

This makes format parsing a part of the libv4l2subdev and thus available on
all who use the library.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/main.c       |  340 +-----------------------------------------------------
 src/v4l2subdev.c |  343 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/v4l2subdev.h |   37 ++++++
 3 files changed, 382 insertions(+), 338 deletions(-)

diff --git a/src/main.c b/src/main.c
index 02cdecd..0d68ff6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -45,61 +45,6 @@
  * Printing
  */
 
-static struct {
-	const char *name;
-	enum v4l2_mbus_pixelcode code;
-} mbus_formats[] = {
-	{ "Y8", V4L2_MBUS_FMT_Y8_1X8},
-	{ "Y10", V4L2_MBUS_FMT_Y10_1X10 },
-	{ "Y12", V4L2_MBUS_FMT_Y12_1X12 },
-	{ "YUYV", V4L2_MBUS_FMT_YUYV8_1X16 },
-	{ "UYVY", V4L2_MBUS_FMT_UYVY8_1X16 },
-	{ "SBGGR8", V4L2_MBUS_FMT_SBGGR8_1X8 },
-	{ "SGBRG8", V4L2_MBUS_FMT_SGBRG8_1X8 },
-	{ "SGRBG8", V4L2_MBUS_FMT_SGRBG8_1X8 },
-	{ "SRGGB8", V4L2_MBUS_FMT_SRGGB8_1X8 },
-	{ "SBGGR10", V4L2_MBUS_FMT_SBGGR10_1X10 },
-	{ "SGBRG10", V4L2_MBUS_FMT_SGBRG10_1X10 },
-	{ "SGRBG10", V4L2_MBUS_FMT_SGRBG10_1X10 },
-	{ "SRGGB10", V4L2_MBUS_FMT_SRGGB10_1X10 },
-	{ "SBGGR10_DPCM8", V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 },
-	{ "SGBRG10_DPCM8", V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 },
-	{ "SGRBG10_DPCM8", V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 },
-	{ "SRGGB10_DPCM8", V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 },
-	{ "SBGGR12", V4L2_MBUS_FMT_SBGGR12_1X12 },
-	{ "SGBRG12", V4L2_MBUS_FMT_SGBRG12_1X12 },
-	{ "SGRBG12", V4L2_MBUS_FMT_SGRBG12_1X12 },
-	{ "SRGGB12", V4L2_MBUS_FMT_SRGGB12_1X12 },
-};
-
-static const char *pixelcode_to_string(enum v4l2_mbus_pixelcode code)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
-		if (mbus_formats[i].code == code)
-			return mbus_formats[i].name;
-	}
-
-	return "unknown";
-}
-
-static enum v4l2_mbus_pixelcode string_to_pixelcode(const char *string,
-					     unsigned int length)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
-		if (strncmp(mbus_formats[i].name, string, length) == 0)
-			break;
-	}
-
-	if (i == ARRAY_SIZE(mbus_formats))
-		return (enum v4l2_mbus_pixelcode)-1;
-
-	return mbus_formats[i].code;
-}
-
 static void v4l2_subdev_print_format(struct media_entity *entity,
 	unsigned int pad, enum v4l2_subdev_format_whence which)
 {
@@ -111,7 +56,7 @@ static void v4l2_subdev_print_format(struct media_entity *entity,
 	if (ret != 0)
 		return;
 
-	printf("[%s %ux%u", pixelcode_to_string(format.code),
+	printf("[%s %ux%u", v4l2_subdev_pixelcode_to_string(format.code),
 	       format.width, format.height);
 
 	ret = v4l2_subdev_get_crop(entity, &rect, pad, which);
@@ -334,287 +279,6 @@ void media_print_topology(struct media_device *media, int dot)
 		media_print_topology_text(media);
 }
 
-/* -----------------------------------------------------------------------------
- * Formats setup
- */
-
-static int parse_format(struct v4l2_mbus_framefmt *format, const char *p, char **endp)
-{
-	enum v4l2_mbus_pixelcode code;
-	unsigned int width, height;
-	char *end;
-
-	for (; isspace(*p); ++p);
-	for (end = (char *)p; !isspace(*end) && *end != '\0'; ++end);
-
-	code = string_to_pixelcode(p, end - p);
-	if (code == (enum v4l2_mbus_pixelcode)-1)
-		return -EINVAL;
-
-	for (p = end; isspace(*p); ++p);
-	width = strtoul(p, &end, 10);
-	if (*end != 'x')
-		return -EINVAL;
-
-	p = end + 1;
-	height = strtoul(p, &end, 10);
-	*endp = end;
-
-	memset(format, 0, sizeof(*format));
-	format->width = width;
-	format->height = height;
-	format->code = code;
-
-	return 0;
-}
-
-static int parse_crop(struct v4l2_rect *crop, const char *p, char **endp)
-{
-	char *end;
-
-	if (*p++ != '(')
-		return -EINVAL;
-
-	crop->left = strtoul(p, &end, 10);
-	if (*end != ',')
-		return -EINVAL;
-
-	p = end + 1;
-	crop->top = strtoul(p, &end, 10);
-	if (*end++ != ')')
-		return -EINVAL;
-	if (*end != '/')
-		return -EINVAL;
-
-	p = end + 1;
-	crop->width = strtoul(p, &end, 10);
-	if (*end != 'x')
-		return -EINVAL;
-
-	p = end + 1;
-	crop->height = strtoul(p, &end, 10);
-	*endp = end;
-
-	return 0;
-}
-
-static int parse_frame_interval(struct v4l2_fract *interval, const char *p, char **endp)
-{
-	char *end;
-
-	for (; isspace(*p); ++p);
-
-	interval->numerator = strtoul(p, &end, 10);
-
-	for (p = end; isspace(*p); ++p);
-	if (*p++ != '/')
-		return -EINVAL;
-
-	for (; isspace(*p); ++p);
-	interval->denominator = strtoul(p, &end, 10);
-
-	*endp = end;
-	return 0;
-}
-
-static struct media_pad *parse_pad_format(struct media_device *media,
-	struct v4l2_mbus_framefmt *format, struct v4l2_rect *crop,
-	struct v4l2_fract *interval, const char *p, char **endp)
-{
-	struct media_pad *pad;
-	char *end;
-	int ret;
-
-	for (; isspace(*p); ++p);
-
-	pad = media_parse_pad(media, p, &end);
-	if (pad == NULL)
-		return NULL;
-
-	for (p = end; isspace(*p); ++p);
-	if (*p++ != '[')
-		return NULL;
-
-	for (; isspace(*p); ++p);
-
-	if (isalnum(*p)) {
-		ret = parse_format(format, p, &end);
-		if (ret < 0)
-			return NULL;
-
-		for (p = end; isspace(*p); p++);
-	}
-
-	if (*p == '(') {
-		ret = parse_crop(crop, p, &end);
-		if (ret < 0)
-			return NULL;
-
-		for (p = end; isspace(*p); p++);
-	}
-
-	if (*p == '@') {
-		ret = parse_frame_interval(interval, ++p, &end);
-		if (ret < 0)
-			return NULL;
-
-		for (p = end; isspace(*p); p++);
-	}
-
-	if (*p != ']')
-		return NULL;
-
-	*endp = (char *)p + 1;
-	return pad;
-}
-
-static int set_format(struct media_pad *pad, struct v4l2_mbus_framefmt *format)
-{
-	int ret;
-
-	if (format->width == 0 || format->height == 0)
-		return 0;
-
-	printf("Setting up format %s %ux%u on pad %s/%u\n",
-		pixelcode_to_string(format->code), format->width, format->height,
-		pad->entity->info.name, pad->index);
-
-	ret = v4l2_subdev_set_format(pad->entity, format, pad->index,
-				     V4L2_SUBDEV_FORMAT_ACTIVE);
-	if (ret < 0) {
-		printf("Unable to set format: %s (%d)\n", strerror(-ret), ret);
-		return ret;
-	}
-
-	printf("Format set: %s %ux%u\n",
-		pixelcode_to_string(format->code), format->width, format->height);
-
-	return 0;
-}
-
-static int set_crop(struct media_pad *pad, struct v4l2_rect *crop)
-{
-	int ret;
-
-	if (crop->left == -1 || crop->top == -1)
-		return 0;
-
-	printf("Setting up crop rectangle (%u,%u)/%ux%u on pad %s/%u\n",
-		crop->left, crop->top, crop->width, crop->height,
-		pad->entity->info.name, pad->index);
-
-	ret = v4l2_subdev_set_crop(pad->entity, crop, pad->index,
-				   V4L2_SUBDEV_FORMAT_ACTIVE);
-	if (ret < 0) {
-		printf("Unable to set crop rectangle: %s (%d)\n", strerror(-ret), ret);
-		return ret;
-	}
-
-	printf("Crop rectangle set: (%u,%u)/%ux%u\n",
-		crop->left, crop->top, crop->width, crop->height);
-
-	return 0;
-}
-
-static int set_frame_interval(struct media_entity *entity, struct v4l2_fract *interval)
-{
-	int ret;
-
-	if (interval->numerator == 0)
-		return 0;
-
-	printf("Setting up frame interval %u/%u on entity %s\n",
-		interval->numerator, interval->denominator, entity->info.name);
-
-	ret = v4l2_subdev_set_frame_interval(entity, interval);
-	if (ret < 0) {
-		printf("Unable to set frame interval: %s (%d)", strerror(-ret), ret);
-		return ret;
-	}
-
-	printf("Frame interval set: %u/%u\n",
-		interval->numerator, interval->denominator);
-
-	return 0;
-}
-
-
-static int setup_format(struct media_device *media, const char *p, char **endp)
-{
-	struct v4l2_mbus_framefmt format = { 0, 0, 0 };
-	struct media_pad *pad;
-	struct v4l2_rect crop = { -1, -1, -1, -1 };
-	struct v4l2_fract interval = { 0, 0 };
-	unsigned int i;
-	char *end;
-	int ret;
-
-	pad = parse_pad_format(media, &format, &crop, &interval, p, &end);
-	if (pad == NULL) {
-		printf("Unable to parse format\n");
-		return -EINVAL;
-	}
-
-	if (pad->flags & MEDIA_PAD_FL_SOURCE) {
-		ret = set_crop(pad, &crop);
-		if (ret < 0)
-			return ret;
-	}
-
-	ret = set_format(pad, &format);
-	if (ret < 0)
-		return ret;
-
-	if (pad->flags & MEDIA_PAD_FL_SINK) {
-		ret = set_crop(pad, &crop);
-		if (ret < 0)
-			return ret;
-	}
-
-	ret = set_frame_interval(pad->entity, &interval);
-	if (ret < 0)
-		return ret;
-
-
-	/* If the pad is an output pad, automatically set the same format on
-	 * the remote subdev input pads, if any.
-	 */
-	if (pad->flags & MEDIA_PAD_FL_SOURCE) {
-		for (i = 0; i < pad->entity->num_links; ++i) {
-			struct media_link *link = &pad->entity->links[i];
-			struct v4l2_mbus_framefmt remote_format;
-
-			if (!(link->flags & MEDIA_LNK_FL_ENABLED))
-				continue;
-
-			if (link->source == pad &&
-			    link->sink->entity->info.type == MEDIA_ENT_T_V4L2_SUBDEV) {
-				remote_format = format;
-				set_format(link->sink, &remote_format);
-			}
-		}
-	}
-
-	*endp = end;
-	return 0;
-}
-
-static int setup_formats(struct media_device *media, const char *p)
-{
-	char *end;
-	int ret;
-
-	do {
-		ret = setup_format(media, p, &end);
-		if (ret < 0)
-			return ret;
-
-		p = end + 1;
-	} while (*end == ',');
-
-	return *end ? -EINVAL : 0;
-}
-
 int main(int argc, char **argv)
 {
 	struct media_device *media;
@@ -669,7 +333,7 @@ int main(int argc, char **argv)
 		media_parse_setup_links(media, media_opts.links);
 
 	if (media_opts.formats)
-		setup_formats(media, media_opts.formats);
+		v4l2_subdev_parse_setup_formats(media, media_opts.formats);
 
 	if (media_opts.interactive) {
 		while (1) {
diff --git a/src/v4l2subdev.c b/src/v4l2subdev.c
index 785209b..0b4793d 100644
--- a/src/v4l2subdev.c
+++ b/src/v4l2subdev.c
@@ -186,3 +186,346 @@ int v4l2_subdev_set_frame_interval(struct media_entity *entity,
 	*interval = ival.interval;
 	return 0;
 }
+
+static int v4l2_subdev_parse_format(struct v4l2_mbus_framefmt *format,
+				    const char *p, char **endp)
+{
+	enum v4l2_mbus_pixelcode code;
+	unsigned int width, height;
+	char *end;
+
+	for (; isspace(*p); ++p);
+	for (end = (char *)p; !isspace(*end) && *end != '\0'; ++end);
+
+	code = v4l2_subdev_string_to_pixelcode(p, end - p);
+	if (code == (enum v4l2_mbus_pixelcode)-1)
+		return -EINVAL;
+
+	for (p = end; isspace(*p); ++p);
+	width = strtoul(p, &end, 10);
+	if (*end != 'x')
+		return -EINVAL;
+
+	p = end + 1;
+	height = strtoul(p, &end, 10);
+	*endp = end;
+
+	memset(format, 0, sizeof(*format));
+	format->width = width;
+	format->height = height;
+	format->code = code;
+
+	return 0;
+}
+
+static int v4l2_subdev_parse_crop(
+	struct v4l2_rect *crop, const char *p, char **endp)
+{
+	char *end;
+
+	if (*p++ != '(')
+		return -EINVAL;
+
+	crop->left = strtoul(p, &end, 10);
+	if (*end != ',')
+		return -EINVAL;
+
+	p = end + 1;
+	crop->top = strtoul(p, &end, 10);
+	if (*end++ != ')')
+		return -EINVAL;
+	if (*end != '/')
+		return -EINVAL;
+
+	p = end + 1;
+	crop->width = strtoul(p, &end, 10);
+	if (*end != 'x')
+		return -EINVAL;
+
+	p = end + 1;
+	crop->height = strtoul(p, &end, 10);
+	*endp = end;
+
+	return 0;
+}
+
+static int v4l2_subdev_parse_frame_interval(struct v4l2_fract *interval,
+					    const char *p, char **endp)
+{
+	char *end;
+
+	for (; isspace(*p); ++p);
+
+	interval->numerator = strtoul(p, &end, 10);
+
+	for (p = end; isspace(*p); ++p);
+	if (*p++ != '/')
+		return -EINVAL;
+
+	for (; isspace(*p); ++p);
+	interval->denominator = strtoul(p, &end, 10);
+
+	*endp = end;
+	return 0;
+}
+
+static struct media_pad *v4l2_subdev_parse_pad_format(
+	struct media_device *media, struct v4l2_mbus_framefmt *format,
+	struct v4l2_rect *crop, struct v4l2_fract *interval, const char *p,
+	char **endp)
+{
+	struct media_pad *pad;
+	char *end;
+	int ret;
+
+	for (; isspace(*p); ++p);
+
+	pad = media_parse_pad(media, p, &end);
+	if (pad == NULL)
+		return NULL;
+
+	for (p = end; isspace(*p); ++p);
+	if (*p++ != '[')
+		return NULL;
+
+	for (; isspace(*p); ++p);
+
+	if (isalnum(*p)) {
+		ret = v4l2_subdev_parse_format(format, p, &end);
+		if (ret < 0)
+			return NULL;
+
+		for (p = end; isspace(*p); p++);
+	}
+
+	if (*p == '(') {
+		ret = v4l2_subdev_parse_crop(crop, p, &end);
+		if (ret < 0)
+			return NULL;
+
+		for (p = end; isspace(*p); p++);
+	}
+
+	if (*p == '@') {
+		ret = v4l2_subdev_parse_frame_interval(interval, ++p, &end);
+		if (ret < 0)
+			return NULL;
+
+		for (p = end; isspace(*p); p++);
+	}
+
+	if (*p != ']')
+		return NULL;
+
+	*endp = (char *)p + 1;
+	return pad;
+}
+
+static int set_format(struct media_pad *pad,
+		      struct v4l2_mbus_framefmt *format)
+{
+	int ret;
+
+	if (format->width == 0 || format->height == 0)
+		return 0;
+
+	printf("Setting up format %s %ux%u on pad %s/%u\n",
+	       v4l2_subdev_pixelcode_to_string(format->code),
+	       format->width, format->height,
+	       pad->entity->info.name, pad->index);
+
+	ret = v4l2_subdev_set_format(pad->entity, format, pad->index,
+				     V4L2_SUBDEV_FORMAT_ACTIVE);
+	if (ret < 0) {
+		printf("Unable to set format: %s (%d)\n", strerror(-ret), ret);
+		return ret;
+	}
+
+	printf("Format set: %s %ux%u\n",
+	       v4l2_subdev_pixelcode_to_string(format->code),
+	       format->width, format->height);
+
+	return 0;
+}
+
+static int set_crop(struct media_pad *pad, struct v4l2_rect *crop)
+{
+	int ret;
+
+	if (crop->left == -1 || crop->top == -1)
+		return 0;
+
+	printf("Setting up crop rectangle (%u,%u)/%ux%u on pad %s/%u\n",
+		crop->left, crop->top, crop->width, crop->height,
+		pad->entity->info.name, pad->index);
+
+	ret = v4l2_subdev_set_crop(pad->entity, crop, pad->index,
+				   V4L2_SUBDEV_FORMAT_ACTIVE);
+	if (ret < 0) {
+		printf("Unable to set crop rectangle: %s (%d)\n", strerror(-ret), ret);
+		return ret;
+	}
+
+	printf("Crop rectangle set: (%u,%u)/%ux%u\n",
+		crop->left, crop->top, crop->width, crop->height);
+
+	return 0;
+}
+
+static int set_frame_interval(struct media_entity *entity,
+			      struct v4l2_fract *interval)
+{
+	int ret;
+
+	if (interval->numerator == 0)
+		return 0;
+
+	printf("Setting up frame interval %u/%u on entity %s\n",
+		interval->numerator, interval->denominator, entity->info.name);
+
+	ret = v4l2_subdev_set_frame_interval(entity, interval);
+	if (ret < 0) {
+		printf("Unable to set frame interval: %s (%d)", strerror(-ret), ret);
+		return ret;
+	}
+
+	printf("Frame interval set: %u/%u\n",
+		interval->numerator, interval->denominator);
+
+	return 0;
+}
+
+
+static int v4l2_subdev_parse_setup_format(struct media_device *media,
+					  const char *p, char **endp)
+{
+	struct v4l2_mbus_framefmt format = { 0, 0, 0 };
+	struct media_pad *pad;
+	struct v4l2_rect crop = { -1, -1, -1, -1 };
+	struct v4l2_fract interval = { 0, 0 };
+	unsigned int i;
+	char *end;
+	int ret;
+
+	pad = v4l2_subdev_parse_pad_format(media, &format, &crop, &interval,
+					   p, &end);
+	if (pad == NULL) {
+		printf("Unable to parse format\n");
+		return -EINVAL;
+	}
+
+	if (pad->flags & MEDIA_PAD_FL_SOURCE) {
+		ret = set_crop(pad, &crop);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = set_format(pad, &format);
+	if (ret < 0)
+		return ret;
+
+	if (pad->flags & MEDIA_PAD_FL_SINK) {
+		ret = set_crop(pad, &crop);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = set_frame_interval(pad->entity, &interval);
+	if (ret < 0)
+		return ret;
+
+
+	/* If the pad is an output pad, automatically set the same format on
+	 * the remote subdev input pads, if any.
+	 */
+	if (pad->flags & MEDIA_PAD_FL_SOURCE) {
+		for (i = 0; i < pad->entity->num_links; ++i) {
+			struct media_link *link = &pad->entity->links[i];
+			struct v4l2_mbus_framefmt remote_format;
+
+			if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+				continue;
+
+			if (link->source == pad &&
+			    link->sink->entity->info.type == MEDIA_ENT_T_V4L2_SUBDEV) {
+				remote_format = format;
+				set_format(link->sink, &remote_format);
+			}
+		}
+	}
+
+	*endp = end;
+	return 0;
+}
+
+int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p)
+{
+	char *end;
+	int ret;
+
+	do {
+		ret = v4l2_subdev_parse_setup_format(media, p, &end);
+		if (ret < 0)
+			return ret;
+
+		p = end + 1;
+	} while (*end == ',');
+
+	return *end ? -EINVAL : 0;
+}
+
+static struct {
+	const char *name;
+	enum v4l2_mbus_pixelcode code;
+} mbus_formats[] = {
+	{ "Y8", V4L2_MBUS_FMT_Y8_1X8},
+	{ "Y10", V4L2_MBUS_FMT_Y10_1X10 },
+	{ "Y12", V4L2_MBUS_FMT_Y12_1X12 },
+	{ "YUYV", V4L2_MBUS_FMT_YUYV8_1X16 },
+	{ "UYVY", V4L2_MBUS_FMT_UYVY8_1X16 },
+	{ "SBGGR8", V4L2_MBUS_FMT_SBGGR8_1X8 },
+	{ "SGBRG8", V4L2_MBUS_FMT_SGBRG8_1X8 },
+	{ "SGRBG8", V4L2_MBUS_FMT_SGRBG8_1X8 },
+	{ "SRGGB8", V4L2_MBUS_FMT_SRGGB8_1X8 },
+	{ "SBGGR10", V4L2_MBUS_FMT_SBGGR10_1X10 },
+	{ "SGBRG10", V4L2_MBUS_FMT_SGBRG10_1X10 },
+	{ "SGRBG10", V4L2_MBUS_FMT_SGRBG10_1X10 },
+	{ "SRGGB10", V4L2_MBUS_FMT_SRGGB10_1X10 },
+	{ "SBGGR10_DPCM8", V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 },
+	{ "SGBRG10_DPCM8", V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 },
+	{ "SGRBG10_DPCM8", V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 },
+	{ "SRGGB10_DPCM8", V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 },
+	{ "SBGGR12", V4L2_MBUS_FMT_SBGGR12_1X12 },
+	{ "SGBRG12", V4L2_MBUS_FMT_SGBRG12_1X12 },
+	{ "SGRBG12", V4L2_MBUS_FMT_SGRBG12_1X12 },
+	{ "SRGGB12", V4L2_MBUS_FMT_SRGGB12_1X12 },
+};
+
+const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
+		if (mbus_formats[i].code == code)
+			return mbus_formats[i].name;
+	}
+
+	return "unknown";
+}
+
+enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
+							 unsigned int length)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
+		if (strncmp(mbus_formats[i].name, string, length) == 0)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(mbus_formats))
+		return (enum v4l2_mbus_pixelcode)-1;
+
+	return mbus_formats[i].code;
+}
+
diff --git a/src/v4l2subdev.h b/src/v4l2subdev.h
index b5772e0..db85491 100644
--- a/src/v4l2subdev.h
+++ b/src/v4l2subdev.h
@@ -158,5 +158,42 @@ int v4l2_subdev_get_frame_interval(struct media_entity *entity,
 int v4l2_subdev_set_frame_interval(struct media_entity *entity,
 	struct v4l2_fract *interval);
 
+/**
+ * @brief Parse a string and apply format, crop and frame interval settings.
+ * @param media - media device.
+ * @param p - input string
+ * @param endp - pointer to string p where parsing ended (return)
+ *
+ * Parse string @a p and apply format, crop and frame interval settings to a
+ * subdev pad specified in @a p. @a endp will be written a pointer where
+ * parsing of @a p ended.
+ *
+ * Format strings are separeted by commas (,).
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p);
+
+/**
+ * @brief Convert media bus pixel code to string.
+ * @param code - input string
+ *
+ * Convert media bus pixel code @a code to a human-readable string.
+ *
+ * @return A pointer to a string on success, NULL on failure.
+ */
+const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code);
+
+/**
+ * @brief Parse string to media bus pixel code.
+ * @param string - input string
+ * @param lenght - length of the string
+ *
+ * Parse human readable string @a string to an media bus pixel code.
+ *
+ * @return media bus pixelcode on success, -1 on failure.
+ */
+enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
+							 unsigned int length);
 #endif
 
-- 
1.7.2.5


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

* [media-ctl PATCH 4/7] libv4l2subdev and libmediactl are not test programs
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
                   ` (2 preceding siblings ...)
  2011-10-07 15:38 ` [media-ctl PATCH 3/7] Move V4L2 subdev format parsing from main.c to subdev.c Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 5/7] Add link to media_device from the media_entity Sakari Ailus
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

Call the libraries libraries rather than test programs.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/mediactl.c   |    2 +-
 src/mediactl.h   |    2 +-
 src/v4l2subdev.c |    2 +-
 src/v4l2subdev.h |    2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/mediactl.c b/src/mediactl.c
index dc5b022..a03c19a 100644
--- a/src/mediactl.c
+++ b/src/mediactl.c
@@ -1,5 +1,5 @@
 /*
- * Media controller test application
+ * Media controller interface library
  *
  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
  *
diff --git a/src/mediactl.h b/src/mediactl.h
index 5627cd7..9ebad9f 100644
--- a/src/mediactl.h
+++ b/src/mediactl.h
@@ -1,5 +1,5 @@
 /*
- * Media controller test application
+ * Media controller interface library
  *
  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
  *
diff --git a/src/v4l2subdev.c b/src/v4l2subdev.c
index 0b4793d..80365e6 100644
--- a/src/v4l2subdev.c
+++ b/src/v4l2subdev.c
@@ -1,5 +1,5 @@
 /*
- * Media controller test application
+ * V4L2 subdev interface library
  *
  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
  *
diff --git a/src/v4l2subdev.h b/src/v4l2subdev.h
index db85491..d9ab692 100644
--- a/src/v4l2subdev.h
+++ b/src/v4l2subdev.h
@@ -1,5 +1,5 @@
 /*
- * Media controller test application
+ * V4L2 subdev interface library
  *
  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
  *
-- 
1.7.2.5


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

* [media-ctl PATCH 5/7] Add link to media_device from the media_entity
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
                   ` (3 preceding siblings ...)
  2011-10-07 15:38 ` [media-ctl PATCH 4/7] libv4l2subdev and libmediactl are not test programs Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 6/7] Add debugging handler Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 7/7] Remove extra verbosity Sakari Ailus
  6 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

This makes it possible to obtain the media device an entity belongs to.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/mediactl.c |    1 +
 src/mediactl.h |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/src/mediactl.c b/src/mediactl.c
index a03c19a..8cc338d 100644
--- a/src/mediactl.c
+++ b/src/mediactl.c
@@ -372,6 +372,7 @@ static int media_enum_entities(struct media_device *media, int verbose)
 		memset(entity, 0, sizeof(*entity));
 		entity->fd = -1;
 		entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
+		entity->media = media;
 
 		ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
 		if (ret < 0) {
diff --git a/src/mediactl.h b/src/mediactl.h
index 9ebad9f..98b47fd 100644
--- a/src/mediactl.h
+++ b/src/mediactl.h
@@ -38,6 +38,7 @@ struct media_pad {
 };
 
 struct media_entity {
+	struct media_device *media;
 	struct media_entity_desc info;
 	struct media_pad *pads;
 	struct media_link *links;
-- 
1.7.2.5


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

* [media-ctl PATCH 6/7] Add debugging handler
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
                   ` (4 preceding siblings ...)
  2011-10-07 15:38 ` [media-ctl PATCH 5/7] Add link to media_device from the media_entity Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  2011-10-07 15:38 ` [media-ctl PATCH 7/7] Remove extra verbosity Sakari Ailus
  6 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

Add debugging handler to media_device that may be used to redirect all debug
formatting to user-supplied function. fprintf will do, and that's what
media-ctl test program will use.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/main.c       |    3 +-
 src/mediactl.c   |  105 +++++++++++++++++++++++++++++++++---------------------
 src/mediactl.h   |   41 +++++++++++++++++++++
 src/v4l2subdev.c |   57 ++++++++++++++++++-----------
 4 files changed, 142 insertions(+), 64 deletions(-)

diff --git a/src/main.c b/src/main.c
index 0d68ff6..40ab13e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -288,7 +288,8 @@ int main(int argc, char **argv)
 		return EXIT_FAILURE;
 
 	/* Open the media device and enumerate entities, pads and links. */
-	media = media_open(media_opts.devname, media_opts.verbose);
+	media = media_open_debug(media_opts.devname, media_opts.verbose,
+				 (void (*)(void *, ...))fprintf, stdout);
 	if (media == NULL)
 		goto out;
 
diff --git a/src/mediactl.c b/src/mediactl.c
index 8cc338d..43d1b6a 100644
--- a/src/mediactl.c
+++ b/src/mediactl.c
@@ -36,12 +36,6 @@
 #include "mediactl.h"
 #include "tools.h"
 
-#ifdef DEBUG
-#define dprintf(...) printf(__VA_ARGS__)
-#else
-#define dprintf(...)
-#endif
-
 struct media_pad *media_entity_remote_source(struct media_pad *pad)
 {
 	unsigned int i;
@@ -113,7 +107,7 @@ int media_setup_link(struct media_device *media,
 	}
 
 	if (i == source->entity->num_links) {
-		dprintf("%s: Link not found\n", __func__);
+		media_dbg(media, "%s: Link not found\n", __func__);
 		return -ENOENT;
 	}
 
@@ -131,8 +125,8 @@ int media_setup_link(struct media_device *media,
 
 	ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
 	if (ret == -1) {
-		dprintf("%s: Unable to setup link (%s)\n", __func__,
-			strerror(errno));
+		media_dbg(media, "%s: Unable to setup link (%s)\n",
+			  __func__, strerror(errno));
 		return -errno;
 	}
 
@@ -202,8 +196,9 @@ static int media_enum_links(struct media_device *media)
 		links.links = malloc(entity->info.links * sizeof(struct media_link_desc));
 
 		if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
-			dprintf("%s: Unable to enumerate pads and links (%s).\n",
-				__func__, strerror(errno));
+			media_dbg(media,
+				  "%s: Unable to enumerate pads and links (%s).\n",
+				  __func__, strerror(errno));
 			free(links.pads);
 			free(links.links);
 			return -errno;
@@ -226,9 +221,12 @@ static int media_enum_links(struct media_device *media)
 			sink = media_get_entity_by_id(media, link->sink.entity);
 
 			if (source == NULL || sink == NULL) {
-				dprintf("WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
-					id, i, link->source.entity, link->source.index,
-					link->sink.entity, link->sink.index);
+				media_dbg(media,
+					  "WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
+					  id, i, link->source.entity,
+					  link->source.index,
+					  link->sink.entity,
+					  link->sink.index);
 				ret = -EINVAL;
 			} else {
 				fwdlink = media_entity_add_link(source);
@@ -284,7 +282,8 @@ static int media_get_devname_udev(struct udev *udev,
 
 	devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
 	if (verbose)
-		printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
+		media_dbg(entity->media, "looking up device: %u:%u\n",
+			  major(devnum), minor(devnum));
 	device = udev_device_new_from_devnum(udev, 'c', devnum);
 	if (device) {
 		p = udev_device_get_devnode(device);
@@ -362,7 +361,7 @@ static int media_enum_entities(struct media_device *media, int verbose)
 
 	ret = media_udev_open(&udev);
 	if (ret < 0)
-		printf("%s: Can't get udev context\n", __func__);
+		media_dbg(media, "Can't get udev context\n");
 
 	for (id = 0, ret = 0; ; id = entity->info.id) {
 		size = (media->entities_count + 1) * sizeof(*media->entities);
@@ -412,48 +411,66 @@ static int media_enum_entities(struct media_device *media, int verbose)
 	return ret;
 }
 
-struct media_device *media_open(const char *name, int verbose)
+static void media_debug_default(void *ptr, ...)
+{
+}
+
+void media_debug_set_handler(struct media_device *media,
+			     void (*debug_handler)(void *, ...),
+			     void *debug_priv)
+{
+	if (debug_handler) {
+		media->debug_handler = debug_handler;
+		media->debug_priv = debug_priv;
+	} else {
+		media->debug_handler = media_debug_default;
+		media->debug_priv = NULL;
+	}
+}
+
+struct media_device *media_open_debug(
+	const char *name, int verbose, void (*debug_handler)(void *, ...),
+	void *debug_priv)
 {
 	struct media_device *media;
 	int ret;
 
 	media = calloc(1, sizeof(*media));
-	if (media == NULL) {
-		dprintf("%s: unable to allocate memory\n", __func__);
+	if (media == NULL)
 		return NULL;
-	}
 
-	if (verbose)
-		dprintf("Opening media device %s\n", name);
+	media_debug_set_handler(media, debug_handler, debug_priv);
+
+	media_dbg(media, "Opening media device %s\n", name);
 
 	media->fd = open(name, O_RDWR);
 	if (media->fd < 0) {
 		media_close(media);
-		dprintf("%s: Can't open media device %s\n", __func__, name);
+		media_dbg(media, "%s: Can't open media device %s\n",
+			  __func__, name);
 		return NULL;
 	}
 
-	if (verbose)
-		dprintf("Enumerating entities\n");
+	media_dbg(media, "Enumerating entities\n");
 
 	ret = media_enum_entities(media, verbose);
 
 	if (ret < 0) {
-		dprintf("%s: Unable to enumerate entities for device %s (%s)\n",
-			__func__, name, strerror(-ret));
+		media_dbg(media,
+			  "%s: Unable to enumerate entities for device %s (%s)\n",
+			  __func__, name, strerror(-ret));
 		media_close(media);
 		return NULL;
 	}
 
-	if (verbose) {
-		dprintf("Found %u entities\n", media->entities_count);
-		dprintf("Enumerating pads and links\n");
-	}
+	media_dbg(media, "Found %u entities\n", media->entities_count);
+	media_dbg(media, "Enumerating pads and links\n");
 
 	ret = media_enum_links(media);
 	if (ret < 0) {
-		dprintf("%s: Unable to enumerate pads and linksfor device %s\n",
-			__func__, name);
+		media_dbg(media,
+			  "%s: Unable to enumerate pads and linksfor device %s\n",
+			  __func__, name);
 		media_close(media);
 		return NULL;
 	}
@@ -461,6 +478,11 @@ struct media_device *media_open(const char *name, int verbose)
 	return media;
 }
 
+struct media_device *media_open(const char *name, int verbose)
+{
+	return media_open_debug(name, verbose, NULL, NULL);
+}
+
 void media_close(struct media_device *media)
 {
 	unsigned int i;
@@ -567,30 +589,32 @@ int media_parse_setup_link(struct media_device *media,
 
 	link = media_parse_link(media, p, &end);
 	if (link == NULL) {
-		dprintf("Unable to parse link\n");
+		media_dbg(media,
+			  "%s: Unable to parse link\n", __func__);
 		return -EINVAL;
 	}
 
 	p = end;
 	if (*p++ != '[') {
-		dprintf("Unable to parse link flags\n");
+		media_dbg(media, "Unable to parse link flags\n");
 		return -EINVAL;
 	}
 
 	flags = strtoul(p, &end, 10);
 	for (p = end; isspace(*p); p++);
 	if (*p++ != ']') {
-		dprintf("Unable to parse link flags\n");
+		media_dbg(media, "Unable to parse link flags\n");
 		return -EINVAL;
 	}
 
 	for (; isspace(*p); p++);
 	*endp = (char *)p;
 
-	dprintf("Setting up link %u:%u -> %u:%u [%u]\n",
-		link->source->entity->info.id, link->source->index,
-		link->sink->entity->info.id, link->sink->index,
-		flags);
+	media_dbg(media,
+		  "Setting up link %u:%u -> %u:%u [%u]\n",
+		  link->source->entity->info.id, link->source->index,
+		  link->sink->entity->info.id, link->sink->index,
+		  flags);
 
 	return media_setup_link(media, link->source, link->sink, flags);
 }
@@ -610,4 +634,3 @@ int media_parse_setup_links(struct media_device *media, const char *p)
 
 	return *end ? -EINVAL : 0;
 }
-
diff --git a/src/mediactl.h b/src/mediactl.h
index 98b47fd..c6bf723 100644
--- a/src/mediactl.h
+++ b/src/mediactl.h
@@ -54,9 +54,50 @@ struct media_device {
 	int fd;
 	struct media_entity *entities;
 	unsigned int entities_count;
+	void (*debug_handler)(void *, ...);
+	void *debug_priv;
 	__u32 padding[6];
 };
 
+#define media_dbg(media, ...) \
+	(media)->debug_handler((media)->debug_priv, __VA_ARGS__)
+
+/**
+ * @brief Set a handler for debug messages.
+ * @param media - device instance.
+ * @param debug_handler - debug message handler
+ * @param debug_priv - first argument to debug message handler
+ *
+ * Set a handler for debug messages that will be called whenever
+ * debugging information is to be printed. The handler expects an
+ * fprintf-like function.
+ */
+void media_debug_set_handler(
+	struct media_device *media, void (*debug_handler)(void *, ...),
+	void *debug_priv);
+
+/**
+ * @brief Open a media device with debugging enabled.
+ * @param name - name (including path) of the device node.
+ * @param verbose - whether to print verbose information on the standard output.
+ * @param debug_handler - debug message handler
+ * @param debug_priv - first argument to debug message handler
+ *
+ * Open the media device referenced by @a name and enumerate entities, pads and
+ * links.
+ *
+ * Calling media_open_debug() instead of media_open() is equivalent to
+ * media_open() and media_debug_set_handler() except that debugging is
+ * also enabled during media_open().
+ *
+ * @return A pointer to a newly allocated media_device structure instance on
+ * success and NULL on failure. The returned pointer must be freed with
+ * media_close when the device isn't needed anymore.
+ */
+struct media_device *media_open_debug(
+	const char *name, int verbose, void (*debug_handler)(void *, ...),
+	void *debug_priv);
+
 /**
  * @brief Open a media device.
  * @param name - name (including path) of the device node.
diff --git a/src/v4l2subdev.c b/src/v4l2subdev.c
index 80365e6..5759948 100644
--- a/src/v4l2subdev.c
+++ b/src/v4l2subdev.c
@@ -40,8 +40,9 @@ int v4l2_subdev_open(struct media_entity *entity)
 
 	entity->fd = open(entity->devname, O_RDWR);
 	if (entity->fd == -1) {
-		printf("%s: Failed to open subdev device node %s\n", __func__,
-			entity->devname);
+		media_dbg(entity->media,
+			  "%s: Failed to open subdev device node %s\n", __func__,
+			  entity->devname);
 		return -errno;
 	}
 
@@ -329,21 +330,25 @@ static int set_format(struct media_pad *pad,
 	if (format->width == 0 || format->height == 0)
 		return 0;
 
-	printf("Setting up format %s %ux%u on pad %s/%u\n",
-	       v4l2_subdev_pixelcode_to_string(format->code),
-	       format->width, format->height,
-	       pad->entity->info.name, pad->index);
+	media_dbg(pad->entity->media,
+		  "Setting up format %s %ux%u on pad %s/%u\n",
+		  v4l2_subdev_pixelcode_to_string(format->code),
+		  format->width, format->height,
+		  pad->entity->info.name, pad->index);
 
 	ret = v4l2_subdev_set_format(pad->entity, format, pad->index,
 				     V4L2_SUBDEV_FORMAT_ACTIVE);
 	if (ret < 0) {
-		printf("Unable to set format: %s (%d)\n", strerror(-ret), ret);
+		media_dbg(pad->entity->media,
+			  "Unable to set format: %s (%d)\n",
+			  strerror(-ret), ret);
 		return ret;
 	}
 
-	printf("Format set: %s %ux%u\n",
-	       v4l2_subdev_pixelcode_to_string(format->code),
-	       format->width, format->height);
+	media_dbg(pad->entity->media,
+		  "Format set: %s %ux%u\n",
+		  v4l2_subdev_pixelcode_to_string(format->code),
+		  format->width, format->height);
 
 	return 0;
 }
@@ -355,19 +360,23 @@ static int set_crop(struct media_pad *pad, struct v4l2_rect *crop)
 	if (crop->left == -1 || crop->top == -1)
 		return 0;
 
-	printf("Setting up crop rectangle (%u,%u)/%ux%u on pad %s/%u\n",
-		crop->left, crop->top, crop->width, crop->height,
-		pad->entity->info.name, pad->index);
+	media_dbg(pad->entity->media,
+		  "Setting up crop rectangle (%u,%u)/%ux%u on pad %s/%u\n",
+		  crop->left, crop->top, crop->width, crop->height,
+		  pad->entity->info.name, pad->index);
 
 	ret = v4l2_subdev_set_crop(pad->entity, crop, pad->index,
 				   V4L2_SUBDEV_FORMAT_ACTIVE);
 	if (ret < 0) {
-		printf("Unable to set crop rectangle: %s (%d)\n", strerror(-ret), ret);
+		media_dbg(pad->entity->media,
+			  "Unable to set crop rectangle: %s (%d)\n",
+			  strerror(-ret), ret);
 		return ret;
 	}
 
-	printf("Crop rectangle set: (%u,%u)/%ux%u\n",
-		crop->left, crop->top, crop->width, crop->height);
+	media_dbg(pad->entity->media,
+		  "Crop rectangle set: (%u,%u)/%ux%u\n",
+		  crop->left, crop->top, crop->width, crop->height);
 
 	return 0;
 }
@@ -380,17 +389,21 @@ static int set_frame_interval(struct media_entity *entity,
 	if (interval->numerator == 0)
 		return 0;
 
-	printf("Setting up frame interval %u/%u on entity %s\n",
-		interval->numerator, interval->denominator, entity->info.name);
+	media_dbg(entity->media,
+		  "Setting up frame interval %u/%u on entity %s\n",
+		  interval->numerator, interval->denominator,
+		  entity->info.name);
 
 	ret = v4l2_subdev_set_frame_interval(entity, interval);
 	if (ret < 0) {
-		printf("Unable to set frame interval: %s (%d)", strerror(-ret), ret);
+		media_dbg(entity->media,
+			  "Unable to set frame interval: %s (%d)",
+			  strerror(-ret), ret);
 		return ret;
 	}
 
-	printf("Frame interval set: %u/%u\n",
-		interval->numerator, interval->denominator);
+	media_dbg(entity->media, "Frame interval set: %u/%u\n",
+		  interval->numerator, interval->denominator);
 
 	return 0;
 }
@@ -410,7 +423,7 @@ static int v4l2_subdev_parse_setup_format(struct media_device *media,
 	pad = v4l2_subdev_parse_pad_format(media, &format, &crop, &interval,
 					   p, &end);
 	if (pad == NULL) {
-		printf("Unable to parse format\n");
+		media_dbg(media, "Unable to parse format\n");
 		return -EINVAL;
 	}
 
-- 
1.7.2.5


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

* [media-ctl PATCH 7/7] Remove extra verbosity
  2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
                   ` (5 preceding siblings ...)
  2011-10-07 15:38 ` [media-ctl PATCH 6/7] Add debugging handler Sakari Ailus
@ 2011-10-07 15:38 ` Sakari Ailus
  6 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-07 15:38 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart

Remove extra verbosity by default; "-v" option brings back what used to be
there. The error messages are now being printed by main.c with the possibly
helpful error code attached.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 src/main.c     |   48 ++++++++++++++++++++++++++++++++++++++----------
 src/mediactl.c |   21 ++++++++++-----------
 src/mediactl.h |    6 ++----
 3 files changed, 50 insertions(+), 25 deletions(-)

diff --git a/src/main.c b/src/main.c
index 40ab13e..57bbc16 100644
--- a/src/main.c
+++ b/src/main.c
@@ -288,10 +288,16 @@ int main(int argc, char **argv)
 		return EXIT_FAILURE;
 
 	/* Open the media device and enumerate entities, pads and links. */
-	media = media_open_debug(media_opts.devname, media_opts.verbose,
-				 (void (*)(void *, ...))fprintf, stdout);
-	if (media == NULL)
+	if (media_opts.verbose)
+		media = media_open_debug(
+			media_opts.devname,
+			(void (*)(void *, ...))fprintf, stdout);
+	else
+		media = media_open(media_opts.devname);
+	if (media == NULL) {
+		printf("Failed to open %s\n", media_opts.devname);
 		goto out;
+	}
 
 	if (media_opts.entity) {
 		struct media_entity *entity;
@@ -326,15 +332,34 @@ int main(int argc, char **argv)
 	}
 
 	if (media_opts.reset) {
-		printf("Resetting all links to inactive\n");
-		media_reset_links(media);
+		if (media_opts.verbose)
+			printf("Resetting all links to inactive\n");
+		ret = media_reset_links(media);
+		if (ret) {
+			printf("Unable to reset links: %s (%d)\n",
+			       strerror(-ret), -ret);
+			goto out;
+		}
 	}
 
-	if (media_opts.links)
-		media_parse_setup_links(media, media_opts.links);
+	if (media_opts.links) {
+		ret = media_parse_setup_links(media, media_opts.links);
+		if (ret) {
+			printf("Unable to parse link: %s (%d)\n",
+			       strerror(-ret), -ret);
+			goto out;
+		}
+	}
 
-	if (media_opts.formats)
-		v4l2_subdev_parse_setup_formats(media, media_opts.formats);
+	if (media_opts.formats) {
+		ret = v4l2_subdev_parse_setup_formats(media,
+						      media_opts.formats);
+		if (ret) {
+			printf("Unable to parse format: %s (%d)\n",
+			       strerror(-ret), -ret);
+			goto out;
+		}
+	}
 
 	if (media_opts.interactive) {
 		while (1) {
@@ -348,7 +373,10 @@ int main(int argc, char **argv)
 			if (buffer[0] == '\n')
 				break;
 
-			media_parse_setup_link(media, buffer, &end);
+			ret = media_parse_setup_link(media, buffer, &end);
+			if (ret)
+				printf("Unable to parse link: %s (%d)\n",
+				       strerror(-ret), -ret);
 		}
 	}
 
diff --git a/src/mediactl.c b/src/mediactl.c
index 43d1b6a..b9c2a10 100644
--- a/src/mediactl.c
+++ b/src/mediactl.c
@@ -270,7 +270,7 @@ static inline void media_udev_close(struct udev *udev)
 }
 
 static int media_get_devname_udev(struct udev *udev,
-		struct media_entity *entity, int verbose)
+		struct media_entity *entity)
 {
 	struct udev_device *device;
 	dev_t devnum;
@@ -281,9 +281,8 @@ static int media_get_devname_udev(struct udev *udev,
 		return -EINVAL;
 
 	devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
-	if (verbose)
-		media_dbg(entity->media, "looking up device: %u:%u\n",
-			  major(devnum), minor(devnum));
+	media_dbg(entity->media, "looking up device: %u:%u\n",
+		  major(devnum), minor(devnum));
 	device = udev_device_new_from_devnum(udev, 'c', devnum);
 	if (device) {
 		p = udev_device_get_devnode(device);
@@ -308,7 +307,7 @@ static inline int media_udev_open(struct udev **udev) { return 0; }
 static inline void media_udev_close(struct udev *udev) { }
 
 static inline int media_get_devname_udev(struct udev *udev,
-		struct media_entity *entity, int verbose)
+		struct media_entity *entity)
 {
 	return -ENOTSUP;
 }
@@ -351,7 +350,7 @@ static int media_get_devname_sysfs(struct media_entity *entity)
 	return 0;
 }
 
-static int media_enum_entities(struct media_device *media, int verbose)
+static int media_enum_entities(struct media_device *media)
 {
 	struct media_entity *entity;
 	struct udev *udev;
@@ -400,7 +399,7 @@ static int media_enum_entities(struct media_device *media, int verbose)
 			continue;
 
 		/* Try to get the device name via udev */
-		if (!media_get_devname_udev(udev, entity, verbose))
+		if (!media_get_devname_udev(udev, entity))
 			continue;
 
 		/* Fall back to get the device name via sysfs */
@@ -429,7 +428,7 @@ void media_debug_set_handler(struct media_device *media,
 }
 
 struct media_device *media_open_debug(
-	const char *name, int verbose, void (*debug_handler)(void *, ...),
+	const char *name, void (*debug_handler)(void *, ...),
 	void *debug_priv)
 {
 	struct media_device *media;
@@ -453,7 +452,7 @@ struct media_device *media_open_debug(
 
 	media_dbg(media, "Enumerating entities\n");
 
-	ret = media_enum_entities(media, verbose);
+	ret = media_enum_entities(media);
 
 	if (ret < 0) {
 		media_dbg(media,
@@ -478,9 +477,9 @@ struct media_device *media_open_debug(
 	return media;
 }
 
-struct media_device *media_open(const char *name, int verbose)
+struct media_device *media_open(const char *name)
 {
-	return media_open_debug(name, verbose, NULL, NULL);
+	return media_open_debug(name, NULL, NULL);
 }
 
 void media_close(struct media_device *media)
diff --git a/src/mediactl.h b/src/mediactl.h
index c6bf723..5fdd078 100644
--- a/src/mediactl.h
+++ b/src/mediactl.h
@@ -79,7 +79,6 @@ void media_debug_set_handler(
 /**
  * @brief Open a media device with debugging enabled.
  * @param name - name (including path) of the device node.
- * @param verbose - whether to print verbose information on the standard output.
  * @param debug_handler - debug message handler
  * @param debug_priv - first argument to debug message handler
  *
@@ -95,13 +94,12 @@ void media_debug_set_handler(
  * media_close when the device isn't needed anymore.
  */
 struct media_device *media_open_debug(
-	const char *name, int verbose, void (*debug_handler)(void *, ...),
+	const char *name, void (*debug_handler)(void *, ...),
 	void *debug_priv);
 
 /**
  * @brief Open a media device.
  * @param name - name (including path) of the device node.
- * @param verbose - whether to print verbose information on the standard output.
  *
  * Open the media device referenced by @a name and enumerate entities, pads and
  * links.
@@ -110,7 +108,7 @@ struct media_device *media_open_debug(
  * success and NULL on failure. The returned pointer must be freed with
  * media_close when the device isn't needed anymore.
  */
-struct media_device *media_open(const char *name, int verbose);
+struct media_device *media_open(const char *name);
 
 /**
  * @brief Close a media device.
-- 
1.7.2.5


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

* Re: [media-ctl PATCH 1/7] Rename files to match the names of the libraries
  2011-10-07 15:38 ` [media-ctl PATCH 1/7] Rename files to match the names of the libraries Sakari Ailus
@ 2011-10-08 11:53   ` Laurent Pinchart
  2011-10-08 12:58     ` Sakari Ailus
  0 siblings, 1 reply; 10+ messages in thread
From: Laurent Pinchart @ 2011-10-08 11:53 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media

Applied :-)

-- 
Regards,

Laurent Pinchart

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

* Re: [media-ctl PATCH 1/7] Rename files to match the names of the libraries
  2011-10-08 11:53   ` Laurent Pinchart
@ 2011-10-08 12:58     ` Sakari Ailus
  0 siblings, 0 replies; 10+ messages in thread
From: Sakari Ailus @ 2011-10-08 12:58 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media

On Sat, Oct 08, 2011 at 01:53:07PM +0200, Laurent Pinchart wrote:
> Applied :-)

Thanks!

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

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

end of thread, other threads:[~2011-10-08 12:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-07 15:34 [media-ctl PATCH 0/7] Move functionality to libraries, debug changes Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 1/7] Rename files to match the names of the libraries Sakari Ailus
2011-10-08 11:53   ` Laurent Pinchart
2011-10-08 12:58     ` Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 2/7] Move link parsing from main.c to media.c, making it part of libmediactl Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 3/7] Move V4L2 subdev format parsing from main.c to subdev.c Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 4/7] libv4l2subdev and libmediactl are not test programs Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 5/7] Add link to media_device from the media_entity Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 6/7] Add debugging handler Sakari Ailus
2011-10-07 15:38 ` [media-ctl PATCH 7/7] Remove extra verbosity Sakari Ailus

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