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

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

 



Hi Sakari,

On 11/24/2016 01:17 PM, Sakari Ailus wrote:
Hi Jacek,

Thanks for the patchset.

On Wed, Oct 12, 2016 at 04:35:19PM +0200, Jacek Anaszewski wrote:
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.

Doesn't this work with video nodes as well? That's what you seem to be using
it for later on. And I think that's actually more useful.

The existing implementation uses udev to look up devices. Could you use
libudev device enumeration API to find the media devices, and fall back to
sysfs if udev doesn't work? There seems to be a reasonable-looking example
here:

<URL:http://stackoverflow.com/questions/25361042/how-to-list-usb-mass-storage-devices-programatically-using-libudev-in-linux>

Actually I am calling media_get_devname_udev() at first and falling back
to sysfs similarly as it is accomplished in media_enum_entities().
Is there any specific reason for which I should use libudev device
enumeration API in media_device_new_by_subdev_fd()?

Best regards,
Jacek Anaszewski


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;
 }

+

Unrelated change.

 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))

Why 4? And isn't entry->d_name nul-terminated, so you could use strcmp()?

+			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);

This would be better split on two lines.

+
+		/* 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;
+			}
+		}

What if you exit the loop without finding the entity you were looking for?

+
+		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));

This seems risky. How does the caller know the maximum size? I'd simply
allocate the string, and document the caller is responsible for releasing
it.

+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);

I'd drop the "subdev_" part as both V4L2 device nodes and sub-devices work.

If you wish to keep this V4L2 specific, I suggest ...by_v4l2_fd().

+
+/**
  * @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.
  *

--
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