From: Hans Verkuil <hans.verk...@cisco.com>

Preliminary ARC and CDC support. Untested and experimental!

Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
---
 .../DocBook/media/v4l/cec-ioc-adap-g-caps.xml      |  10 ++
 Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml |  36 ++++
 Documentation/cec.txt                              |  75 ++++++++
 drivers/media/cec.c                                | 198 ++++++++++++++++++++-
 drivers/media/pci/cobalt/cobalt-driver.c           |   4 +-
 drivers/media/pci/cobalt/cobalt-v4l2.c             |  37 ++++
 include/media/cec.h                                |  11 ++
 include/uapi/linux/cec.h                           |   5 +
 8 files changed, 372 insertions(+), 4 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml 
b/Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml
index 7b22bf3..648ad3c 100644
--- a/Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml
+++ b/Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml
@@ -135,6 +135,16 @@
            <entry>This CEC adapter is an HDMI source, &ie; it has an HDMI 
output
            connector.</entry>
          </row>
+         <row>
+           <entry><constant>CEC_CAP_ARC</constant></entry>
+           <entry>0x00000080</entry>
+           <entry>This adapter supports the Audio Return Channel 
protocol.</entry>
+         </row>
+         <row>
+           <entry><constant>CEC_CAP_CDC_HPD</constant></entry>
+           <entry>0x00000100</entry>
+           <entry>This adapter supports the hotplug detect protocol over 
CDC.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml 
b/Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml
index c6260ae..b08b0c4 100644
--- a/Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml
@@ -187,6 +187,42 @@ The follower can of course always call 
&CEC-TRANSMIT;.</para>
        &cs-def;
        <tbody valign="top">
          <row>
+           <entry><constant>CEC_MSG_INITIATE_ARC</constant></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>CEC_MSG_TERMINATE_ARC</constant></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>CEC_MSG_REQUEST_ARC_INITIATION</constant></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>CEC_MSG_REQUEST_ARC_TERMINATION</constant></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>CEC_MSG_REPORT_ARC_INITIATED</constant></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>CEC_MSG_REPORT_ARC_TERMINATED</constant></entry>
+           <entry>If <constant>CEC_CAP_ARC</constant> is not set, then just 
pass
+           it on to userspace for processing. However, if 
<constant>CEC_CAP_ARC</constant> is
+           set, then the core framework processes this message and userspace 
will
+           not see it, not even in passthrough mode.</entry>
+         </row>
+         <row>
+           <entry><constant>CEC_MSG_CDC_MESSAGE</constant></entry>
+           <entry>If <constant>CEC_CAP_CDC_HPD</constant> is not set, then 
just pass
+           it on to userspace for processing. Do the same if the CDC command 
is not
+           one of <constant>CEC_MSG_CDC_HPD_REPORT_STATE</constant> or
+           <constant>CEC_MSG_CDC_HPD_SET_STATE</constant>. Else the core 
framework
+           processes this message and userspace will not see it, not even in 
passthrough
+           mode.</entry>
+         </row>
+         <row>
            <entry><constant>CEC_MSG_GET_CEC_VERSION</constant></entry>
            <entry>When in passthrough mode this message has to be handled by 
userspace,
            otherwise the core will return the CEC version that was set with 
&CEC-ADAP-S-LOG-ADDRS;.</entry>
diff --git a/Documentation/cec.txt b/Documentation/cec.txt
index 9d62a02..52bf1f3 100644
--- a/Documentation/cec.txt
+++ b/Documentation/cec.txt
@@ -217,6 +217,16 @@ struct cec_adap_ops {

        /* High-level CEC message callback */
        int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
+
+       /* High-level CDC Hotplug Detect callbacks */
+       u8 (*source_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state);
+       void (*sink_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state, u8 
cdc_hpd_error);
+
+       /* High-level Audio Return Channel callbacks */
+       int (*sink_initiate_arc)(struct cec_adapter *adap);
+       int (*sink_terminate_arc)(struct cec_adapter *adap);
+       int (*source_arc_initiated)(struct cec_adapter *adap);
+       int (*source_arc_terminated)(struct cec_adapter *adap);
 };

 The received() callback allows the driver to optionally handle a newly
