summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2016-05-23 00:33:58 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2016-05-23 01:12:34 +0300
commitb3ec4d492df50abe1d5bf1355da3e9d5f3b3919f (patch)
tree9faa8d8cbd246500b36b324326031c1b4ed43936
parent36b54dfbc7c3a5cd85e3f37576e91940158723e8 (diff)
Import media-enum as 3rd party code
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--3rdparty/media-enum/.gitignore2
-rw-r--r--3rdparty/media-enum/Makefile22
-rw-r--r--3rdparty/media-enum/include/media-enumerate.h114
-rw-r--r--3rdparty/media-enum/media-enumerate.c646
4 files changed, 784 insertions, 0 deletions
diff --git a/3rdparty/media-enum/.gitignore b/3rdparty/media-enum/.gitignore
new file mode 100644
index 0000000..9eca6c8
--- /dev/null
+++ b/3rdparty/media-enum/.gitignore
@@ -0,0 +1,2 @@
+*.a
+*.o
diff --git a/3rdparty/media-enum/Makefile b/3rdparty/media-enum/Makefile
new file mode 100644
index 0000000..a79744b
--- /dev/null
+++ b/3rdparty/media-enum/Makefile
@@ -0,0 +1,22 @@
+AR := $(CROSS_COMPILE)ar
+CC := $(CROSS_COMPILE)gcc
+CFLAGS := -O2 -W -Wall -Wno-unused-parameter -I$(KDIR)/usr/include -I$(topdir)/3rdparty/media-ctl/include -Iinclude/ -I. -fPIC
+LDFLAGS :=
+
+OBJECTS := media-enumerate.o
+
+TARGET := libmediaenum.a
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(AR) -r $@ $^
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+ -$(RM) *.o
+ -$(RM) $(TARGET)
+
+install:
diff --git a/3rdparty/media-enum/include/media-enumerate.h b/3rdparty/media-enum/include/media-enumerate.h
new file mode 100644
index 0000000..ecd6b3d
--- /dev/null
+++ b/3rdparty/media-enum/include/media-enumerate.h
@@ -0,0 +1,114 @@
+/*
+ * Media device discovery library
+ *
+ * Copyright (C) 2012 Ideas on board SPRL
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MEDIA_ENUMERATE_H__
+#define __MEDIA_ENUMERATE_H__
+
+struct media_enumerate;
+
+/**
+ * @brief Create a new media device enumeration context.
+ *
+ * Media device enumeration contexts are used to enumerate media devices. They
+ * store all context information required by enumeration and cache the
+ * enumeration results for later access. Enumeration itself is performed by the
+ * separate media_enumerate_scan() function.
+ *
+ * Enumeration contexts are reference-counted, see media_enumerate_ref() and
+ * media_enumerate_unref() for more information.
+ *
+ * @return A pointer to the new media device enumeration context or NULL if
+ * memory cannot be allocated.
+ */
+struct media_enumerate *media_enumerate_new(void);
+
+/**
+ * @brief Take a reference to the enumeration context.
+ * @param media_enum - enumeration context instance.
+ *
+ * Media device enumeration contexts are reference-counted. Taking a reference
+ * to an enumeration context prevents it and all the information it stores from
+ * being freed until all references are released. The reference count is
+ * initialized to 1 when the context is created.
+ *
+ * @return A pointer to @a media.
+ */
+struct media_enumerate *media_enumerate_ref(struct media_enumerate *media_enum);
+
+/**
+ * @brief Release a reference to the enumeration context.
+ * @param media_enum - enumeration context instance.
+ *
+ * Release a reference to the enumeration context. When the reference count
+ * reaches 0 this function frees the context, including all information it
+ * stores.
+ */
+void media_enumerate_unref(struct media_enumerate *media_enum);
+
+/**
+ * @brief Enumerate media devices in the system
+ * @param media_enum - enumeration context instance.
+ *
+ * Scan the system to locate all available media devices. This function must be
+ * called once and only once before accessing the list of enumerated devices.
+ *
+ * Devices are enumerated using libudev if available or through sysfs otherwise.
+ * sysfs-based enumeration requires device nodes to use the standard Linux
+ * device names and be numbered by the device sysfs device number. For instance
+ * the device node corresponding to /sys/class/video4linux/video0 must be named
+ * /dev/video0. libudev-based enumeration doesn't have this restriction.
+ *
+ * Media devices are enumerated by scanning media controller, V4L and ALSA
+ * kernel devices, in that order. Emulated media devices are created as needed
+ * for V4L devices that are not part of a media controller based device. ALSA
+ * devices without a corresponding media controller or V4L devices are skipped.
+ *
+ * @return Zero on success or a negative error code on failure.
+ */
+int media_enumerate_scan(struct media_enumerate *media_enum);
+
+/**
+ * @brief Get the number of media devices found during enumeration
+ * @param media_enum - enumeration context instance.
+ *
+ * This function returns the total number of media devices found in the system
+ * during enumeration. If media devices haven't been enumerated yet it will
+ * return 0.
+ *
+ * @return The number of media devices found in the system
+ */
+unsigned int media_enumerate_get_devices_count(struct media_enumerate *media_enum);
+
+/**
+ * @brief Get the media devices
+ * @param media_enum - enumeration context instance.
+ *
+ * This function returns a pointer to the array of enumerated media devices. If
+ * If media devices haven't been enumerated yet it will return NULL.
+ *
+ * The array of media devices is owned by the enumeration context and will be
+ * freed when the enumeration context is destroyed.
+ *
+ * @return A pointer to an array of media devices
+ */
+struct media_device **media_enumerate_get_devices(struct media_enumerate *media_enum);
+
+#endif /* __MEDIA_ENUMERATE_H__ */
diff --git a/3rdparty/media-enum/media-enumerate.c b/3rdparty/media-enum/media-enumerate.c
new file mode 100644
index 0000000..0db4cdd
--- /dev/null
+++ b/3rdparty/media-enum/media-enumerate.c
@@ -0,0 +1,646 @@
+/*
+ * Media device discovery library
+ *
+ * Copyright (C) 2012 Ideas on board SPRL
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define HAVE_LIBUDEV
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/videodev2.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef HAVE_LIBUDEV
+#include <libudev.h>
+#endif
+
+#include "mediactl.h"
+
+#include "media-enumerate.h"
+
+struct media_enumerate {
+ unsigned int refcount;
+
+ char **syspaths;
+ struct media_device **devices;
+ unsigned int devices_count;
+ unsigned int devices_max;
+
+#ifdef HAVE_LIBUDEV
+ struct udev *udev;
+#endif
+};
+
+static int media_enumerate_add_device(struct media_enumerate *media_enum,
+ const char *syspath,
+ struct media_device *media)
+{
+ if (media_enum->devices_count == media_enum->devices_max) {
+ struct media_device **devices;
+ char **syspaths;
+ unsigned int count;
+
+ count = media_enum->devices_max * 2;
+ count = count < 16 ? 16 : count;
+
+ devices = realloc(media_enum->devices, count * sizeof *devices);
+ if (devices == NULL)
+ return -ENOMEM;
+ media_enum->devices = devices;
+
+ syspaths = realloc(media_enum->syspaths, count * sizeof *syspaths);
+ if (syspaths == NULL)
+ return -ENOMEM;
+ media_enum->syspaths = syspaths;
+
+ media_enum->devices_max = count;
+ }
+
+ media_enum->devices[media_enum->devices_count] = media;
+ media_enum->syspaths[media_enum->devices_count] = strdup(syspath);
+ media_enum->devices_count++;
+
+ return 0;
+}
+
+typedef int(*media_enumerate_callback)(struct media_enumerate *, const char *,
+ const char *, dev_t);
+
+enum media_enumerate_bus_type {
+ BUS_TYPE_UNKNOWN,
+ BUS_TYPE_PCI,
+ BUS_TYPE_USB,
+};
+
+static enum media_enumerate_bus_type
+media_enumerate_get_physical_bus(const char *syspath)
+{
+ char *modalias;
+ char type[4];
+ int ret;
+ int fd;
+
+ modalias = malloc(strlen(syspath) + 10);
+ if (modalias == NULL)
+ return BUS_TYPE_UNKNOWN;
+
+ sprintf(modalias, "%s/modalias", syspath);
+ fd = open(modalias, O_RDONLY);
+ free(modalias);
+
+ if (fd == -1)
+ return BUS_TYPE_UNKNOWN;
+
+ ret = read(fd, type, 3);
+ close(fd);
+
+ if (ret != 3)
+ return BUS_TYPE_UNKNOWN;
+
+ type[3] = '\0';
+
+ if (!strcmp(type, "pci"))
+ return BUS_TYPE_PCI;
+ else if (!strcmp(type, "usb"))
+ return BUS_TYPE_USB;
+ else
+ return BUS_TYPE_UNKNOWN;
+}
+
+static char *media_enumerate_get_physical_parent(const char *syspath)
+{
+ enum media_enumerate_bus_type bus_type;
+ char *phys;
+ char *p;
+
+ phys = realpath(syspath, NULL);
+ if (phys == NULL)
+ return NULL;
+
+ p = strstr(phys, "media");
+ if (p)
+ *(p - 1) = '\0';
+ p = strstr(phys, "sound");
+ if (p)
+ *(p - 1) = '\0';
+ p = strstr(phys, "video4linux");
+ if (p)
+ *(p - 1) = '\0';
+
+ bus_type = media_enumerate_get_physical_bus(phys);
+
+ switch (bus_type) {
+ case BUS_TYPE_PCI:
+ /* Remove the PCI function from the path if present. */
+ p = strrchr(phys, '.');
+ if (p)
+ *p = '\0';
+ break;
+ case BUS_TYPE_USB:
+ /* Remove the USB interface from the path if present. */
+ p = strrchr(phys, '/');
+ if (p && strchr(p, ':'))
+ *p = '\0';
+ break;
+ default:
+ break;
+ }
+
+ return phys;
+}
+
+#ifdef HAVE_LIBUDEV
+
+/* -----------------------------------------------------------------------------
+ * udev helpers
+ */
+
+static int media_enumerate_udev_scan_one(struct media_enumerate *media_enum,
+ const char *syspath,
+ media_enumerate_callback callback)
+{
+ struct udev_device *dev;
+ const char *devnode;
+ char *devpath = NULL;
+ dev_t devnum;
+ int ret = -ENODEV;
+
+ dev = udev_device_new_from_syspath(media_enum->udev, syspath);
+ if (dev == NULL)
+ return -ENODEV;
+
+ devnode = udev_device_get_devnode(dev);
+ if (devnode == NULL)
+ goto done;
+
+ devpath = media_enumerate_get_physical_parent(syspath);
+ if (devpath == NULL)
+ goto done;
+
+ devnum = udev_device_get_devnum(dev);
+ ret = callback(media_enum, devpath, devnode, devnum);
+
+done:
+ udev_device_unref(dev);
+ free(devpath);
+ return ret;
+}
+
+static int media_enumerate_udev_scan(struct media_enumerate *media_enum,
+ const char *subsystem, const char *type,
+ media_enumerate_callback callback)
+{
+ struct udev_enumerate *udev_enum = NULL;
+ struct udev_list_entry *devs;
+ struct udev_list_entry *dev;
+ unsigned int len;
+ int ret;
+
+ udev_enum = udev_enumerate_new(media_enum->udev);
+ if (udev_enum == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = udev_enumerate_add_match_subsystem(udev_enum, subsystem);
+ if (ret < 0)
+ goto done;
+
+ ret = udev_enumerate_scan_devices(udev_enum);
+ if (ret < 0)
+ goto done;
+
+ devs = udev_enumerate_get_list_entry(udev_enum);
+ if (devs == NULL)
+ goto done;
+
+ len = strlen(type);
+
+ udev_list_entry_foreach(dev, devs) {
+ const char *syspath;
+ const char *p;
+
+ syspath = udev_list_entry_get_name(dev);
+
+ p = strrchr(syspath, '/');
+ if (p == NULL || strncmp(p + 1, type, len))
+ continue;
+
+ media_enumerate_udev_scan_one(media_enum, syspath, callback);
+ }
+
+ ret = 0;
+
+done:
+ udev_enumerate_unref(udev_enum);
+ return ret;
+}
+
+#else
+
+/* -----------------------------------------------------------------------------
+ * sysfs helpers
+ */
+
+static int
+media_enumerate_sysfs_scan_one(struct media_enumerate *media_enum,
+ const char *sysbase, const char *prefix, int idx,
+ media_enumerate_callback callback)
+{
+ unsigned int major;
+ unsigned int minor;
+ struct stat devstat;
+ unsigned int len;
+ char *devname;
+ char *devpath;
+ char dev[20];
+ char *end;
+ int ret;
+ int fd;
+
+ /* Read the device major and minor from sysfs. */
+ len = strlen(sysbase) + strlen(prefix) + 17;
+ devname = malloc(len);
+ if (devname == NULL)
+ return -ENOMEM;
+
+ sprintf(devname, "%s/%s%u", sysbase, prefix, idx);
+ devpath = media_enumerate_get_physical_parent(devname);
+ if (devpath == NULL)
+ goto done;
+
+ sprintf(devname, "%s/%s%u/dev", sysbase, prefix, idx);
+ fd = open(devname, O_RDONLY);
+ if (fd == -1) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = read(fd, dev, sizeof dev - 1);
+ close(fd);
+ if (ret < 0) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev[ret] = '\0';
+ major = strtoul(dev, &end, 10);
+ if (*end != ':') {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ minor = strtoul(end + 1, &end, 10);
+ if (!isspace(*end) && end != '\0') {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ /* Verify that the device node exists. udev might have reordered the
+ * device nodes, make sure the major/minor match as a sanity check.
+ */
+ if (!strcmp(prefix, "controlC"))
+ sprintf(devname, "/dev/snd/%s%u", prefix, idx);
+ else
+ sprintf(devname, "/dev/%s%u", prefix, idx);
+
+ ret = stat(devname, &devstat);
+ if (ret < 0) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (major(devstat.st_rdev) != major || minor(devstat.st_rdev) != minor) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = callback(media_enum, devpath, devname, makedev(major, minor));
+
+done:
+ free(devname);
+ free(devpath);
+ return ret;
+}
+
+static int
+media_enumerate_sysfs_scan(struct media_enumerate *media_enum,
+ const char *sysbase, const char *prefix,
+ media_enumerate_callback callback)
+{
+ struct dirent *ent;
+ unsigned int len;
+ char *end;
+ DIR *dir;
+
+ len = strlen(prefix);
+
+ dir = opendir(sysbase);
+ if (dir == NULL)
+ return -ENODEV;
+
+ while ((ent = readdir(dir)) != NULL) {
+ unsigned int idx;
+
+ if (strncmp(ent->d_name, prefix, len))
+ continue;
+
+ idx = strtoul(ent->d_name + len, &end, 10);
+ if (*end != '\0')
+ continue;
+
+ media_enumerate_sysfs_scan_one(media_enum, sysbase, prefix, idx,
+ callback);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Media devices enumeration
+ */
+
+static int media_enumerate_match_one_media(struct media_enumerate *media_enum,
+ const char *syspath, const char *devname,
+ dev_t devnum __attribute__((__unused__)))
+{
+ struct media_device *media;
+ int ret;
+
+ media = media_device_new(devname);
+ if (media == NULL)
+ return -ENODEV;
+
+ ret = media_device_enumerate(media);
+ if (ret < 0) {
+ media_device_unref(media);
+ return -ENODEV;
+ }
+
+ return media_enumerate_add_device(media_enum, syspath, media);
+}
+
+static int media_enumerate_scan_media(struct media_enumerate *media_enum)
+{
+#ifdef HAVE_LIBUDEV
+ return media_enumerate_udev_scan(media_enum, "media", "media",
+ media_enumerate_match_one_media);
+#else
+ return media_enumerate_sysfs_scan(media_enum, "/sys/bus/media/devices",
+ "media", media_enumerate_match_one_media);
+#endif /* HAVE_LIBUDEV */
+}
+
+/* -----------------------------------------------------------------------------
+ * Video devices enumeration
+ */
+
+static int media_enumerate_match_one_video(struct media_enumerate *media_enum,
+ const char *syspath,
+ const char *devname, dev_t devnum)
+{
+ struct media_entity_desc entity;
+ struct media_device_info info;
+ struct v4l2_capability cap;
+ struct media_device *media;
+ unsigned int i, j;
+ int ret;
+ int fd;
+
+ /* Verify whether the video device node is part of an already enumerated
+ * media device.
+ */
+ for (i = 0; i < media_enum->devices_count; ++i) {
+ unsigned int nents;
+
+ media = media_enum->devices[i];
+ nents = media_get_entities_count(media);
+
+ for (j = 0; j < nents; ++j) {
+ struct media_entity *entity = media_get_entity(media, j);
+ const struct media_entity_desc *info = media_entity_get_info(entity);
+ dev_t dev;
+
+ if (info->type != MEDIA_ENT_T_DEVNODE_V4L)
+ continue;
+
+ dev = makedev(info->v4l.major, info->v4l.minor);
+ if (dev == devnum)
+ return 0;
+ }
+ }
+
+ fd = open(devname, O_RDWR);
+ if (fd < 0)
+ return -ENODEV;
+
+ memset(&cap, 0, sizeof cap);
+ ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+ close(fd);
+
+ if (ret < 0)
+ return -ENODEV;
+
+ memset(&info, 0, sizeof info);
+ memcpy(info.driver, cap.driver, sizeof info.driver);
+ memcpy(info.model, cap.card, sizeof info.model);
+ memcpy(info.bus_info, cap.bus_info, sizeof info.bus_info);
+ info.driver_version = cap.version;
+
+ media = media_device_new_emulated(&info);
+ if (media == NULL)
+ return -ENOMEM;
+
+ memset(&entity, 0, sizeof entity);
+ memcpy(entity.name, cap.card, sizeof entity.name);
+ entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ entity.flags = MEDIA_ENT_FL_DEFAULT;
+ entity.v4l.major = major(devnum);
+ entity.v4l.minor = minor(devnum);
+
+ ret = media_device_add_entity(media, &entity, devname);
+ if (ret < 0) {
+ media_device_unref(media);
+ return ret;
+ }
+
+ return media_enumerate_add_device(media_enum, syspath, media);
+}
+
+static int media_enumerate_scan_video(struct media_enumerate *media_enum)
+{
+#ifdef HAVE_LIBUDEV
+ return media_enumerate_udev_scan(media_enum, "video4linux", "video",
+ media_enumerate_match_one_video);
+#else
+ return media_enumerate_sysfs_scan(media_enum, "/sys/class/video4linux",
+ "video", media_enumerate_match_one_video);
+#endif /* HAVE_LIBUDEV */
+}
+
+/* -----------------------------------------------------------------------------
+ * Audio devices enumeration
+ */
+
+static int media_enumerate_match_one_audio(struct media_enumerate *media_enum,
+ const char *syspath, const char *devname,
+ dev_t devnum __attribute__((__unused__)))
+{
+ struct media_entity_desc entity;
+ struct media_device *parent = NULL;
+ struct media_device *media;
+ unsigned int card;
+ unsigned int i, j;
+ char *endp;
+
+ /* Verify whether the sound card is part of an already enumerated media
+ * device.
+ */
+ card = strtoul(strrchr(devname, '/') + strlen("/controlC"), &endp, 10);
+ if (*endp != '\0')
+ return -EINVAL;
+
+ for (i = 0; i < media_enum->devices_count; ++i) {
+ unsigned int nents;
+
+ media = media_enum->devices[i];
+ nents = media_get_entities_count(media);
+
+ if (!strcmp(media_enum->syspaths[i], syspath))
+ parent = media;
+
+ for (j = 0; j < nents; ++j) {
+ struct media_entity *entity = media_get_entity(media, j);
+ const struct media_entity_desc *info = media_entity_get_info(entity);
+
+ if (info->type != MEDIA_ENT_T_DEVNODE_ALSA)
+ continue;
+
+ if (info->alsa.card == card)
+ return 0;
+ }
+ }
+
+ if (!parent)
+ return 0;
+
+ memset(&entity, 0, sizeof entity);
+ entity.type = MEDIA_ENT_T_DEVNODE_ALSA;
+ entity.flags = MEDIA_ENT_FL_DEFAULT;
+ snprintf(entity.name, sizeof entity.name, "ALSA %u/%u/%u", card, 0, 0);
+ entity.alsa.card = card;
+ entity.alsa.device = 0;
+ entity.alsa.subdevice = 0;
+
+ return media_device_add_entity(parent, &entity, devname);
+}
+
+static int media_enumerate_scan_audio(struct media_enumerate *media_enum)
+{
+#ifdef HAVE_LIBUDEV
+ return media_enumerate_udev_scan(media_enum, "sound", "control",
+ media_enumerate_match_one_audio);
+#else
+ return media_enumerate_sysfs_scan(media_enum, "/sys/class/sound",
+ "controlC", media_enumerate_match_one_audio);
+#endif /* HAVE_LIBUDEV */
+}
+
+/* -------------------------------------------------------------------------- */
+
+struct media_enumerate *media_enumerate_new(void)
+{
+ struct media_enumerate *media_enum;
+
+ media_enum = calloc(1, sizeof *media_enum);
+ if (media_enum == NULL)
+ return NULL;
+
+ media_enum->refcount = 1;
+
+#ifdef HAVE_LIBUDEV
+ media_enum->udev = udev_new();
+ if (media_enum->udev == NULL) {
+ printf("Unable to get udev context\n");
+ media_enumerate_unref(media_enum);
+ return NULL;
+ }
+#endif
+
+ return media_enum;
+}
+
+struct media_enumerate *media_enumerate_ref(struct media_enumerate *media_enum)
+{
+ media_enum->refcount++;
+ return media_enum;
+}
+
+void media_enumerate_unref(struct media_enumerate *media_enum)
+{
+ unsigned int i;
+
+ media_enum->refcount--;
+ if (media_enum->refcount > 0)
+ return;
+
+ for (i = 0; i < media_enum->devices_count; ++i) {
+ media_device_unref(media_enum->devices[i]);
+ free(media_enum->syspaths[i]);
+ }
+
+#ifdef HAVE_LIBUDEV
+ udev_unref(media_enum->udev);
+#endif
+
+ free(media_enum->devices);
+ free(media_enum->syspaths);
+ free(media_enum);
+}
+
+int media_enumerate_scan(struct media_enumerate *media_enum)
+{
+ media_enumerate_scan_media(media_enum);
+ media_enumerate_scan_video(media_enum);
+ media_enumerate_scan_audio(media_enum);
+
+ return 0;
+}
+
+struct media_device **media_enumerate_get_devices(struct media_enumerate *media_enum)
+{
+ return media_enum->devices;
+}
+
+unsigned int media_enumerate_get_devices_count(struct media_enumerate *media_enum)
+{
+ return media_enum->devices_count;
+}