[PATCH v4l-utils v7 4/7] mediactl: Add media_device creation helpers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add helper functions that allow for easy instantiation of media_device
object basing on whether the media device contains v4l2 subdev with
given file descriptor.

Signed-off-by: Jacek Anaszewski <j.anaszewski@xxxxxxxxxxx>
Acked-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
 utils/media-ctl/libmediactl.c | 131 +++++++++++++++++++++++++++++++++++++++++-
 utils/media-ctl/mediactl.h    |  27 +++++++++
 2 files changed, 156 insertions(+), 2 deletions(-)

diff --git a/utils/media-ctl/libmediactl.c b/utils/media-ctl/libmediactl.c
index 155b65f..d347a40 100644
--- a/utils/media-ctl/libmediactl.c
+++ b/utils/media-ctl/libmediactl.c
@@ -27,6 +27,7 @@
 #include <sys/sysmacros.h>
 
 #include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
@@ -440,8 +441,9 @@ static int media_get_devname_udev(struct udev *udev,
 		return -EINVAL;
 
 	devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
-	media_dbg(entity->media, "looking up device: %u:%u\n",
-		  major(devnum), minor(devnum));
+	if (entity->media)
+		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);
@@ -523,6 +525,7 @@ static int media_get_devname_sysfs(struct media_entity *entity)
 	return 0;
 }
 
+
 static int media_enum_entities(struct media_device *media)
 {
 	struct media_entity *entity;
@@ -707,6 +710,92 @@ struct media_device *media_device_new(const char *devnode)
 	return media;
 }
 
+struct media_device *media_device_new_by_subdev_fd(int fd, struct media_entity **fd_entity)
+{
+	char video_devname[32], device_dir_path[256], media_dev_path[256], media_major_minor[10];
+	struct media_device *media = NULL;
+	struct dirent *entry;
+	struct media_entity tmp_entity;
+	DIR *device_dir;
+	struct udev *udev;
+	char *p;
+	int ret, i;
+
+	if (fd_entity == NULL)
+		return NULL;
+
+	ret = media_get_devname_by_fd(fd, video_devname);
+	if (ret < 0)
+		return NULL;
+
+	p = strrchr(video_devname, '/');
+	if (p == NULL)
+		return NULL;
+
+	ret = media_udev_open(&udev);
+	if (ret < 0)
+		return NULL;
+
+	sprintf(device_dir_path, "/sys/class/video4linux/%s/device/", p + 1);
+
+	device_dir = opendir(device_dir_path);
+	if (device_dir == NULL)
+		return NULL;
+
+	while ((entry = readdir(device_dir))) {
+		if (strncmp(entry->d_name, "media", 4))
+			continue;
+
+		sprintf(media_dev_path, "%s%s/dev", device_dir_path, entry->d_name);
+
+		fd = open(media_dev_path, O_RDONLY);
+		if (fd < 0)
+			continue;
+
+		ret = read(fd, media_major_minor, sizeof(media_major_minor));
+		if (ret < 0)
+			continue;
+
+		sscanf(media_major_minor, "%d:%d", &tmp_entity.info.dev.major, &tmp_entity.info.dev.minor);
+
+		/* Try to get the device name via udev */
+		if (media_get_devname_udev(udev, &tmp_entity)) {
+			/* Fall back to get the device name via sysfs */
+			if (media_get_devname_sysfs(&tmp_entity))
+				continue;
+		}
+
+		media = media_device_new(tmp_entity.devname);
+		if (media == NULL)
+			continue;
+
+		ret = media_device_enumerate(media);
+		if (ret < 0) {
+			media_dbg(media, "Failed to enumerate %s (%d)\n",
+				  tmp_entity.devname, ret);
+			media_device_unref(media);
+			media = NULL;
+			continue;
+		}
+
+		/* Get the entity associated with given fd */
+		for (i = 0; i < media->entities_count; i++) {
+			struct media_entity *entity = &media->entities[i];
+
+			if (!strcmp(entity->devname, video_devname)) {
+				*fd_entity = &media->entities[i];
+				break;
+			}
+		}
+
+		break;
+	}
+
+	media_udev_close(udev);
+
+	return media;
+}
+
 struct media_device *media_device_new_emulated(struct media_device_info *info)
 {
 	struct media_device *media;
@@ -748,6 +837,44 @@ void media_device_unref(struct media_device *media)
 	free(media);
 }
 
+int media_get_devname_by_fd(int fd, char *node_name)
+{
+	struct udev *udev;
+	struct media_entity tmp_entity;
+	struct stat stat;
+	int ret, ret_udev;
+
+	if (node_name == NULL)
+		return -EINVAL;
+
+	ret = fstat(fd, &stat);
+	if (ret < 0)
+		return -errno;
+
+	tmp_entity.info.v4l.major = MAJOR(stat.st_rdev);
+	tmp_entity.info.v4l.minor = MINOR(stat.st_rdev);
+
+	ret_udev = media_udev_open(&udev);
+	if (ret_udev < 0)
+		printf("Can't get udev context\n");
+
+	/* Try to get the device name via udev */
+	ret = media_get_devname_udev(udev, &tmp_entity);
+	if (!ret)
+		goto out;
+
+	ret = media_get_devname_sysfs(&tmp_entity);
+	if (ret < 0)
+		goto err_get_devname;
+
+out:
+	strncpy(node_name, tmp_entity.devname, sizeof(tmp_entity.devname));
+err_get_devname:
+	if (!ret_udev)
+		media_udev_close(udev);
+	return ret;
+}
+
 int media_device_add_entity(struct media_device *media,
 			    const struct media_entity_desc *desc,
 			    const char *devnode)
diff --git a/utils/media-ctl/mediactl.h b/utils/media-ctl/mediactl.h
index b1f33cd..580a25a 100644
--- a/utils/media-ctl/mediactl.h
+++ b/utils/media-ctl/mediactl.h
@@ -76,6 +76,21 @@ struct media_device *media_device_new(const char *devnode);
 struct media_device *media_device_new_emulated(struct media_device_info *info);
 
 /**
+ * @brief Create a new media device contatning entity associated with v4l2 subdev fd.
+ * @param fd - file descriptor of a v4l2 subdev.
+ * @param fd_entity - media entity associated with the v4l2 subdev.
+ *
+ * Create a representation of the media device referenced by the v4l2-subdev.
+ * The media device instance is initialized with enumerated entities and links.
+ *
+ * Media devices are reference-counted, see media_device_ref() and
+ * media_device_unref() for more information.
+ *
+ * @return A pointer to the new media device or NULL if error occurred.
+ */
+struct media_device *media_device_new_by_subdev_fd(int fd, struct media_entity **fd_entity);
+
+/**
  * @brief Take a reference to the device.
  * @param media - device instance.
  *
@@ -231,6 +246,18 @@ const struct media_link *media_entity_get_link(struct media_entity *entity,
 const char *media_entity_get_devname(struct media_entity *entity);
 
 /**
+ * @brief Get the device node name by its file descriptor
+ * @param fd - file descriptor of a device.
+ * @param node_name - output device node name string.
+ *
+ * This function returns the full path and name to the device node corresponding
+ * to the given file descriptor.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int media_get_devname_by_fd(int fd, char *node_name);
+
+/**
  * @brief Get the type of an entity.
  * @param entity - the entity.
  *
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux