summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-08-03 10:55:50 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-03-10 19:54:04 +0100
commitc4aee27b34a92f1774dbb41f255b79f46e1bdf06 (patch)
treeedd2b461e5cdcc0534355cc12512fad7023219e2
parent5d751cc0b289282d354f7701a1ff896cc0778be8 (diff)
Add support for emulated devices
Emulated media devices are backed by real hardware devices for the functions they provide, but have no kernel media device counterpart. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Sakari Ailus <sakari.ailus@iki.fi>
-rw-r--r--src/mediactl.c85
-rw-r--r--src/mediactl.h52
2 files changed, 133 insertions, 4 deletions
diff --git a/src/mediactl.c b/src/mediactl.c
index 4da334a..5daecb6 100644
--- a/src/mediactl.c
+++ b/src/mediactl.c
@@ -637,7 +637,7 @@ void media_debug_set_handler(struct media_device *media,
}
}
-struct media_device *media_device_new(const char *devnode)
+static struct media_device *__media_device_new(void)
{
struct media_device *media;
int ret;
@@ -651,6 +651,18 @@ struct media_device *media_device_new(const char *devnode)
media_debug_set_handler(media, NULL, NULL);
+ return media;
+}
+
+struct media_device *media_device_new(const char *devnode)
+{
+ struct media_device *media;
+ int ret;
+
+ media = __media_device_new();
+ if (media == NULL)
+ return NULL;
+
media->devnode = strdup(devnode);
if (media->devnode == NULL) {
media_device_unref(media);
@@ -660,6 +672,19 @@ struct media_device *media_device_new(const char *devnode)
return media;
}
+struct media_device *media_device_new_emulated(struct media_device_info *info)
+{
+ struct media_device *media;
+
+ media = __media_device_new();
+ if (media == NULL)
+ return NULL;
+
+ media->info = *info;
+
+ return media;
+}
+
struct media_device *media_device_ref(struct media_device *media)
{
media->refcount++;
@@ -688,9 +713,61 @@ void media_device_unref(struct media_device *media)
free(media);
}
-/* -----------------------------------------------------------------------------
- * Parsing
- */
+int media_device_add_entity(struct media_device *media,
+ const struct media_entity_desc *desc,
+ const char *devnode)
+{
+ struct media_entity **defent;
+ struct media_entity *entity;
+ unsigned int size;
+
+ size = (media->entities_count + 1) * sizeof(*media->entities);
+ entity = realloc(media->entities, size);
+ if (entity == NULL)
+ return -ENOMEM;
+
+ media->entities = entity;
+ media->entities_count++;
+
+ entity = &media->entities[media->entities_count - 1];
+ memset(entity, 0, sizeof *entity);
+
+ entity->fd = -1;
+ entity->media = media;
+ strncpy(entity->devname, devnode, sizeof entity->devname);
+ entity->devname[sizeof entity->devname - 1] = '\0';
+
+ entity->info.id = 0;
+ entity->info.type = desc->type;
+ entity->info.flags = 0;
+ memcpy(entity->info.name, desc->name, sizeof entity->info.name);
+
+ switch (entity->info.type) {
+ case MEDIA_ENT_T_DEVNODE_V4L:
+ defent = &media->def.v4l;
+ entity->info.v4l = desc->v4l;
+ break;
+ case MEDIA_ENT_T_DEVNODE_FB:
+ defent = &media->def.fb;
+ entity->info.fb = desc->fb;
+ break;
+ case MEDIA_ENT_T_DEVNODE_ALSA:
+ defent = &media->def.alsa;
+ entity->info.alsa = desc->alsa;
+ break;
+ case MEDIA_ENT_T_DEVNODE_DVB:
+ defent = &media->def.dvb;
+ entity->info.dvb = desc->dvb;
+ break;
+ }
+
+ if (desc->flags & MEDIA_ENT_FL_DEFAULT) {
+ entity->info.flags |= MEDIA_ENT_FL_DEFAULT;
+ *defent = entity;
+ }
+
+ return 0;
+}
struct media_pad *media_parse_pad(struct media_device *media,
const char *p, char **endp)
diff --git a/src/mediactl.h b/src/mediactl.h
index b74be0b..e34ae81 100644
--- a/src/mediactl.h
+++ b/src/mediactl.h
@@ -60,6 +60,22 @@ struct media_entity;
struct media_device *media_device_new(const char *devnode);
/**
+ * @brief Create a new emulated media device.
+ * @param info - device information.
+ *
+ * Emulated media devices are userspace-only objects not backed by a kernel
+ * media device. They are created for ALSA and V4L2 devices that are not
+ * associated with a media controller device.
+ *
+ * Only device query functions are available for media devices. Enumerating or
+ * setting up links is invalid.
+ *
+ * @return A pointer to the new media device or NULL if memory cannot be
+ * allocated.
+ */
+struct media_device *media_device_new_emulated(struct media_device_info *info);
+
+/**
* @brief Take a reference to the device.
* @param media - device instance.
*
@@ -81,6 +97,42 @@ struct media_device *media_device_ref(struct media_device *media);
void media_device_unref(struct media_device *media);
/**
+ * @brief Add an entity to an existing media device
+ * @param media - device instance.
+ * @param desc - description of the entity to be added
+ * @param devnode - device node corresponding to the entity
+ *
+ * Entities are usually created and added to media devices automatically when
+ * the media device is enumerated through the media controller API. However,
+ * when an emulated media device (thus not backed with a kernel-side media
+ * controller device) is created, entities need to be manually added.
+ *
+ * Entities can also be manually added to a successfully enumerated media device
+ * to group several functions provided by separate kernel devices. The most
+ * common use case is to group the audio and video functions of a USB webcam in
+ * a single media device. Those functions are exposed through separate USB
+ * interfaces and handled through unrelated kernel drivers, they must thus be
+ * manually added to the same media device.
+ *
+ * This function adds a new entity to the given media device and initializes it
+ * from the given entity description and device node name. Only the following
+ * fields of the description are copied over to the new entity:
+ *
+ * - type
+ * - flags (MEDIA_ENT_FL_DEFAULT only)
+ * - name
+ * - v4l, fb, alsa or dvb (depending on the device type)
+ *
+ * All other fields of the newly created entity id are initialized to 0,
+ * including the entity ID.
+ *
+ * @return Zero on success or -ENOMEM if memory cannot be allocated.
+ */
+int media_device_add_entity(struct media_device *media,
+ const struct media_entity_desc *desc,
+ const char *devnode);
+
+/**
* @brief Set a handler for debug messages.
* @param media - device instance.
* @param debug_handler - debug message handler