summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2fc63d0
--- /dev/null
+++ b/main.c
@@ -0,0 +1,289 @@
+/*
+ * 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/>.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <mediactl/mediactl.h>
+#include <mediactl/v4l2subdev.h>
+
+#include "media-enumerate.h"
+
+/* -----------------------------------------------------------------------------
+ * Topology printing - copied from mediactl
+ */
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+
+static void v4l2_subdev_print_format(struct media_entity *entity,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_rect rect;
+ int ret;
+
+ ret = v4l2_subdev_get_format(entity, &format, pad, which);
+ if (ret != 0)
+ return;
+
+ printf("\t\t[fmt:%s/%ux%u",
+ v4l2_subdev_pixelcode_to_string(format.code),
+ format.width, format.height);
+
+ ret = v4l2_subdev_get_selection(entity, &rect, pad,
+ V4L2_SEL_TGT_CROP_BOUNDS,
+ which);
+ if (ret == 0)
+ printf("\n\t\t crop.bounds:(%u,%u)/%ux%u", rect.left, rect.top,
+ rect.width, rect.height);
+
+ ret = v4l2_subdev_get_selection(entity, &rect, pad,
+ V4L2_SEL_TGT_CROP,
+ which);
+ if (ret == 0)
+ printf("\n\t\t crop:(%u,%u)/%ux%u", rect.left, rect.top,
+ rect.width, rect.height);
+
+ ret = v4l2_subdev_get_selection(entity, &rect, pad,
+ V4L2_SEL_TGT_COMPOSE_BOUNDS,
+ which);
+ if (ret == 0)
+ printf("\n\t\t compose.bounds:(%u,%u)/%ux%u",
+ rect.left, rect.top, rect.width, rect.height);
+
+ ret = v4l2_subdev_get_selection(entity, &rect, pad,
+ V4L2_SEL_TGT_COMPOSE,
+ which);
+ if (ret == 0)
+ printf("\n\t\t compose:(%u,%u)/%ux%u",
+ rect.left, rect.top, rect.width, rect.height);
+
+ printf("]\n");
+}
+
+static const char *media_entity_type_to_string(unsigned type)
+{
+ static const struct {
+ __u32 type;
+ const char *name;
+ } types[] = {
+ { MEDIA_ENT_T_DEVNODE, "Node" },
+ { MEDIA_ENT_T_V4L2_SUBDEV, "V4L2 subdev" },
+ };
+
+ unsigned int i;
+
+ type &= MEDIA_ENT_TYPE_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (types[i].type == type)
+ return types[i].name;
+ }
+
+ return "Unknown";
+}
+
+static const char *media_entity_subtype_to_string(unsigned type)
+{
+ static const char *node_types[] = {
+ "Unknown",
+ "V4L",
+ "FB",
+ "ALSA",
+ "DVB",
+ };
+ static const char *subdev_types[] = {
+ "Unknown",
+ "Sensor",
+ "Flash",
+ "Lens",
+ };
+
+ unsigned int subtype = type & MEDIA_ENT_SUBTYPE_MASK;
+
+ switch (type & MEDIA_ENT_TYPE_MASK) {
+ case MEDIA_ENT_T_DEVNODE:
+ if (subtype >= ARRAY_SIZE(node_types))
+ subtype = 0;
+ return node_types[subtype];
+
+ case MEDIA_ENT_T_V4L2_SUBDEV:
+ if (subtype >= ARRAY_SIZE(subdev_types))
+ subtype = 0;
+ return subdev_types[subtype];
+ default:
+ return node_types[0];
+ }
+}
+
+static const char *media_pad_type_to_string(unsigned flag)
+{
+ static const struct {
+ __u32 flag;
+ const char *name;
+ } flags[] = {
+ { MEDIA_PAD_FL_SINK, "Sink" },
+ { MEDIA_PAD_FL_SOURCE, "Source" },
+ };
+
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(flags); i++) {
+ if (flags[i].flag & flag)
+ return flags[i].name;
+ }
+
+ return "Unknown";
+}
+
+static void media_print_topology_text(struct media_device *media)
+{
+ static const struct {
+ __u32 flag;
+ char *name;
+ } link_flags[] = {
+ { MEDIA_LNK_FL_ENABLED, "ENABLED" },
+ { MEDIA_LNK_FL_IMMUTABLE, "IMMUTABLE" },
+ { MEDIA_LNK_FL_DYNAMIC, "DYNAMIC" },
+ };
+
+ struct media_entity *entities = media_get_entities(media);
+ unsigned int nents = media_get_entities_count(media);
+ unsigned int i, j, k;
+ unsigned int padding;
+
+ printf("Device topology\n");
+
+ for (i = 0; i < nents; ++i) {
+ struct media_entity *entity = &entities[i];
+
+ padding = printf("- entity %u: ", entity->info.id);
+ printf("%s (%u pad%s, %u link%s)\n", entity->info.name,
+ entity->info.pads, entity->info.pads > 1 ? "s" : "",
+ entity->num_links, entity->num_links > 1 ? "s" : "");
+ printf("%*ctype %s subtype %s flags %x\n", padding, ' ',
+ media_entity_type_to_string(entity->info.type),
+ media_entity_subtype_to_string(entity->info.type),
+ entity->info.flags);
+ if (entity->devname[0])
+ printf("%*cdevice node name %s\n", padding, ' ', entity->devname);
+
+ for (j = 0; j < entity->info.pads; j++) {
+ struct media_pad *pad = &entity->pads[j];
+
+ printf("\tpad%u: %s\n", j, media_pad_type_to_string(pad->flags));
+
+ if (media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV)
+ v4l2_subdev_print_format(entity, j, V4L2_SUBDEV_FORMAT_ACTIVE);
+
+ for (k = 0; k < entity->num_links; k++) {
+ struct media_link *link = &entity->links[k];
+ struct media_pad *source = link->source;
+ struct media_pad *sink = link->sink;
+ bool first = true;
+ unsigned int i;
+
+ if (source->entity == entity && source->index == j)
+ printf("\t\t-> \"%s\":%u [",
+ sink->entity->info.name, sink->index);
+ else if (sink->entity == entity && sink->index == j)
+ printf("\t\t<- \"%s\":%u [",
+ source->entity->info.name, source->index);
+ else
+ continue;
+
+ for (i = 0; i < ARRAY_SIZE(link_flags); i++) {
+ if (!(link->flags & link_flags[i].flag))
+ continue;
+ if (!first)
+ printf(",");
+ printf("%s", link_flags[i].name);
+ first = false;
+ }
+
+ printf("]\n");
+ }
+ }
+ printf("\n");
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Printing
+ */
+
+int main(int argc, char *argv[])
+{
+ struct media_enumerate *media_enum;
+ struct media_device **devices;
+ unsigned int n_devs;
+ unsigned int i;
+ int ret;
+
+ media_enum = media_enumerate_new();
+ if (media_enum == NULL) {
+ printf("Unable to create enumeration context\n");
+ return EXIT_FAILURE;
+ }
+
+ ret = media_enumerate_scan(media_enum);
+ if (ret < 0) {
+ goto done;
+ printf("Unable to enumerate media devices (%d)\n", ret);
+ }
+
+ n_devs = media_enumerate_get_devices_count(media_enum);
+ if (n_devs == 0) {
+ printf("No devices found\n");
+ goto done;
+ }
+
+ devices = media_enumerate_get_devices(media_enum);
+ for (i = 0; i < n_devs; ++i) {
+ const struct media_device_info *info = media_get_info(devices[i]);
+
+ printf("Media controller API version %u.%u.%u\n\n",
+ (info->media_version << 16) & 0xff,
+ (info->media_version << 8) & 0xff,
+ (info->media_version << 0) & 0xff);
+ printf("Media device information\n"
+ "------------------------\n"
+ "driver %s\n"
+ "model %s\n"
+ "serial %s\n"
+ "bus info %s\n"
+ "hw revision 0x%x\n"
+ "driver version %u.%u.%u\n\n",
+ info->driver, info->model,
+ info->serial, info->bus_info,
+ info->hw_revision,
+ (info->driver_version << 16) & 0xff,
+ (info->driver_version << 8) & 0xff,
+ (info->driver_version << 0) & 0xff);
+
+ media_print_topology_text(devices[i]);
+ }
+
+done:
+ media_enumerate_unref(media_enum);
+ return EXIT_SUCCESS;
+}