@@ -229,6 +239,62 @@ callback. If it doesn't want to handle this message, then 
it should return
 -ENOMSG, otherwise the CEC framework assumes it processed this message and
 it will not no anything with it.

+The other callbacks deal with two CEC features: CDC Hotplug Detect and
+Audio Return Channel. Here the framework takes care of handling these
+messages and it calls the callbacks to notify the driver when it needs
+to take action.
+
+CDC Hotplug Support
+-------------------
+
+A source received a hotplug state change message:
+
+       u8 (*source_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state);
+
+A source received a CEC_MSG_CDC_HPD_SET_STATE message. The framework will
+reply with a CEC_MSG_CDC_HPD_REPORT_STATE message and this callback is used
+to fill in the HPD Error Code Operand of the REPORT_STATE message. In addition,
+the driver can act in this callback on the hotplug state change.
+
+Only implement if CEC_CAP_CDC_HPD is set.
+
+A sink received a hotplug report state message:
+
+       void (*sink_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state, u8 
cdc_hpd_error);
+
+A sink received a CEC_MSG_CDC_HPD_REPORT_STATE message. This callback will
+do anything necessary to implement this hotplug change. The two arguments
+are the HPD Error State and HPD Error Code Operands from the 
CEC_MSG_CDC_HPD_REPORT_STATE
+message.
+
+
+Audio Return Channel Support
+----------------------------
+
+Called if a CEC_MSG_INITIATE_ARC message is received by an HDMI sink.
+This callback should start sending audio over the audio return channel. If
+successful it should return 0.
+
+       int (*sink_initiate_arc)(struct cec_adapter *adap);
+
+Called if a CEC_MSG_TERMINATE_ARC message is received by an HDMI sink.
+This callback should stop sending audio over the audio return channel. If
+successful it should return 0.
+
+       void (*sink_terminate_arc)(struct cec_adapter *adap);
+
+Called if a CEC_MSG_REPORT_ARC_INITIATED message is received by an
+HDMI source. This callback can be used to enable receiving audio from
+the audio return channel.
+
+       void (*source_arc_initiated)(struct cec_adapter *adap);
+
+Called if a CEC_MSG_REPORT_ARC_TERMINATED message is received by an
+HDMI source. This callback can be used to disable receiving audio from
+the audio return channel.
+
+       void (*source_arc_terminated)(struct cec_adapter *adap);
+

 CEC framework functions
 -----------------------
@@ -274,6 +340,15 @@ unconfiguring. This function will just return if the 
physical address is
 invalid. Once the physical address becomes valid, then the framework will
 attempt to claim these logical addresses.

+u8 cec_sink_cdc_hpd(struct cec_adapter *adap, u8 input_port, u8 cdc_hpd_state);
+
+If an HDMI receiver supports hotplug signalling over CDC (CEC_CAP_CDC_HPD is
+set), then the driver should call this function whenever the hotplug state
+changes for an input. This call will send an appropriate CDC message over
+the CEC line. It returns CEC_OP_HPD_ERROR_NONE on success, if the adapter
+is unconfigured it returns CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE and if
+the cec_transmit fails it returns CEC_OP_HPD_ERROR_OTHER.
+
 void cec_log_status(struct cec_adapter *adap);

 This logs the current CEC adapter status in the kernel log. Useful for
diff --git a/drivers/media/cec.c b/drivers/media/cec.c
index 55d5b86..09db8a6 100644
--- a/drivers/media/cec.c
+++ b/drivers/media/cec.c
@@ -160,6 +160,42 @@ u16 cec_phys_addr_parent(u16 phys_addr)
 }
 EXPORT_SYMBOL_GPL(cec_phys_addr_parent);

