diff --git a/include/linux/cec.h b/include/linux/cec.h index c747e375..0b8b3362 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -317,6 +317,8 @@ static __inline__ int cec_is_unconfigured(__u16 log_addr_mask) #define CEC_CAP_NEEDS_HPD (1 << 6) /* Hardware can monitor CEC pin transitions */ #define CEC_CAP_MONITOR_PIN (1 << 7) +/* CEC_ADAP_G_CONNECTOR_INFO is available */ +#define CEC_CAP_CONNECTOR_INFO (1 << 8) /** * struct cec_caps - CEC capabilities structure. @@ -402,6 +404,7 @@ struct cec_log_addrs { struct cec_event_state_change { __u16 phys_addr; __u16 log_addr_mask; + __u16 have_conn_info; }; /** @@ -413,6 +416,27 @@ struct cec_event_lost_msgs { }; /** + * struct cec_event_connector - tells if and which connector is associated + * with the CEC adapter. + * @card_no: drm card number + * @connector_id: drm connector ID + */ +struct cec_drm_connector_info { + __u32 card_no; + __u32 connector_id; +}; + +#define CEC_CONNECTOR_TYPE_NO_CONNECTOR 0 +#define CEC_CONNECTOR_TYPE_DRM 1 +struct cec_connector_info { + __u32 type; + union { + struct cec_drm_connector_info drm; + __u32 raw[16]; + }; +}; + +/** * struct cec_event - CEC event structure * @ts: the timestamp of when the event was sent. * @event: the event. @@ -476,6 +500,9 @@ struct cec_event { #define CEC_G_MODE _IOR('a', 8, __u32) #define CEC_S_MODE _IOW('a', 9, __u32) +/* Gets the connector info */ +#define CEC_ADAP_G_CONNECTOR_INFO _IOR('a', 10, struct cec_connector_info) + /* * The remainder of this header defines all CEC messages and operands. * The format matters since it the cec-ctl utility parses it to generate diff --git a/utils/cec-ctl/cec-ctl.cpp b/utils/cec-ctl/cec-ctl.cpp index 0b262409..79c8ba5a 100644 --- a/utils/cec-ctl/cec-ctl.cpp +++ b/utils/cec-ctl/cec-ctl.cpp @@ -1049,10 +1049,11 @@ static void log_event(struct cec_event &ev, bool show) case CEC_EVENT_STATE_CHANGE: pa = ev.state_change.phys_addr; if (show) - printf("Event: State Change: PA: %x.%x.%x.%x, LA mask: 0x%04x\n", + printf("Event: State Change: PA: %x.%x.%x.%x, LA mask: 0x%04x, Conn Info: %s\n", pa >> 12, (pa >> 8) & 0xf, (pa >> 4) & 0xf, pa & 0xf, - ev.state_change.log_addr_mask); + ev.state_change.log_addr_mask, + ev.state_change.have_conn_info ? "yes" : "no"); break; case CEC_EVENT_LOST_MSGS: if (show) @@ -1635,6 +1636,8 @@ static bool wait_for_pwr_state(struct node &node, unsigned from, bool on, unsign cec_msg_init(&msg, from, CEC_LOG_ADDR_TV); cec_msg_give_device_power_status(&msg, true); ret = doioctl(&node, CEC_TRANSMIT, &msg); + cec_ops_report_power_status(&msg, &pwr); + fprintf(stderr, "Give Device Power Status Transmit: %s (from %d on %d pwr %d rxstat %d)\n", strerror(ret), from, on, pwr, msg.rx_status & CEC_RX_STATUS_OK); if (ret == ENONET) return !on; if (ret) { @@ -1656,6 +1659,7 @@ static void test_power_cycle(struct node &node, unsigned from) struct cec_msg msg; unsigned tries; unsigned no_reply; + __u16 pa; __u8 wakeup_la; int ret; @@ -1687,6 +1691,7 @@ static void test_power_cycle(struct node &node, unsigned from) exit(1); } } + printf("TV is in Standby\n"); } for (unsigned iter = 0; iter <= 21; iter++) { @@ -1703,10 +1708,17 @@ static void test_power_cycle(struct node &node, unsigned from) exit(1); } tries = no_reply = 0; - while (!wait_for_pwr_state(node, from, true, no_reply)) { - sleep(1); + for (;;) { + doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs); + from = CEC_LOG_ADDR_UNREGISTERED; + if (laddrs.num_log_addrs) + from = laddrs.log_addr[0] & 0xf; + if (from != CEC_LOG_ADDR_UNREGISTERED && + wait_for_pwr_state(node, from, true, no_reply)) + break; if (++tries > 60) break; + sleep(1); } if (tries > 60 && wakeup_la == CEC_LOG_ADDR_UNREGISTERED) { @@ -1731,9 +1743,12 @@ static void test_power_cycle(struct node &node, unsigned from) printf("Woke up TV after %d seconds using Image View On from LA %s", tries, la2s(wakeup_la)); if (no_reply) - printf(" (%d Give Device Power Status messages ignored", no_reply); + printf(" (%d Give Device Power Status messages ignored)", no_reply); printf("\n"); + doioctl(&node, CEC_ADAP_G_PHYS_ADDR, &pa); + printf("\tPhysical Address: %x.%x.%x.%x\n", + cec_phys_addr_exp(pa)); doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs); from = laddrs.log_addr[0] & 0xf; @@ -1746,21 +1761,29 @@ static void test_power_cycle(struct node &node, unsigned from) } tries = no_reply = 0; - while (!wait_for_pwr_state(node, from, false, no_reply)) { - sleep(1); + for (;;) { + doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs); + if (!laddrs.num_log_addrs) + break; + if (wait_for_pwr_state(node, from, true, no_reply)) + break; if (++tries > 60) { fprintf(stderr, "Could not put display in standby\n"); exit(1); } + sleep(1); } printf("Put TV in Standby after %d seconds from LA %s", tries, la2s(from)); if (no_reply) - printf(" (%d Give Device Power Status messages ignored", no_reply); + printf(" (%d Give Device Power Status messages ignored)", no_reply); printf("\n"); unsigned secs = iter <= 10 ? iter : 10 + 10 * (iter - 10); printf("Sleep %d seconds\n", secs); sleep(secs); + doioctl(&node, CEC_ADAP_G_PHYS_ADDR, &pa); + printf("\tPhysical Address: %x.%x.%x.%x\n", + cec_phys_addr_exp(pa)); } } @@ -2619,8 +2642,22 @@ int main(int argc, char **argv) phys_addrs[la] = (phys_addr << 8) | la; } - if (!options[OptSkipInfo]) + if (!options[OptSkipInfo]) { + struct cec_connector_info conn_info; + cec_driver_info(caps, laddrs, phys_addr); + if (!doioctl(&node, CEC_ADAP_G_CONNECTOR_INFO, &conn_info)) { + switch (conn_info.type) { + case CEC_CONNECTOR_TYPE_NO_CONNECTOR: + printf("\tNo Connector\n"); + break; + case CEC_CONNECTOR_TYPE_DRM: + printf("\tDRM Connector : card %u, connector %u\n", + conn_info.drm.card_no, conn_info.drm.connector_id); + break; + } + } + } if (node.num_log_addrs == 0) { if (options[OptMonitor] || options[OptMonitorAll] || diff --git a/utils/common/cec-info.cpp b/utils/common/cec-info.cpp index 31fb09fd..ff647044 100644 --- a/utils/common/cec-info.cpp +++ b/utils/common/cec-info.cpp @@ -33,6 +33,8 @@ static std::string caps2s(unsigned caps) s += "\t\tNeeds HPD\n"; if (caps & CEC_CAP_MONITOR_PIN) s += "\t\tMonitor Pin\n"; + if (caps & CEC_CAP_CONNECTOR_INFO) + s += "\t\tConnector Info\n"; return s; }