/* * Media device discovery library * * Copyright (C) 2012 Ideas on board SPRL * * Contact: Laurent Pinchart * * 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 . */ #include #include #include #include #include #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" }, }; 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 = media_get_entity(media, i); const struct media_entity_desc *info = media_entity_get_info(entity); const char *devname = media_entity_get_devname(entity); unsigned int num_links = media_entity_get_links_count(entity); padding = printf("- entity %u: ", info->id); printf("%s (%u pad%s, %u link%s)\n", info->name, info->pads, info->pads > 1 ? "s" : "", num_links, num_links > 1 ? "s" : ""); printf("%*ctype %s subtype %s flags %x\n", padding, ' ', media_entity_type_to_string(info->type), media_entity_subtype_to_string(info->type), info->flags); if (devname) printf("%*cdevice node name %s\n", padding, ' ', devname); for (j = 0; j < info->pads; j++) { const struct media_pad *pad = media_entity_get_pad(entity, 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 < num_links; k++) { const struct media_link *link = media_entity_get_link(entity, k); const struct media_pad *source = link->source; const struct media_pad *sink = link->sink; bool first = true; unsigned int i; if (source->entity == entity && source->index == j) printf("\t\t-> \"%s\":%u [", media_entity_get_info(sink->entity)->name, sink->index); else if (sink->entity == entity && sink->index == j) printf("\t\t<- \"%s\":%u [", media_entity_get_info(source->entity)->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; }