+/*
+ * Two physical addresses are adjacent if they have a direct link.
+ * So 0.0.0.0 and 1.0.0.0 are adjacent, but not 0.0.0.0 and 1.1.0.0.
+ * And 2.3.0.0 and 2.3.1.0 are adjacent, but not 2.3.0.0 and 2.4.0.0.
+ *
+ * In other words, the two addresses share the same prefix, but then
+ * one has a zero and the other has a non-zero value. And the remaining
+ * components are all zero for both.
+ */
+static bool cec_pa_are_adjacent(const struct cec_adapter *adap, u16 pa1, u16 
pa2)
+{
+       u16 mask = 0xf000;
+       int i;
+
+       if (pa1 == CEC_PHYS_ADDR_INVALID || pa2 == CEC_PHYS_ADDR_INVALID)
+               return false;
+       for (i = 0; i < 3; i++) {
+               if ((pa1 & mask) != (pa2 & mask))
+                       break;
+               mask = (mask >> 4) | 0xf000;
+       }
+       if ((pa1 & ~mask) || (pa2 & ~mask))
+               return false;
+       if (!(pa1 & mask) ^ !(pa2 & mask))
+               return true;
+       return false;
+}
+
+static bool cec_la_are_adjacent(const struct cec_adapter *adap, u8 la1, u8 la2)
+{
+       u16 pa1 = adap->phys_addrs[la1];
+       u16 pa2 = adap->phys_addrs[la2];
+
+       return cec_pa_are_adjacent(adap, pa1, pa2);
+}
+
 static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr)
 {
        int i;
@@ -1034,7 +1070,9 @@ static int cec_receive_notify(struct cec_adapter *adap, 
struct cec_msg *msg,
        int la_idx = cec_log_addr2idx(adap, dest_laddr);
        bool is_directed = la_idx >= 0;
        bool from_unregistered = init_laddr == 0xf;
+       u16 cdc_phys_addr;
        struct cec_msg tx_cec_msg = { };
+       u8 *tx_msg = tx_cec_msg.msg;

        dprintk(1, "cec_receive_notify: %*ph\n", msg->len, msg->msg);

@@ -1045,12 +1083,57 @@ static int cec_receive_notify(struct cec_adapter *adap, 
struct cec_msg *msg,
        }

        /*
-        * REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and
+        * ARC, CDC and REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and
         * CEC_MSG_USER_CONTROL_RELEASED messages always have to be
         * handled by the CEC core, even if the passthrough mode is on.
-        * The others are just ignored if passthrough mode is on.
+        * ARC and CDC messages will never be seen even if passthrough is
+        * on, but the others are just passed on normally after we processed
+        * them.
         */
        switch (msg->msg[1]) {
+       case CEC_MSG_INITIATE_ARC:
+       case CEC_MSG_TERMINATE_ARC:
+       case CEC_MSG_REQUEST_ARC_INITIATION:
+       case CEC_MSG_REQUEST_ARC_TERMINATION:
+       case CEC_MSG_REPORT_ARC_INITIATED:
+       case CEC_MSG_REPORT_ARC_TERMINATED:
+               /* ARC messages are never passed through if CAP_ARC is set */
+
+               /* Abort/ignore if ARC is not supported */
+               if (!(adap->capabilities & CEC_CAP_ARC)) {
+                       /* Just abort if nobody is listening */
+                       if (is_directed && !is_reply && !adap->cec_follower &&
+                           !adap->follower_cnt)
+                               return cec_feature_abort(adap, msg);
+                       goto skip_processing;
+               }
+               /* Ignore if addressing is wrong */
+               if (is_broadcast || from_unregistered)
+                       return 0;
+               break;
+
+       case CEC_MSG_CDC_MESSAGE:
+               switch (msg->msg[4]) {
+               case CEC_MSG_CDC_HPD_REPORT_STATE:
+               case CEC_MSG_CDC_HPD_SET_STATE:
+                       /*
+                        * CDC_HPD messages are never passed through if
+                        * CAP_CDC_HPD is set
+                        */
+
+                       /* Ignore if CDC_HPD is not supported */
+                       if (!(adap->capabilities & CEC_CAP_CDC_HPD))
+                               goto skip_processing;
+                       /* or the addressing is wrong */
+                       if (!is_broadcast)
+                               return 0;
+                       break;
+               default:
+                       /* Other CDC messages are ignored */
+                       goto skip_processing;
+               }
+               break;
+
        case CEC_MSG_GET_CEC_VERSION:
        case CEC_MSG_GIVE_DEVICE_VENDOR_ID:
        case CEC_MSG_ABORT:
@@ -1186,6 +1269,97 @@ static int cec_receive_notify(struct cec_adapter *adap, 
struct cec_msg *msg,
                        return cec_report_features(adap, la_idx);
                return 0;

+       case CEC_MSG_REQUEST_ARC_INITIATION:
+               if (!adap->is_source ||
+                   !cec_la_are_adjacent(adap, dest_laddr, init_laddr))
+                       return cec_feature_refused(adap, msg);
+               cec_msg_initiate_arc(&tx_cec_msg, false);
+               return cec_transmit_msg(adap, &tx_cec_msg, false);
+
+       case CEC_MSG_REQUEST_ARC_TERMINATION:
+               if (!adap->is_source ||
+                   !cec_la_are_adjacent(adap, dest_laddr, init_laddr))
+                       return cec_feature_refused(adap, msg);
+               cec_msg_terminate_arc(&tx_cec_msg, false);
+               return cec_transmit_msg(adap, &tx_cec_msg, false);
+
+       case CEC_MSG_INITIATE_ARC:
+               if (adap->is_source ||
+                   !cec_la_are_adjacent(adap, dest_laddr, init_laddr))
+                       return cec_feature_refused(adap, msg);
+               if (call_op(adap, sink_initiate_arc))
+                       return 0;
+               cec_msg_report_arc_initiated(&tx_cec_msg);
+               return cec_transmit_msg(adap, &tx_cec_msg, false);
+
+       case CEC_MSG_TERMINATE_ARC:
+               if (adap->is_source ||
+                   !cec_la_are_adjacent(adap, dest_laddr, init_laddr))
+                       return cec_feature_refused(adap, msg);
+               call_void_op(adap, sink_terminate_arc);
+               cec_msg_report_arc_terminated(&tx_cec_msg);
+               return cec_transmit_msg(adap, &tx_cec_msg, false);
+
+       case CEC_MSG_REPORT_ARC_INITIATED:
+               if (!adap->is_source ||
+                   !cec_la_are_adjacent(adap, dest_laddr, init_laddr))
+                       return cec_feature_refused(adap, msg);
+               call_void_op(adap, source_arc_initiated);
+               return 0;
+
+       case CEC_MSG_REPORT_ARC_TERMINATED:
+               if (!adap->is_source ||
+                   !cec_la_are_adjacent(adap, dest_laddr, init_laddr))
+                       return cec_feature_refused(adap, msg);
+               call_void_op(adap, source_arc_terminated);
+               return 0;
+
+       case CEC_MSG_CDC_MESSAGE: {
+               unsigned int shift;
+               unsigned int input_port;
+
+               cdc_phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+               if (!cec_pa_are_adjacent(adap, cdc_phys_addr, adap->phys_addr))
+                       return 0;
+
+               switch (msg->msg[4]) {
+               case CEC_MSG_CDC_HPD_REPORT_STATE:
+                       /*
+                        * Ignore if we're not a sink or the message comes from
+                        * an upstream device.
+                        */
+                       if (adap->is_source || cdc_phys_addr <= adap->phys_addr)
+                               return 0;
+                       adap->ops->sink_cdc_hpd(adap, msg->msg[5] >> 4, 
msg->msg[5] & 0xf);
+                       return 0;
+               case CEC_MSG_CDC_HPD_SET_STATE:
+                       /* Ignore if we're not a source */
+                       if (!adap->is_source)
+                               return 0;
+                       break;
+               default:
+                       return 0;
+               }
+
+               input_port = msg->msg[5] >> 4;
+               for (shift = 0; shift < 16; shift += 4) {
+                       if (cdc_phys_addr & (0xf000 >> shift))
+                               continue;
+                       cdc_phys_addr |= input_port << (12 - shift);
+                       break;
+               }
+               if (cdc_phys_addr != adap->phys_addr)
+                       return 0;
+
+               tx_cec_msg.len = 6;
+               /* broadcast reply */
+               tx_msg[0] = (adap->log_addrs.log_addr[0] << 4) | 0xf;
+               cec_msg_cdc_hpd_report_state(&tx_cec_msg,
+                            msg->msg[5] & 0xf,
+                            adap->ops->source_cdc_hpd(adap, msg->msg[5] & 
0xf));
+               return cec_transmit_msg(adap, &tx_cec_msg, false);
+       }
+
        default:
                /*
                 * Unprocessed messages are aborted if userspace isn't doing
@@ -1681,6 +1855,26 @@ void cec_log_status(struct cec_adapter *adap, struct 
cec_fh *fh)
 }
 EXPORT_SYMBOL_GPL(cec_log_status);

+/*
+ * Called by drivers to update the CDC HPD state of an input port.
+ */
+u8 cec_sink_cdc_hpd(struct cec_adapter *adap, u8 input_port, u8 cdc_hpd_state)
+{
+       struct cec_msg msg = { };
+       int err;
+
+       if (!adap->is_configured)
+               return CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE;
+
+       msg.msg[0] = (adap->log_addrs.log_addr[0] << 4) | 0xf;
+       cec_msg_cdc_hpd_set_state(&msg, input_port, cdc_hpd_state);
+       err = cec_transmit_msg(adap, &msg, false);
+       if (err)
+               return CEC_OP_HPD_ERROR_OTHER;
+       return CEC_OP_HPD_ERROR_NONE;
+}
+EXPORT_SYMBOL_GPL(cec_sink_cdc_hpd);
+

 /* CEC file operations */

diff --git a/drivers/media/pci/cobalt/cobalt-driver.c 
b/drivers/media/pci/cobalt/cobalt-driver.c
index dff92ef..54ef6cc 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -517,10 +517,10 @@ static void cobalt_stream_struct_init(struct cobalt 
*cobalt)
 static int cobalt_create_cec_adap(struct cobalt_stream *s)
 {
        u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS |
-               CEC_CAP_PASSTHROUGH | CEC_CAP_RC;
+               CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_ARC;

        if (s->is_output)
-               caps |= CEC_CAP_IS_SOURCE;
+               caps |= CEC_CAP_IS_SOURCE | CEC_CAP_CDC_HPD;
        s->cec_adap = cec_create_adapter(&cobalt_cec_adap_ops,
                                 s, s->vdev.name, caps, 1,
                                 &s->cobalt->pci_dev->dev);
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c 
b/drivers/media/pci/cobalt/cobalt-v4l2.c
index 1c00748..47460338 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -1195,6 +1195,38 @@ static int cobalt_cec_adap_transmit(struct cec_adapter 
*adap, u8 attempts,
                                attempts, signal_free_time, msg);
 }

+static u8 cobalt_cec_cdc_hpd(struct cec_adapter *adap, u8 cdc_hpd_state)
+{
+       switch (cdc_hpd_state) {
+       case CEC_OP_HPD_STATE_EDID_DISABLE:
+       case CEC_OP_HPD_STATE_EDID_ENABLE:
+       case CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE:
+               return CEC_OP_HPD_ERROR_NONE;
+       case CEC_OP_HPD_STATE_CP_EDID_DISABLE:
+       case CEC_OP_HPD_STATE_CP_EDID_ENABLE:
+       case CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE:
+       default:
+               return CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE;
+       }
+}
+
+static int cobalt_sink_initiate_arc(struct cec_adapter *adap)
+{
+       return 0;
+}
+
+static void cobalt_sink_terminate_arc(struct cec_adapter *adap)
+{
+}
+
+static void cobalt_source_arc_initiated(struct cec_adapter *adap)
+{
+}
+
+static void cobalt_source_arc_terminated(struct cec_adapter *adap)
+{
+}
+
 static int cobalt_received(struct cec_adapter *adap, struct cec_msg *msg)
 {
        struct cec_msg reply;
@@ -1223,6 +1255,11 @@ const struct cec_adap_ops cobalt_cec_adap_ops = {
        .adap_enable = cobalt_cec_adap_enable,
        .adap_log_addr = cobalt_cec_adap_log_addr,
        .adap_transmit = cobalt_cec_adap_transmit,
+       .source_cdc_hpd = cobalt_cec_cdc_hpd,
+       .sink_initiate_arc = cobalt_sink_initiate_arc,
+       .sink_terminate_arc = cobalt_sink_terminate_arc,
+       .source_arc_initiated = cobalt_source_arc_initiated,
+       .source_arc_terminated = cobalt_source_arc_terminated,
        .received = cobalt_received,
 };

diff --git a/include/media/cec.h b/include/media/cec.h
index 899bccd..6ac367b 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -108,6 +108,16 @@ struct cec_adap_ops {

        /* High-level CEC message callback */
        int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
+
+       /* High-level CDC Hotplug Detect callbacks */
+       u8 (*source_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state);
+       void (*sink_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state, u8 
cdc_hpd_error);
+
+       /* High-level Audio Return Channel callbacks */
+       int (*sink_initiate_arc)(struct cec_adapter *adap);
+       void (*sink_terminate_arc)(struct cec_adapter *adap);
+       void (*source_arc_initiated)(struct cec_adapter *adap);
+       void (*source_arc_terminated)(struct cec_adapter *adap);
 };

 /*
@@ -194,6 +204,7 @@ void cec_s_available_log_addrs(struct cec_adapter *adap, u8 
available_las);
 int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
                     bool block);

+u8 cec_sink_cdc_hpd(struct cec_adapter *adap, u8 input_port, u8 cdc_hpd_state);
 void cec_log_status(struct cec_adapter *adap, struct cec_fh *fh);

 /* Called by the adapter */
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
index cf3d883..9ad3279 100644
--- a/include/uapi/linux/cec.h
+++ b/include/uapi/linux/cec.h
@@ -226,6 +226,7 @@ static inline bool cec_msg_status_is_ok(const struct 
cec_msg *msg)
 #define CEC_CAP_TRANSMIT       (1 << 2)
 /*
  * Passthrough all messages instead of processing them.
+ * Note: ARC and CDC messages are always processed.
  */
 #define CEC_CAP_PASSTHROUGH    (1 << 3)
 /* Supports remote control */
@@ -234,6 +235,10 @@ static inline bool cec_msg_status_is_ok(const struct 
cec_msg *msg)
 #define CEC_CAP_MONITOR_ALL    (1 << 5)
 /* Is a source */
 #define CEC_CAP_IS_SOURCE      (1 << 6)
+/* Supports ARC */
+#define CEC_CAP_ARC            (1 << 7)
+/* Supports CDC HPD */
+#define CEC_CAP_CDC_HPD                (1 << 8)

 /**
  * struct cec_caps - CEC capabilities structure.
-- 
2.7.0

Reply via email to