aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2020-03-19 10:19:09 +0100
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2020-03-21 10:32:21 +0100
commit6a9d69a9df0e4166eb9e61e5376b2bbe3781b492 (patch)
treebc38ce1fa83e147f3ef4fa36bf617c2ef7f091ee
parente4f587a68cf5e896ba1ff1f205281ba870c7d58e (diff)
cec: add support to list/set connectors
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--include/linux/cec.h15
-rw-r--r--utils/cec-ctl/cec-ctl.cpp82
2 files changed, 91 insertions, 6 deletions
diff --git a/include/linux/cec.h b/include/linux/cec.h
index 16d96133..2d3bac54 100644
--- a/include/linux/cec.h
+++ b/include/linux/cec.h
@@ -405,6 +405,17 @@ struct cec_connector_info {
};
};
+/**
+ * struct cec_enum_connector_info - enumerate connector info
+ * @conn_info: connector info
+ * @index: get connector info at index @index
+ */
+struct cec_enum_connector_info {
+ struct cec_connector_info conn_info;
+ __u32 index;
+ char name[32];
+};
+
/* Events */
/* Event that occurs when the adapter state changes */
@@ -513,8 +524,10 @@ struct cec_event {
#define CEC_G_MODE _IOR('a', 8, __u32)
#define CEC_S_MODE _IOW('a', 9, __u32)
-/* Get the connector info */
+/* Get and set the connector info */
#define CEC_ADAP_G_CONNECTOR_INFO _IOR('a', 10, struct cec_connector_info)
+#define CEC_ADAP_S_CONNECTOR_INFO _IOW('a', 11, struct cec_connector_info)
+#define CEC_ADAP_ENUM_CONNECTOR_INFO _IOWR('a', 12, struct cec_enum_connector_info)
/*
* The remainder of this header defines all CEC messages and operands.
diff --git a/utils/cec-ctl/cec-ctl.cpp b/utils/cec-ctl/cec-ctl.cpp
index ec7dc5ec..9fad0cf9 100644
--- a/utils/cec-ctl/cec-ctl.cpp
+++ b/utils/cec-ctl/cec-ctl.cpp
@@ -63,6 +63,7 @@ static char options[512];
case is used to retrieve a setting. */
enum Option {
OptSetAdapter = 'a',
+ OptSetConnInfo = 'c',
OptClear = 'C',
OptSetDevice = 'd',
OptSetDriver = 'D',
@@ -104,6 +105,7 @@ enum Option {
OptReplyToFollowers,
OptRawMsg,
OptListDevices,
+ OptListConnectors,
OptTimeout,
OptMonitorTime,
OptMonitorPin,
@@ -162,6 +164,7 @@ static struct option long_options[] = {
{ "phys-addr-from-edid-poll", required_argument, 0, OptPhysAddrFromEDIDPoll },
{ "phys-addr-from-edid", required_argument, 0, OptPhysAddrFromEDID },
{ "phys-addr", required_argument, 0, OptPhysAddr },
+ { "set-conn-info", required_argument, 0, OptSetConnInfo },
{ "vendor-id", required_argument, 0, OptVendorID },
{ "cec-version-1.4", no_argument, 0, OptCECVersion1_4 },
{ "allow-unreg-fallback", no_argument, 0, OptAllowUnregFallback },
@@ -188,6 +191,7 @@ static struct option long_options[] = {
{ "show-raw", no_argument, 0, OptShowRaw },
{ "show-topology", no_argument, 0, OptShowTopology },
{ "list-devices", no_argument, 0, OptListDevices },
+ { "list-connectors", no_argument, 0, OptListConnectors },
{ "poll", no_argument, 0, OptPoll },
{ "rc-tv-profile-1", no_argument, 0, OptRcTVProfile1 },
{ "rc-tv-profile-2", no_argument, 0, OptRcTVProfile2 },
@@ -242,6 +246,12 @@ static void usage(void)
" -E, --phys-addr-from-edid-poll <path>\n"
" Continuously poll the EDID file for changes, and update the\n"
" physical address whenever there is a change\n"
+ " -c, --set-conn-info none | card-no=<card>,conn-id=<id>\n"
+ " Associate the CEC adapter with the given connector.\n"
+ " Only valid if CEC_CAP_PHYS_ADDR is set.\n"
+ " none: disassociate the CEC adapter.\n"
+ " card-no,conn-id: associate the CEC adapter with the DRM\n"
+ " device with this card number and connector ID.\n"
" -o, --osd-name <name> Use this OSD name\n"
" -V, --vendor-id <id> Use this vendor ID\n"
" -l, --logical-address Show first configured logical address\n"
@@ -269,6 +279,7 @@ static void usage(void)
" --raw-msg Transmit the message without validating it (must be root)\n"
" --timeout <ms> Set the reply timeout in milliseconds (default is 1000 ms)\n"
" --list-devices List all cec devices\n"
+ " --list-connectors List all connectors that can be used with -c\n"
"\n"
" --tv This is a TV\n"
" --record This is a recording and playback device\n"
@@ -1758,6 +1769,7 @@ int main(int argc, char **argv)
const char *driver = NULL;
const char *adapter = NULL;
const struct cec_msg_args *opt;
+ struct cec_connector_info conn_info = {};
msg_vec msgs;
char short_options[26 * 2 * 2 + 1];
__u32 timeout = 1000;
@@ -1848,6 +1860,39 @@ int main(int argc, char **argv)
case OptMonitorTime:
monitor_time = strtoul(optarg, NULL, 0);
break;
+ case OptSetConnInfo: {
+ static const char *arg_names[] = {
+ "card-no",
+ "conn-id",
+ NULL
+ };
+ char *value, *subs = optarg;
+
+ if (!optarg)
+ break;
+
+ while (*subs != '\0') {
+ if (!strcmp(subs, "none")) {
+ conn_info.type = CEC_CONNECTOR_TYPE_NO_CONNECTOR;
+ break;
+ }
+
+ switch (cec_parse_subopt(&subs, arg_names, &value)) {
+ case 0:
+ conn_info.type = CEC_CONNECTOR_TYPE_DRM;
+ conn_info.drm.card_no = strtoul(value, NULL, 0);
+ break;
+ case 1:
+ conn_info.type = CEC_CONNECTOR_TYPE_DRM;
+ conn_info.drm.connector_id = strtoul(value, NULL, 0);
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ break;
+ }
case OptIgnore: {
bool all_la = !strncmp(optarg, "all", 3);
bool all_opcodes = true;
@@ -2325,7 +2370,7 @@ int main(int argc, char **argv)
node.available_log_addrs = caps.available_log_addrs;
bool set_phys_addr = options[OptPhysAddr] || options[OptPhysAddrFromEDID] ||
- options[OptPhysAddrFromEDIDPoll];
+ options[OptPhysAddrFromEDIDPoll] || options[OptSetConnInfo];
if (set_phys_addr && !(node.caps & CEC_CAP_PHYS_ADDR))
fprintf(stderr, "The CEC adapter doesn't allow setting the physical address manually, ignore this option.\n\n");
@@ -2382,9 +2427,14 @@ int main(int argc, char **argv)
doioctl(&node, CEC_ADAP_S_LOG_ADDRS, &laddrs);
}
- if (set_phys_addr)
+ if (options[OptSetConnInfo])
+ doioctl(&node, CEC_ADAP_S_CONNECTOR_INFO, &conn_info);
+ else if (set_phys_addr)
doioctl(&node, CEC_ADAP_S_PHYS_ADDR, &phys_addr);
+ doioctl(&node, CEC_ADAP_G_CAPS, &caps);
+ node.caps = caps.capabilities;
+
doioctl(&node, CEC_ADAP_G_PHYS_ADDR, &phys_addr);
if (set_log_addrs) {
@@ -2477,12 +2527,36 @@ int main(int argc, char **argv)
phys_addrs[la] = (phys_addr << 8) | la;
}
+ if (options[OptListConnectors]) {
+ struct cec_enum_connector_info c = {};
+ bool first = true;
+
+ while (!doioctl(&node, CEC_ADAP_ENUM_CONNECTOR_INFO, &c)) {
+ if (first) {
+ printf("Available connectors:\n");
+ first = false;
+ }
+ switch (c.conn_info.type) {
+ case CEC_CONNECTOR_TYPE_DRM:
+ printf("\tDRM: card-no=%u,conn-id=%u (%s)\n",
+ c.conn_info.drm.card_no,
+ c.conn_info.drm.connector_id,
+ c.name);
+ break;
+ }
+ c.index++;
+ }
+ if (!first)
+ printf("\n");
+ }
+
if (!options[OptSkipInfo]) {
struct cec_connector_info conn_info = {};
doioctl(&node, CEC_ADAP_G_CONNECTOR_INFO, &conn_info);
cec_driver_info(caps, laddrs, phys_addr, conn_info);
+ printf("\n");
}
if (node.num_log_addrs == 0) {
@@ -2491,11 +2565,9 @@ int main(int argc, char **argv)
options[OptPhysAddrFromEDIDPoll])
goto skip_la;
if (warn_if_unconfigured)
- fprintf(stderr, "\nAdapter is unconfigured, please configure it first.\n");
+ fprintf(stderr, "Adapter is unconfigured, please configure it first.\n");
return 0;
}
- if (!options[OptSkipInfo])
- printf("\n");
if (!options[OptFrom])
from = laddrs.log_addr[0] & 0xf;

Privacy Policy