This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:
Subject: v4l2-ctl/v4l2-compliance: reuse media info code Author: Hans Verkuil <hans.verk...@cisco.com> Date: Sun Feb 4 12:17:22 2018 +0100 The code that displays the media information for an interface is now centralized in common/media-info.cpp and used by both v4l2-ctl and v4l2-compliance. In addition, this code now uses G_TOPOLOGY if available. Signed-off-by: Hans Verkuil <hans.verk...@cisco.com> utils/common/media-info.cpp | 472 ++++++++++++++++++++++++++++++ utils/common/media-info.h | 33 +++ utils/v4l2-compliance/Makefile.am | 3 +- utils/v4l2-compliance/media-info.cpp | 1 + utils/v4l2-compliance/media-info.h | 1 + utils/v4l2-compliance/v4l2-compliance.cpp | 205 +------------ utils/v4l2-compliance/v4l2-test-media.cpp | 8 +- utils/v4l2-ctl/Makefile.am | 3 +- utils/v4l2-ctl/media-info.cpp | 1 + utils/v4l2-ctl/media-info.h | 1 + utils/v4l2-ctl/v4l2-ctl.cpp | 256 +--------------- 11 files changed, 525 insertions(+), 459 deletions(-) --- http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=ce29414c85f565b0ea97804d7e6ee0d6f4dd1d7d diff --git a/utils/common/media-info.cpp b/utils/common/media-info.cpp new file mode 100644 index 000000000000..4ced684dc894 --- /dev/null +++ b/utils/common/media-info.cpp @@ -0,0 +1,472 @@ +/* + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/sysmacros.h> +#include <dirent.h> + +#include <linux/media.h> + +#include <fstream> + +static std::string num2s(unsigned num) +{ + char buf[10]; + + sprintf(buf, "%08x", num); + return buf; +} + +typedef struct { + unsigned flag; + const char *str; +} flag_def; + +static std::string flags2s(unsigned val, const flag_def *def) +{ + std::string s; + + while (def->flag) { + if (val & def->flag) { + if (s.length()) s += ", "; + s += def->str; + val &= ~def->flag; + } + def++; + } + if (val) { + if (s.length()) s += ", "; + s += num2s(val); + } + return s; +} + +int mi_get_media_fd(int fd) +{ + struct stat sb; + int media_fd = -1; + + if (fstat(fd, &sb) == -1) { + fprintf(stderr, "failed to stat file\n"); + return -1; + } + + char media_path[100]; + if (snprintf(media_path, sizeof(media_path), "/sys/dev/char/%d:%d/device", + major(sb.st_rdev), minor(sb.st_rdev)) == -1) { + fprintf(stderr, "failed to create media file path\n"); + return -1; + } + DIR *dp; + struct dirent *ep; + dp = opendir(media_path); + if (dp == NULL) + return -1; + media_path[0] = 0; + while ((ep = readdir(dp))) { + if (!memcmp(ep->d_name, "media", 5) && isdigit(ep->d_name[5])) { + std::string devname("/dev/"); + + devname += ep->d_name; + media_fd = open(devname.c_str(), O_RDWR); + break; + } + } + closedir(dp); + return media_fd; +} + +bool mi_is_subdevice(int fd) +{ + struct stat sb; + if (fstat(fd, &sb) == -1) { + fprintf(stderr, "failed to stat file\n"); + exit(1); + } + + char uevent_path[100]; + if (snprintf(uevent_path, sizeof(uevent_path), "/sys/dev/char/%d:%d/uevent", + major(sb.st_rdev), minor(sb.st_rdev)) == -1) { + fprintf(stderr, "failed to create uevent file path\n"); + exit(1); + } + + std::ifstream uevent_file(uevent_path); + if (uevent_file.fail()) { + fprintf(stderr, "failed to open %s\n", uevent_path); + exit(1); + } + + std::string line; + + while (std::getline(uevent_file, line)) { + if (line.compare(0, 8, "DEVNAME=")) + continue; + + static const char * devnames[] = { + "v4l-subdev", + "video", + "vbi", + "radio", + "swradio", + "v4l-touch", + NULL + }; + + for (size_t i = 0; devnames[i]; i++) { + size_t len = strlen(devnames[i]); + + if (!line.compare(8, len, devnames[i]) && isdigit(line[8+len])) { + uevent_file.close(); + return i == 0; + } + } + } + + uevent_file.close(); + + fprintf(stderr, "unknown device name\n"); + exit(1); +} + +static const flag_def entity_flags_def[] = { + { MEDIA_ENT_FL_DEFAULT, "default" }, + { MEDIA_ENT_FL_CONNECTOR, "connector" }, + { 0, NULL } +}; + +static std::string entflags2s(__u32 flags) +{ + return flags2s(flags, entity_flags_def); +} + +static const flag_def interface_types_def[] = { + { MEDIA_INTF_T_DVB_FE, "DVB Front End" }, + { MEDIA_INTF_T_DVB_DEMUX, "DVB Demuxer" }, + { MEDIA_INTF_T_DVB_DVR, "DVB DVR" }, + { MEDIA_INTF_T_DVB_CA, "DVB Conditional Access" }, + { MEDIA_INTF_T_DVB_NET, "DVB Net" }, + + { MEDIA_INTF_T_V4L_VIDEO, "V4L Video" }, + { MEDIA_INTF_T_V4L_VBI, "V4L VBI" }, + { MEDIA_INTF_T_V4L_RADIO, "V4L Radio" }, + { MEDIA_INTF_T_V4L_SUBDEV, "V4L Sub-Device" }, + { MEDIA_INTF_T_V4L_SWRADIO, "V4L Software Defined Radio" }, + { MEDIA_INTF_T_V4L_TOUCH, "V4L Touch" }, + + { MEDIA_INTF_T_ALSA_PCM_CAPTURE, "ALSA PCM Capture" }, + { MEDIA_INTF_T_ALSA_PCM_PLAYBACK, "ALSA PCM Playback" }, + { MEDIA_INTF_T_ALSA_CONTROL, "ALSA Control" }, + { MEDIA_INTF_T_ALSA_COMPRESS, "ALSA Compress" }, + { MEDIA_INTF_T_ALSA_RAWMIDI, "ALSA Raw MIDI" }, + { MEDIA_INTF_T_ALSA_HWDEP, "ALSA HWDEP" }, + { MEDIA_INTF_T_ALSA_SEQUENCER, "ALSA Sequencer" }, + { MEDIA_INTF_T_ALSA_TIMER, "ALSA Timer" }, + { 0, NULL } +}; + +static std::string ifacetype2s(__u32 type) +{ + for (unsigned i = 0; interface_types_def[i].str; i++) + if (type == interface_types_def[i].flag) + return interface_types_def[i].str; + return "Unknown (" + num2s(type) + ")"; +} + +static const flag_def entity_types_def[] = { + { MEDIA_ENT_F_UNKNOWN, "Unknown" }, + { MEDIA_ENT_F_DTV_DEMOD, "Digital TV Demodulator" }, + { MEDIA_ENT_F_TS_DEMUX, "Transport Stream Demuxer" }, + { MEDIA_ENT_F_DTV_CA, "Digital TV Conditional Access" }, + { MEDIA_ENT_F_DTV_NET_DECAP, "Digital TV Network ULE/MLE Desencapsulation" }, + { MEDIA_ENT_F_IO_DTV, "Digital TV I/O" }, + { MEDIA_ENT_F_IO_VBI, "VBI I/O" }, + { MEDIA_ENT_F_IO_SWRADIO, "Software Radio I/O" }, + { MEDIA_ENT_F_IF_VID_DECODER, "IF-PLL Video Decoder" }, + { MEDIA_ENT_F_IF_AUD_DECODER, "IF-PLL Audio Decoder" }, + { MEDIA_ENT_F_AUDIO_CAPTURE, "Audio Capture" }, + { MEDIA_ENT_F_AUDIO_PLAYBACK, "Audio Playback" }, + { MEDIA_ENT_F_AUDIO_MIXER, "Audio Mixer" }, + { MEDIA_ENT_F_PROC_VIDEO_COMPOSER, "Video Composer" }, + { MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, "Video Pixel Formatter" }, + { MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, "Video Pixel Encoding Converter" }, + { MEDIA_ENT_F_PROC_VIDEO_LUT, "Video Look-Up Table" }, + { MEDIA_ENT_F_PROC_VIDEO_SCALER, "Video Scaler" }, + { MEDIA_ENT_F_PROC_VIDEO_STATISTICS, "Video Statistics" }, + { MEDIA_ENT_F_VID_MUX, "Video Muxer" }, + { MEDIA_ENT_F_VID_IF_BRIDGE, "Video Interface Bridge" }, + + { MEDIA_ENT_F_IO_V4L, "V4L2 I/O" }, + { MEDIA_ENT_F_CAM_SENSOR, "Camera Sensor" }, + { MEDIA_ENT_F_FLASH, "Flash Controller" }, + { MEDIA_ENT_F_LENS, "Lens Controller" }, + { MEDIA_ENT_F_ATV_DECODER, "Analog Video Decoder" }, + { MEDIA_ENT_F_TUNER, "Tuner" }, + { MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN, "Unknown" }, + { 0, NULL } +}; + +static std::string enttype2s(__u32 type) +{ + for (unsigned i = 0; entity_types_def[i].str; i++) + if (type == entity_types_def[i].flag) + return entity_types_def[i].str; + return "Unknown (" + num2s(type) + ")"; +} + +static const flag_def pad_flags_def[] = { + { MEDIA_PAD_FL_SINK, "Sink" }, + { MEDIA_PAD_FL_SOURCE, "Source" }, + { MEDIA_PAD_FL_MUST_CONNECT, "Must Connect" }, + { 0, NULL } +}; + +static std::string padflags2s(__u32 flags) +{ + return flags2s(flags, pad_flags_def); +} + +static const flag_def link_flags_def[] = { + { MEDIA_LNK_FL_ENABLED, "Enabled" }, + { MEDIA_LNK_FL_IMMUTABLE, "Immutable" }, + { MEDIA_LNK_FL_DYNAMIC, "Dynamic" }, + { 0, NULL } +}; + +static std::string linkflags2s(__u32 flags) +{ + std::string s = flags2s(flags, link_flags_def); + + if (!s.empty()) + s = ", " + s; + switch (flags & MEDIA_LNK_FL_LINK_TYPE) { + case MEDIA_LNK_FL_DATA_LINK: + return "Data" + s; + case MEDIA_LNK_FL_INTERFACE_LINK: + return "Interface" + s; + default: + return "Unknown" + s; + } +} + +static bool read_topology(int media_fd, __u32 major, __u32 minor) +{ + media_v2_topology topology; + unsigned i, j; + + memset(&topology, 0, sizeof(topology)); + if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology)) + return false; + + media_v2_entity v2_ents[topology.num_entities]; + media_v2_interface v2_ifaces[topology.num_interfaces]; + media_v2_pad v2_pads[topology.num_pads]; + media_v2_link v2_links[topology.num_links]; + + topology.ptr_entities = (__u64)v2_ents; + topology.ptr_interfaces = (__u64)v2_ifaces; + topology.ptr_pads = (__u64)v2_pads; + topology.ptr_links = (__u64)v2_links; + if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology)) + return false; + for (i = 0; i < topology.num_interfaces; i++) + if (v2_ifaces[i].devnode.major == major && + v2_ifaces[i].devnode.minor == minor) + break; + if (i == topology.num_interfaces) { + fprintf(stderr, "could not find %d:%d device in topology\n", + major, minor); + return false; + } + media_v2_interface &iface = v2_ifaces[i]; + for (i = 0; i < topology.num_links; i++) { + __u32 type = v2_links[i].flags & MEDIA_LNK_FL_LINK_TYPE; + + if (type != MEDIA_LNK_FL_INTERFACE_LINK) + continue; + if (v2_links[i].source_id == iface.id) + break; + } + if (i == topology.num_links) { + fprintf(stderr, "could not find link for interface %u in topology\n", + iface.id); + return false; + } + __u32 ent_id = v2_links[i].sink_id; + for (i = 0; i < topology.num_entities; i++) { + if (v2_ents[i].id == ent_id) + break; + } + if (i == topology.num_entities) { + fprintf(stderr, "could not find entity %u in topology\n", + ent_id); + return false; + } + media_v2_entity &ent = v2_ents[i]; + + printf("Interface Info:\n"); + printf("\tID : 0x%08x\n", iface.id); + printf("\tType : %s\n", ifacetype2s(iface.intf_type).c_str()); + printf("Entity Info:\n"); + printf("\tID : 0x%08x (%u)\n", ent.id, ent.id); + printf("\tName : %s\n", ent.name); + printf("\tFunction : %s\n", enttype2s(ent.function).c_str()); + + // Yes, I know, lots of nested for-loops. If we get really complex + // devices with such large topologies that this becomes too inefficient + // then this needs to be changed and we'd need some maps to quickly + // look up values. + for (i = 0; i < topology.num_pads; i++) { + const media_v2_pad &pad = v2_pads[i]; + + if (pad.entity_id != ent.id) + continue; + printf("\tPad 0x%08x : %s\n", + pad.id, padflags2s(pad.flags).c_str()); + for (j = 0; j < topology.num_links; j++) { + const media_v2_link &link = v2_links[j]; + __u32 type = link.flags & MEDIA_LNK_FL_LINK_TYPE; + __u32 remote_pad; + __u32 remote_ent_id = 0; + const media_v2_entity *remote_ent = NULL; + + if (type != MEDIA_LNK_FL_DATA_LINK || + (link.source_id != pad.id && link.sink_id != pad.id)) + continue; + bool is_sink = link.sink_id == pad.id; + remote_pad = is_sink ? link.source_id : link.sink_id; + for (unsigned k = 0; k < topology.num_pads; k++) + if (v2_pads[k].id == remote_pad) { + remote_ent_id = v2_pads[k].entity_id; + break; + } + if (!remote_ent_id) { + fprintf(stderr, "could not find remote pad 0x%08x in topology\n", + remote_pad); + return true; + } + for (unsigned k = 0; k < topology.num_entities; k++) + if (v2_ents[k].id == remote_ent_id) { + remote_ent = &v2_ents[k]; + break; + } + if (!remote_ent) { + fprintf(stderr, "could not find remote entity 0x%08x in topology\n", + remote_ent_id); + return true; + } + printf("\t Link 0x%08x: %s remote pad 0x%x of entity '%s': %s\n", + link.id, is_sink ? "from" : "to", remote_pad, + remote_ent->name, linkflags2s(link.flags).c_str()); + } + } + return true; +} + +void mi_media_info_for_fd(int media_fd, int fd) +{ + struct media_device_info mdinfo; + struct stat sb; + + if (ioctl(media_fd, MEDIA_IOC_DEVICE_INFO, &mdinfo)) + return; + + struct media_entity_desc ent; + bool found = false; + + printf("Media Driver Info:\n"); + printf("\tDriver name : %s\n", mdinfo.driver); + printf("\tModel : %s\n", mdinfo.model); + printf("\tSerial : %s\n", mdinfo.serial); + printf("\tBus info : %s\n", mdinfo.bus_info); + printf("\tMedia version : %d.%d.%d\n", + mdinfo.media_version >> 16, + (mdinfo.media_version >> 8) & 0xff, + mdinfo.media_version & 0xff); + printf("\tHardware revision: 0x%08x (%u)\n", + mdinfo.hw_revision, mdinfo.hw_revision); + printf("\tDriver version : %d.%d.%d\n", + mdinfo.driver_version >> 16, + (mdinfo.driver_version >> 8) & 0xff, + mdinfo.driver_version & 0xff); + + if (fd < 0) + return; + + if (fstat(fd, &sb) == -1) { + fprintf(stderr, "failed to stat file\n"); + exit(1); + } + + if (read_topology(media_fd, major(sb.st_rdev), minor(sb.st_rdev))) + return; + + memset(&ent, 0, sizeof(ent)); + ent.id = MEDIA_ENT_ID_FLAG_NEXT; + while (!ioctl(media_fd, MEDIA_IOC_ENUM_ENTITIES, &ent)) { + if (ent.dev.major == major(sb.st_rdev) && + ent.dev.minor == minor(sb.st_rdev)) { + found = true; + break; + } + ent.id |= MEDIA_ENT_ID_FLAG_NEXT; + } + if (!found) + return; + + printf("Entity Info:\n"); + printf("\tID : %u\n", ent.id); + printf("\tName : %s\n", ent.name); + printf("\tType : %s\n", enttype2s(ent.type).c_str()); + if (ent.flags) + printf("\tFlags : %s\n", entflags2s(ent.flags).c_str()); + if (ent.flags & MEDIA_ENT_FL_DEFAULT) { + printf("\tMajor : %u\n", ent.dev.major); + printf("\tMinor : %u\n", ent.dev.minor); + } + + struct media_links_enum links_enum; + struct media_pad_desc pads[ent.pads]; + struct media_link_desc links[ent.links]; + + memset(&links_enum, 0, sizeof(links_enum)); + links_enum.entity = ent.id; + links_enum.pads = pads; + links_enum.links = links; + if (ioctl(media_fd, MEDIA_IOC_ENUM_LINKS, &links_enum)) + return; + + for (unsigned i = 0; i < ent.pads; i++) + printf("\tPad : %u: %s\n", pads[i].index, + padflags2s(pads[i].flags).c_str()); + for (unsigned i = 0; i < ent.links; i++) + printf("\tLink : %u->%u: %s\n", + links[i].source.entity, + links[i].sink.entity, + linkflags2s(links[i].flags).c_str()); +} diff --git a/utils/common/media-info.h b/utils/common/media-info.h new file mode 100644 index 000000000000..2f84af3ef369 --- /dev/null +++ b/utils/common/media-info.h @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _MEDIA_INFO_H +#define _MEDIA_INFO_H + +/* + * For a given device fd return the corresponding media device + * or -1 if there is none. + */ +int mi_get_media_fd(int fd); + +/* + * Test if the given fd corresponds to a sub-device. + */ +bool mi_is_subdevice(int fd); +void mi_media_info_for_fd(int media_fd, int fd); + +#endif diff --git a/utils/v4l2-compliance/Makefile.am b/utils/v4l2-compliance/Makefile.am index 3af8b3f450e9..07f4cef71119 100644 --- a/utils/v4l2-compliance/Makefile.am +++ b/utils/v4l2-compliance/Makefile.am @@ -4,7 +4,8 @@ DEFS := v4l2_compliance_SOURCES = v4l2-compliance.cpp v4l2-test-debug.cpp v4l2-test-input-output.cpp \ v4l2-test-controls.cpp v4l2-test-io-config.cpp v4l2-test-formats.cpp v4l2-test-buffers.cpp \ - v4l2-test-codecs.cpp v4l2-test-subdevs.cpp v4l2-test-media.cpp v4l2-test-colors.cpp v4l2-compliance.h + v4l2-test-codecs.cpp v4l2-test-subdevs.cpp v4l2-test-media.cpp v4l2-test-colors.cpp \ + media-info.cpp v4l2_compliance_CPPFLAGS = -I$(top_srcdir)/utils/common if WITH_V4L2_COMPLIANCE_LIBV4L diff --git a/utils/v4l2-compliance/media-info.cpp b/utils/v4l2-compliance/media-info.cpp new file mode 120000 index 000000000000..89676ff50494 --- /dev/null +++ b/utils/v4l2-compliance/media-info.cpp @@ -0,0 +1 @@ +../common/media-info.cpp \ No newline at end of file diff --git a/utils/v4l2-compliance/media-info.h b/utils/v4l2-compliance/media-info.h new file mode 120000 index 000000000000..c4612f3cbe13 --- /dev/null +++ b/utils/v4l2-compliance/media-info.h @@ -0,0 +1 @@ +../common/media-info.h \ No newline at end of file diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp index 8e887838369f..7747bdcaaf8d 100644 --- a/utils/v4l2-compliance/v4l2-compliance.cpp +++ b/utils/v4l2-compliance/v4l2-compliance.cpp @@ -39,6 +39,7 @@ #include <vector> #include "v4l2-compliance.h" +#include <media-info.h> #ifndef ANDROID #include "version.h" #endif @@ -760,206 +761,6 @@ static int get_media_fd(int fd) return media_fd; } -typedef struct { - unsigned flag; - const char *str; -} flag_def; - -static std::string num2s(unsigned num) -{ - char buf[10]; - - sprintf(buf, "%08x", num); - return buf; -} - -static std::string flags2s(unsigned val, const flag_def *def) -{ - std::string s; - - while (def->flag) { - if (val & def->flag) { - if (s.length()) s += ", "; - s += def->str; - val &= ~def->flag; - } - def++; - } - if (val) { - if (s.length()) s += ", "; - s += num2s(val); - } - return s; -} - -static const flag_def entity_flags_def[] = { - { MEDIA_ENT_FL_DEFAULT, "default" }, - { MEDIA_ENT_FL_CONNECTOR, "connector" }, - { 0, NULL } -}; - -static std::string entflags2s(__u32 flags) -{ - return flags2s(flags, entity_flags_def); -} - -static const flag_def entity_types_def[] = { - { MEDIA_ENT_F_UNKNOWN, "Unknown" }, - { MEDIA_ENT_F_DTV_DEMOD, "Digital TV Demodulator" }, - { MEDIA_ENT_F_TS_DEMUX, "Transport Stream Demuxer" }, - { MEDIA_ENT_F_DTV_CA, "Digital TV Conditional Access" }, - { MEDIA_ENT_F_DTV_NET_DECAP, "Digital TV Network ULE/MLE Desencapsulation" }, - { MEDIA_ENT_F_IO_DTV, "Digital TV I/O" }, - { MEDIA_ENT_F_IO_VBI, "VBI I/O" }, - { MEDIA_ENT_F_IO_SWRADIO, "Software Radio I/O" }, - { MEDIA_ENT_F_IF_VID_DECODER, "IF-PLL Video Decoder" }, - { MEDIA_ENT_F_IF_AUD_DECODER, "IF-PLL Audio Decoder" }, - { MEDIA_ENT_F_AUDIO_CAPTURE, "Audio Capture" }, - { MEDIA_ENT_F_AUDIO_PLAYBACK, "Audio Playback" }, - { MEDIA_ENT_F_AUDIO_MIXER, "Audio Mixer" }, - { MEDIA_ENT_F_PROC_VIDEO_COMPOSER, "Video Composer" }, - { MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, "Video Pixel Formatter" }, - { MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, "Video Pixel Encoding Converter" }, - { MEDIA_ENT_F_PROC_VIDEO_LUT, "Video Look-Up Table" }, - { MEDIA_ENT_F_PROC_VIDEO_SCALER, "Video Scaler" }, - { MEDIA_ENT_F_PROC_VIDEO_STATISTICS, "Video Statistics" }, - { MEDIA_ENT_F_VID_MUX, "Video Muxer" }, - { MEDIA_ENT_F_VID_IF_BRIDGE, "Video Interface Bridge" }, - - { MEDIA_ENT_F_IO_V4L, "V4L2 I/O" }, - { MEDIA_ENT_F_CAM_SENSOR, "Camera Sensor" }, - { MEDIA_ENT_F_FLASH, "Flash Controller" }, - { MEDIA_ENT_F_LENS, "Lens Controller" }, - { MEDIA_ENT_F_ATV_DECODER, "Analog Video Decoder" }, - { MEDIA_ENT_F_TUNER, "Tuner" }, - { MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN, "Unknown" }, - { 0, NULL } -}; - -static std::string enttype2s(__u32 type) -{ - for (unsigned i = 0; entity_types_def[i].str; i++) - if (type == entity_types_def[i].flag) - return entity_types_def[i].str; - return "Unknown (" + num2s(type) + ")"; -} - -static const flag_def pad_flags_def[] = { - { MEDIA_PAD_FL_SINK, "Sink" }, - { MEDIA_PAD_FL_SOURCE, "Source" }, - { MEDIA_PAD_FL_MUST_CONNECT, "Must Connect" }, - { 0, NULL } -}; - -static std::string padflags2s(__u32 flags) -{ - return flags2s(flags, pad_flags_def); -} - -static const flag_def link_flags_def[] = { - { MEDIA_LNK_FL_ENABLED, "Enabled" }, - { MEDIA_LNK_FL_IMMUTABLE, "Immutable" }, - { MEDIA_LNK_FL_DYNAMIC, "Dynamic" }, - { 0, NULL } -}; - -static std::string linkflags2s(__u32 flags) -{ - switch (flags & MEDIA_LNK_FL_LINK_TYPE) { - case MEDIA_LNK_FL_DATA_LINK: - return "Data " + flags2s(flags, link_flags_def); - case MEDIA_LNK_FL_INTERFACE_LINK: - return "Interface " + flags2s(flags, link_flags_def); - default: - return "Unknown " + flags2s(flags, link_flags_def); - } -} - -static void mdev_info(node *node, int media_fd) -{ - struct media_device_info mdinfo; - struct stat sb; - int fd = node->g_fd(); - - if (media_fd < 0) - media_fd = fd; - else if (fd >= 0 && fstat(fd, &sb) == -1) { - fprintf(stderr, "failed to stat file\n"); - exit(1); - } - - if (ioctl(media_fd, MEDIA_IOC_DEVICE_INFO, &mdinfo)) - return; - - struct media_entity_desc &ent = node->entity; - bool found = false; - - printf("Media Driver Info:\n"); - printf("\tDriver name : %s\n", mdinfo.driver); - printf("\tModel : %s\n", mdinfo.model); - printf("\tSerial : %s\n", mdinfo.serial); - printf("\tBus info : %s\n", mdinfo.bus_info); - printf("\tMedia version : %d.%d.%d\n", - mdinfo.media_version >> 16, - (mdinfo.media_version >> 8) & 0xff, - mdinfo.media_version & 0xff); - printf("\tHardware revision: 0x%08x, %d\n", - mdinfo.hw_revision, mdinfo.hw_revision); - printf("\tDriver version : %d.%d.%d\n", - mdinfo.driver_version >> 16, - (mdinfo.driver_version >> 8) & 0xff, - mdinfo.driver_version & 0xff); - - if (node->is_media()) - return; - - memset(&ent, 0, sizeof(ent)); - ent.id = MEDIA_ENT_ID_FLAG_NEXT; - while (!ioctl(media_fd, MEDIA_IOC_ENUM_ENTITIES, &ent)) { - if (ent.dev.major == major(sb.st_rdev) && - ent.dev.minor == minor(sb.st_rdev)) { - found = true; - break; - } - ent.id |= MEDIA_ENT_ID_FLAG_NEXT; - } - if (!found) { - ent.id = 0; - return; - } - - printf("Entity Info:\n"); - printf("\tID : %u\n", ent.id); - printf("\tName : %s\n", ent.name); - printf("\tType : %s\n", enttype2s(ent.type).c_str()); - printf("\tFlags: %s\n", entflags2s(ent.flags).c_str()); - if (ent.flags & MEDIA_ENT_FL_DEFAULT) { - printf("\tMajor: %u\n", ent.dev.major); - printf("\tMinor: %u\n", ent.dev.minor); - } - - struct media_links_enum links_enum; - node->pads = new media_pad_desc[ent.pads]; - node->links = new media_link_desc[ent.links]; - - memset(&links_enum, 0, sizeof(links_enum)); - links_enum.entity = ent.id; - links_enum.pads = node->pads; - links_enum.links = node->links; - if (ioctl(media_fd, MEDIA_IOC_ENUM_LINKS, &links_enum)) - return; - - for (unsigned i = 0; i < ent.pads; i++) - printf("\tPad %u: %s\n", node->pads[i].index, - padflags2s(node->pads[i].flags).c_str()); - for (unsigned i = 0; i < ent.links; i++) - printf("\tLinks %u->%u: %s\n", - node->links[i].source.entity, - node->links[i].sink.entity, - linkflags2s(node->links[i].flags).c_str()); -} - - int main(int argc, char **argv) { int i; @@ -1356,9 +1157,9 @@ int main(int argc, char **argv) } } if (node.is_media()) - mdev_info(&node, -1); + mi_media_info_for_fd(node.g_fd(), -1); else if (media_fd >= 0) - mdev_info(&node, media_fd); + mi_media_info_for_fd(media_fd, node.g_fd()); printf("\nCompliance test for device %s%s:\n\n", device, direct ? "" : " (using libv4l2)"); diff --git a/utils/v4l2-compliance/v4l2-test-media.cpp b/utils/v4l2-compliance/v4l2-test-media.cpp index 15b8965292f8..08b5e078060e 100644 --- a/utils/v4l2-compliance/v4l2-test-media.cpp +++ b/utils/v4l2-compliance/v4l2-test-media.cpp @@ -124,10 +124,10 @@ int testMediaTopology(struct node *node) memset(v2_links, 0xff, topology.num_links * sizeof(*v2_links)); topology.ptr_links = (__u64)v2_links; fail_on_test(doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology)); - v2_ents = (media_v2_entity *)topology.ptr_entities; - v2_ifaces = (media_v2_interface *)topology.ptr_interfaces; - v2_pads = (media_v2_pad *)topology.ptr_pads; - v2_links = (media_v2_link *)topology.ptr_links; + fail_on_test(v2_ents != (media_v2_entity *)topology.ptr_entities); + fail_on_test(v2_ifaces != (media_v2_interface *)topology.ptr_interfaces); + fail_on_test(v2_pads != (media_v2_pad *)topology.ptr_pads); + fail_on_test(v2_links != (media_v2_link *)topology.ptr_links); for (unsigned i = 0; i < topology.num_entities; i++) { media_v2_entity &ent = v2_ents[i]; diff --git a/utils/v4l2-ctl/Makefile.am b/utils/v4l2-ctl/Makefile.am index b3ccfc8b6e9e..819e35fcf051 100644 --- a/utils/v4l2-ctl/Makefile.am +++ b/utils/v4l2-ctl/Makefile.am @@ -6,7 +6,8 @@ v4l2_ctl_SOURCES = v4l2-ctl.cpp v4l2-ctl.h v4l2-ctl-common.cpp v4l2-ctl-tuner.cp v4l2-ctl-io.cpp v4l2-ctl-stds.cpp v4l2-ctl-vidcap.cpp v4l2-ctl-vidout.cpp \ v4l2-ctl-overlay.cpp v4l2-ctl-vbi.cpp v4l2-ctl-selection.cpp v4l2-ctl-misc.cpp \ v4l2-ctl-streaming.cpp v4l2-ctl-sdr.cpp v4l2-ctl-edid.cpp v4l2-ctl-modes.cpp \ - v4l2-ctl-subdev.cpp v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp + v4l2-ctl-subdev.cpp v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp \ + media-info.cpp v4l2_ctl_CPPFLAGS = -I$(top_srcdir)/utils/common media-bus-format-names.h: ../../include/linux/media-bus-format.h diff --git a/utils/v4l2-ctl/media-info.cpp b/utils/v4l2-ctl/media-info.cpp new file mode 120000 index 000000000000..89676ff50494 --- /dev/null +++ b/utils/v4l2-ctl/media-info.cpp @@ -0,0 +1 @@ +../common/media-info.cpp \ No newline at end of file diff --git a/utils/v4l2-ctl/media-info.h b/utils/v4l2-ctl/media-info.h new file mode 120000 index 000000000000..c4612f3cbe13 --- /dev/null +++ b/utils/v4l2-ctl/media-info.h @@ -0,0 +1 @@ +../common/media-info.h \ No newline at end of file diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp index 02baf48cc9df..83408de306a8 100644 --- a/utils/v4l2-ctl/v4l2-ctl.cpp +++ b/utils/v4l2-ctl/v4l2-ctl.cpp @@ -39,6 +39,8 @@ #include <linux/media.h> +#include <media-info.h> + #include "v4l2-ctl.h" #ifdef HAVE_SYS_KLOG_H @@ -1225,254 +1227,6 @@ __u32 find_pixel_format(int fd, unsigned index, bool output, bool mplane) return fmt.pixelformat; } -static int get_media_fd(int fd) -{ - struct stat sb; - int media_fd = -1; - - if (fstat(fd, &sb) == -1) { - fprintf(stderr, "failed to stat file\n"); - exit(1); - } - - char media_path[100]; - if (snprintf(media_path, sizeof(media_path), "/sys/dev/char/%d:%d/device", - major(sb.st_rdev), minor(sb.st_rdev)) == -1) { - fprintf(stderr, "failed to create media file path\n"); - exit(1); - } - DIR *dp; - struct dirent *ep; - dp = opendir(media_path); - if (dp == NULL) { - perror("Couldn't open the directory"); - exit(1); - } - media_path[0] = 0; - while ((ep = readdir(dp))) { - if (!memcmp(ep->d_name, "media", 5) && isdigit(ep->d_name[5])) { - if (snprintf(media_path, sizeof(media_path), - "/dev/%s", ep->d_name) >= 0) - media_fd = open(media_path, O_RDWR); - break; - } - } - closedir(dp); - return media_fd; -} - -static bool is_subdevice(int fd) -{ - struct stat sb; - if (fstat(fd, &sb) == -1) { - fprintf(stderr, "failed to stat file\n"); - exit(1); - } - - char uevent_path[100]; - if (snprintf(uevent_path, sizeof(uevent_path), "/sys/dev/char/%d:%d/uevent", - major(sb.st_rdev), minor(sb.st_rdev)) == -1) { - fprintf(stderr, "failed to create uevent file path\n"); - exit(1); - } - - std::ifstream uevent_file(uevent_path); - if (uevent_file.fail()) { - fprintf(stderr, "failed to open %s\n", uevent_path); - exit(1); - } - - std::string line; - - while (std::getline(uevent_file, line)) { - if (line.compare(0, 8, "DEVNAME=")) - continue; - - static const char * devnames[] = { - "v4l-subdev", - "video", - "vbi", - "radio", - "swradio", - "v4l-touch", - NULL - }; - - for (size_t i = 0; devnames[i]; i++) { - size_t len = strlen(devnames[i]); - - if (!line.compare(8, len, devnames[i]) && isdigit(line[8+len])) { - uevent_file.close(); - return i == 0; - } - } - } - - uevent_file.close(); - - fprintf(stderr, "unknown device name\n"); - exit(1); -} - -static const flag_def entity_flags_def[] = { - { MEDIA_ENT_FL_DEFAULT, "default" }, - { MEDIA_ENT_FL_CONNECTOR, "connector" }, - { 0, NULL } -}; - -static std::string entflags2s(__u32 flags) -{ - return flags2s(flags, entity_flags_def); -} - -static const flag_def entity_types_def[] = { - { MEDIA_ENT_F_UNKNOWN, "Unknown" }, - { MEDIA_ENT_F_DTV_DEMOD, "Digital TV Demodulator" }, - { MEDIA_ENT_F_TS_DEMUX, "Transport Stream Demuxer" }, - { MEDIA_ENT_F_DTV_CA, "Digital TV Conditional Access" }, - { MEDIA_ENT_F_DTV_NET_DECAP, "Digital TV Network ULE/MLE Desencapsulation" }, - { MEDIA_ENT_F_IO_DTV, "Digital TV I/O" }, - { MEDIA_ENT_F_IO_VBI, "VBI I/O" }, - { MEDIA_ENT_F_IO_SWRADIO, "Software Radio I/O" }, - { MEDIA_ENT_F_IF_VID_DECODER, "IF-PLL Video Decoder" }, - { MEDIA_ENT_F_IF_AUD_DECODER, "IF-PLL Audio Decoder" }, - { MEDIA_ENT_F_AUDIO_CAPTURE, "Audio Capture" }, - { MEDIA_ENT_F_AUDIO_PLAYBACK, "Audio Playback" }, - { MEDIA_ENT_F_AUDIO_MIXER, "Audio Mixer" }, - { MEDIA_ENT_F_PROC_VIDEO_COMPOSER, "Video Composer" }, - { MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, "Video Pixel Formatter" }, - { MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, "Video Pixel Encoding Converter" }, - { MEDIA_ENT_F_PROC_VIDEO_LUT, "Video Look-Up Table" }, - { MEDIA_ENT_F_PROC_VIDEO_SCALER, "Video Scaler" }, - { MEDIA_ENT_F_PROC_VIDEO_STATISTICS, "Video Statistics" }, - { MEDIA_ENT_F_VID_MUX, "Video Muxer" }, - { MEDIA_ENT_F_VID_IF_BRIDGE, "Video Interface Bridge" }, - - { MEDIA_ENT_F_IO_V4L, "V4L2 I/O" }, - { MEDIA_ENT_F_CAM_SENSOR, "Camera Sensor" }, - { MEDIA_ENT_F_FLASH, "Flash Controller" }, - { MEDIA_ENT_F_LENS, "Lens Controller" }, - { MEDIA_ENT_F_ATV_DECODER, "Analog Video Decoder" }, - { MEDIA_ENT_F_TUNER, "Tuner" }, - { MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN, "Unknown" }, - { 0, NULL } -}; - -static std::string enttype2s(__u32 type) -{ - for (unsigned i = 0; entity_types_def[i].str; i++) - if (type == entity_types_def[i].flag) - return entity_types_def[i].str; - return "Unknown (" + num2s(type) + ")"; -} - -static const flag_def pad_flags_def[] = { - { MEDIA_PAD_FL_SINK, "Sink" }, - { MEDIA_PAD_FL_SOURCE, "Source" }, - { MEDIA_PAD_FL_MUST_CONNECT, "Must Connect" }, - { 0, NULL } -}; - -static std::string padflags2s(__u32 flags) -{ - return flags2s(flags, pad_flags_def); -} - -static const flag_def link_flags_def[] = { - { MEDIA_LNK_FL_ENABLED, "Enabled" }, - { MEDIA_LNK_FL_IMMUTABLE, "Immutable" }, - { MEDIA_LNK_FL_DYNAMIC, "Dynamic" }, - { 0, NULL } -}; - -static std::string linkflags2s(__u32 flags) -{ - switch (flags & MEDIA_LNK_FL_LINK_TYPE) { - case MEDIA_LNK_FL_DATA_LINK: - return "Data " + flags2s(flags, link_flags_def); - case MEDIA_LNK_FL_INTERFACE_LINK: - return "Interface " + flags2s(flags, link_flags_def); - default: - return "Unknown " + flags2s(flags, link_flags_def); - } -} - -static void mdev_info(int fd, int media_fd) -{ - struct media_device_info mdinfo; - struct stat sb; - - if (fstat(fd, &sb) == -1) { - fprintf(stderr, "failed to stat file\n"); - exit(1); - } - - if (ioctl(media_fd, MEDIA_IOC_DEVICE_INFO, &mdinfo)) - return; - - struct media_entity_desc ent; - bool found = false; - - printf("Media Driver Info:\n"); - printf("\tDriver name : %s\n", mdinfo.driver); - printf("\tModel : %s\n", mdinfo.model); - printf("\tSerial : %s\n", mdinfo.serial); - printf("\tBus info : %s\n", mdinfo.bus_info); - printf("\tMedia version : %d.%d.%d\n", - mdinfo.media_version >> 16, - (mdinfo.media_version >> 8) & 0xff, - mdinfo.media_version & 0xff); - printf("\tHardware revision: 0x%08x, %d\n", - mdinfo.hw_revision, mdinfo.hw_revision); - printf("\tDriver version : %d.%d.%d\n", - mdinfo.driver_version >> 16, - (mdinfo.driver_version >> 8) & 0xff, - mdinfo.driver_version & 0xff); - - memset(&ent, 0, sizeof(ent)); - ent.id = MEDIA_ENT_ID_FLAG_NEXT; - while (!ioctl(media_fd, MEDIA_IOC_ENUM_ENTITIES, &ent)) { - if (ent.dev.major == major(sb.st_rdev) && - ent.dev.minor == minor(sb.st_rdev)) { - found = true; - break; - } - ent.id |= MEDIA_ENT_ID_FLAG_NEXT; - } - if (!found) - return; - - printf("Entity Info:\n"); - printf("\tID : %u\n", ent.id); - printf("\tName : %s\n", ent.name); - printf("\tType : %s\n", enttype2s(ent.type).c_str()); - printf("\tFlags: %s\n", entflags2s(ent.flags).c_str()); - if (ent.flags & MEDIA_ENT_FL_DEFAULT) { - printf("\tMajor: %u\n", ent.dev.major); - printf("\tMinor: %u\n", ent.dev.minor); - } - - struct media_links_enum links_enum; - struct media_pad_desc pads[ent.pads]; - struct media_link_desc links[ent.links]; - - memset(&links_enum, 0, sizeof(links_enum)); - links_enum.entity = ent.id; - links_enum.pads = pads; - links_enum.links = links; - if (ioctl(media_fd, MEDIA_IOC_ENUM_LINKS, &links_enum)) - return; - - for (unsigned i = 0; i < ent.pads; i++) - printf("\tPad %u: %s\n", pads[i].index, - padflags2s(pads[i].flags).c_str()); - for (unsigned i = 0; i < ent.links; i++) - printf("\tLinks %u->%u: %s\n", - links[i].source.entity, - links[i].sink.entity, - linkflags2s(links[i].flags).c_str()); -} - int main(int argc, char **argv) { int i; @@ -1645,7 +1399,7 @@ int main(int argc, char **argv) exit(1); } verbose = options[OptVerbose]; - is_subdev = is_subdevice(fd); + is_subdev = mi_is_subdevice(fd); if (is_subdev) options[OptUseWrapper] = 0; @@ -1666,7 +1420,7 @@ int main(int argc, char **argv) if (capabilities & V4L2_CAP_DEVICE_CAPS) capabilities = vcap.device_caps; - media_fd = get_media_fd(fd); + media_fd = mi_get_media_fd(fd); priv_magic = (capabilities & V4L2_CAP_EXT_PIX_FORMAT) ? V4L2_PIX_FMT_PRIV_MAGIC : 0; @@ -1764,7 +1518,7 @@ int main(int argc, char **argv) } } if (options[OptGetDriverInfo] && media_fd >= 0) - mdev_info(fd, media_fd); + mi_media_info_for_fd(media_fd, fd); /* Set options */ _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits