/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
* cec - HDMI Consumer Electronics Control public header
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
#include <linux/string.h>
#define CEC_MAX_MSG_SIZE 16
* struct cec_msg - CEC message structure.
* @tx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the
* driver when the message transmission has finished.
* @rx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the
* driver when the message was received.
* @len: Length in bytes of the message.
* @timeout: The timeout (in ms) that is used to timeout CEC_RECEIVE.
* Set to 0 if you want to wait forever. This timeout can also be
* used with CEC_TRANSMIT as the timeout for waiting for a reply.
* If 0, then it will use a 1 second timeout instead of waiting
* forever as is done with CEC_RECEIVE.
* @sequence: The framework assigns a sequence number to messages that are
* sent. This can be used to track replies to previously sent
* @msg: The message payload.
* @reply: This field is ignored with CEC_RECEIVE and is only used by
* CEC_TRANSMIT. If non-zero, then wait for a reply with this
* opcode. Set to CEC_MSG_FEATURE_ABORT if you want to wait for
* a possible ABORT reply. If there was an error when sending the
* msg or FeatureAbort was returned, then reply is set to 0.
* If reply is non-zero upon return, then len/msg are set to
* If reply is zero upon return and status has the
* CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to
* the received feature abort message.
* If reply is zero upon return and status has the
* CEC_TX_STATUS_MAX_RETRIES bit set, then no reply was seen at
* all. If reply is non-zero for CEC_TRANSMIT and the message is a
* broadcast, then -EINVAL is returned.
* if reply is non-zero, then timeout is set to 1000 (the required
* maximum response time).
* @rx_status: The message receive status bits. Set by the driver.
* @tx_status: The message transmit status bits. Set by the driver.
* @tx_arb_lost_cnt: The number of 'Arbitration Lost' events. Set by the driver.
* @tx_nack_cnt: The number of 'Not Acknowledged' events. Set by the driver.
* @tx_low_drive_cnt: The number of 'Low Drive Detected' events. Set by the
* @tx_error_cnt: The number of 'Error' events. Set by the driver.
__u8 msg[CEC_MAX_MSG_SIZE];
* cec_msg_initiator - return the initiator's logical address.
* @msg: the message structure
static __inline__ __u8 cec_msg_initiator(const struct cec_msg *msg)
* cec_msg_destination - return the destination's logical address.
* @msg: the message structure
static __inline__ __u8 cec_msg_destination(const struct cec_msg *msg)
return msg->msg[0] & 0xf;
* cec_msg_opcode - return the opcode of the message, -1 for poll
* @msg: the message structure
static __inline__ int cec_msg_opcode(const struct cec_msg *msg)
return msg->len > 1 ? msg->msg[1] : -1;
* cec_msg_is_broadcast - return true if this is a broadcast message.
* @msg: the message structure
static __inline__ int cec_msg_is_broadcast(const struct cec_msg *msg)
return (msg->msg[0] & 0xf) == 0xf;
* cec_msg_init - initialize the message structure.
* @msg: the message structure
* @initiator: the logical address of the initiator
* @destination:the logical address of the destination (0xf for broadcast)
* The whole structure is zeroed, the len field is set to 1 (i.e. a poll
* message) and the initiator and destination are filled in.
static __inline__ void cec_msg_init(struct cec_msg *msg,
__u8 initiator, __u8 destination)
memset(msg, 0, sizeof(*msg));
msg->msg[0] = (initiator << 4) | destination;
* cec_msg_set_reply_to - fill in destination/initiator in a reply message.
* @msg: the message structure for the reply
* @orig: the original message structure
* Set the msg destination to the orig initiator and the msg initiator to the
* orig destination. Note that msg and orig may be the same pointer, in which
* case the change is done in place.
static __inline__ void cec_msg_set_reply_to(struct cec_msg *msg,
/* The destination becomes the initiator and vice versa */
msg->msg[0] = (cec_msg_destination(orig) << 4) |
msg->reply = msg->timeout = 0;
/* cec_msg flags field */
#define CEC_MSG_FL_REPLY_TO_FOLLOWERS (1 << 0)
#define CEC_MSG_FL_RAW (1 << 1)
/* cec_msg tx/rx_status field */
#define CEC_TX_STATUS_OK (1 << 0)
#define CEC_TX_STATUS_ARB_LOST (1 << 1)
#define CEC_TX_STATUS_NACK (1 << 2)
#define CEC_TX_STATUS_LOW_DRIVE (1 << 3)
#define CEC_TX_STATUS_ERROR (1 << 4)
#define CEC_TX_STATUS_MAX_RETRIES (1 << 5)
#define CEC_TX_STATUS_ABORTED (1 << 6)
#define CEC_TX_STATUS_TIMEOUT (1 << 7)
#define CEC_RX_STATUS_OK (1 << 0)
#define CEC_RX_STATUS_TIMEOUT (1 << 1)
#define CEC_RX_STATUS_FEATURE_ABORT (1 << 2)
#define CEC_RX_STATUS_ABORTED (1 << 3)
static __inline__ int cec_msg_status_is_ok(const struct cec_msg *msg)
if (msg->tx_status && !(msg->tx_status & CEC_TX_STATUS_OK))
if (msg->rx_status && !(msg->rx_status & CEC_RX_STATUS_OK))
if (!msg->tx_status && !msg->rx_status)
return !(msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT);
#define CEC_LOG_ADDR_INVALID 0xff
#define CEC_PHYS_ADDR_INVALID 0xffff
* The maximum number of logical addresses one device can be assigned to.
* The CEC 2.0 spec allows for only 2 logical addresses at the moment. The
* Analog Devices CEC hardware supports 3. So let's go wild and go for 4.
#define CEC_MAX_LOG_ADDRS 4
/* The logical addresses defined by CEC 2.0 */
#define CEC_LOG_ADDR_TV 0
#define CEC_LOG_ADDR_RECORD_1 1
#define CEC_LOG_ADDR_RECORD_2 2
#define CEC_LOG_ADDR_TUNER_1 3
#define CEC_LOG_ADDR_PLAYBACK_1 4
#define CEC_LOG_ADDR_AUDIOSYSTEM 5
#define CEC_LOG_ADDR_TUNER_2 6
#define CEC_LOG_ADDR_TUNER_3 7
#define CEC_LOG_ADDR_PLAYBACK_2 8
#define CEC_LOG_ADDR_RECORD_3 9
#define CEC_LOG_ADDR_TUNER_4 10
#define CEC_LOG_ADDR_PLAYBACK_3 11
#define CEC_LOG_ADDR_BACKUP_1 12
#define CEC_LOG_ADDR_BACKUP_2 13
#define CEC_LOG_ADDR_SPECIFIC 14
#define CEC_LOG_ADDR_UNREGISTERED 15 /* as initiator address */
#define CEC_LOG_ADDR_BROADCAST 15 /* as destination address */
/* The logical address types that the CEC device wants to claim */
#define CEC_LOG_ADDR_TYPE_TV 0
#define CEC_LOG_ADDR_TYPE_RECORD 1
#define CEC_LOG_ADDR_TYPE_TUNER 2
#define CEC_LOG_ADDR_TYPE_PLAYBACK 3
#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM 4
#define CEC_LOG_ADDR_TYPE_SPECIFIC 5
#define CEC_LOG_ADDR_TYPE_UNREGISTERED 6
* Switches should use UNREGISTERED.
* Processors should use SPECIFIC.
#define CEC_LOG_ADDR_MASK_TV (1 << CEC_LOG_ADDR_TV)
#define CEC_LOG_ADDR_MASK_RECORD ((1 << CEC_LOG_ADDR_RECORD_1) | \
(1 << CEC_LOG_ADDR_RECORD_2) | \
(1 << CEC_LOG_ADDR_RECORD_3))
#define CEC_LOG_ADDR_MASK_TUNER ((1 << CEC_LOG_ADDR_TUNER_1) | \
(1 << CEC_LOG_ADDR_TUNER_2) | \
(1 << CEC_LOG_ADDR_TUNER_3) | \
(1 << CEC_LOG_ADDR_TUNER_4))
#define CEC_LOG_ADDR_MASK_PLAYBACK ((1 << CEC_LOG_ADDR_PLAYBACK_1) | \
(1 << CEC_LOG_ADDR_PLAYBACK_2) | \
(1 << CEC_LOG_ADDR_PLAYBACK_3))
#define CEC_LOG_ADDR_MASK_AUDIOSYSTEM (1 << CEC_LOG_ADDR_AUDIOSYSTEM)
#define CEC_LOG_ADDR_MASK_BACKUP ((1 << CEC_LOG_ADDR_BACKUP_1) | \
(1 << CEC_LOG_ADDR_BACKUP_2))
#define CEC_LOG_ADDR_MASK_SPECIFIC (1 << CEC_LOG_ADDR_SPECIFIC)
#define CEC_LOG_ADDR_MASK_UNREGISTERED (1 << CEC_LOG_ADDR_UNREGISTERED)
static __inline__ int cec_has_tv(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_TV;
static __inline__ int cec_has_record(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_RECORD;
static __inline__ int cec_has_tuner(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_TUNER;
static __inline__ int cec_has_playback(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_PLAYBACK;
static __inline__ int cec_has_audiosystem(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_AUDIOSYSTEM;
static __inline__ int cec_has_backup(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_BACKUP;
static __inline__ int cec_has_specific(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_SPECIFIC;
static __inline__ int cec_is_unregistered(__u16 log_addr_mask)
return log_addr_mask & CEC_LOG_ADDR_MASK_UNREGISTERED;
static __inline__ int cec_is_unconfigured(__u16 log_addr_mask)
return log_addr_mask == 0;
* Use this if there is no vendor ID (CEC_G_VENDOR_ID) or if the vendor ID
* should be disabled (CEC_S_VENDOR_ID)
#define CEC_VENDOR_ID_NONE 0xffffffff
/* The message handling modes */
/* Modes for initiator */
#define CEC_MODE_NO_INITIATOR (0x0 << 0)
#define CEC_MODE_INITIATOR (0x1 << 0)
#define CEC_MODE_EXCL_INITIATOR (0x2 << 0)
#define CEC_MODE_INITIATOR_MSK 0x0f
#define CEC_MODE_NO_FOLLOWER (0x0 << 4)
#define CEC_MODE_FOLLOWER (0x1 << 4)
#define CEC_MODE_EXCL_FOLLOWER (0x2 << 4)
#define CEC_MODE_EXCL_FOLLOWER_PASSTHRU (0x3 << 4)
#define CEC_MODE_MONITOR_PIN (0xd << 4)
#define CEC_MODE_MONITOR (0xe << 4)
#define CEC_MODE_MONITOR_ALL (0xf << 4)
#define CEC_MODE_FOLLOWER_MSK 0xf0
/* Userspace has to configure the physical address */
#define CEC_CAP_PHYS_ADDR (1 << 0)
/* Userspace has to configure the logical addresses */
#define CEC_CAP_LOG_ADDRS (1 << 1)
/* Userspace can transmit messages (and thus become follower as well) */
#define CEC_CAP_TRANSMIT (1 << 2)
* Passthrough all messages instead of processing them.
#define CEC_CAP_PASSTHROUGH (1 << 3)
/* Supports remote control */
#define CEC_CAP_RC (1 << 4)
/* Hardware can monitor all messages, not just directed and broadcast. */
#define CEC_CAP_MONITOR_ALL (1 << 5)
/* Hardware can use CEC only if the HDMI HPD pin is high. */
#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.
* @driver: name of the CEC device driver.
* @name: name of the CEC device. @driver + @name must be unique.
* @available_log_addrs: number of available logical addresses.
* @capabilities: capabilities of the CEC adapter.
* @version: version of the CEC adapter framework.
__u32 available_log_addrs;
* struct cec_log_addrs - CEC logical addresses structure.
* @log_addr: the claimed logical addresses. Set by the driver.
* @log_addr_mask: current logical address mask. Set by the driver.
* @cec_version: the CEC version that the adapter should implement. Set by the
* @num_log_addrs: how many logical addresses should be claimed. Set by the
* @vendor_id: the vendor ID of the device. Set by the caller.
* @osd_name: the OSD name of the device. Set by the caller.
* @primary_device_type: the primary device type for each logical address.
* @log_addr_type: the logical address types. Set by the caller.
* @all_device_types: CEC 2.0: all device types represented by the logical
* address. Set by the caller.
* @features: CEC 2.0: The logical address features. Set by the caller.
__u8 log_addr[CEC_MAX_LOG_ADDRS];
__u8 primary_device_type[CEC_MAX_LOG_ADDRS];
__u8 log_addr_type[CEC_MAX_LOG_ADDRS];
__u8 all_device_types[CEC_MAX_LOG_ADDRS];
__u8 features[CEC_MAX_LOG_ADDRS][12];
/* Allow a fallback to unregistered */
#define CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK (1 << 0)
/* Passthrough RC messages to the input subsystem */
#define CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU (1 << 1)
/* CDC-Only device: supports only CDC messages */
#define CEC_LOG_ADDRS_FL_CDC_ONLY (1 << 2)
* struct cec_drm_connector_info - tells which drm connector is
* associated with the CEC adapter.
* @card_no: drm card number
* @connector_id: drm connector ID
struct cec_drm_connector_info {
#define CEC_CONNECTOR_TYPE_NO_CONNECTOR 0
#define CEC_CONNECTOR_TYPE_DRM 1
* struct cec_connector_info - tells if and which connector is
* associated with the CEC adapter.
* @type: connector type (if any)
* @drm: drm connector info
struct cec_connector_info {
struct cec_drm_connector_info drm;
/* Event that occurs when the adapter state changes */
#define CEC_EVENT_STATE_CHANGE 1
* This event is sent when messages are lost because the application
* didn't empty the message queue in time
#define CEC_EVENT_LOST_MSGS 2
#define CEC_EVENT_PIN_CEC_LOW 3
#define CEC_EVENT_PIN_CEC_HIGH 4
#define CEC_EVENT_PIN_HPD_LOW 5
#define CEC_EVENT_PIN_HPD_HIGH 6
#define CEC_EVENT_PIN_5V_LOW 7
#define CEC_EVENT_PIN_5V_HIGH 8
#define CEC_EVENT_FL_INITIAL_STATE (1 << 0)
#define CEC_EVENT_FL_DROPPED_EVENTS (1 << 1)
* struct cec_event_state_change - used when the CEC adapter changes state.
* @phys_addr: the current physical address
* @log_addr_mask: the current logical address mask
* @have_conn_info: if non-zero, then HDMI connector information is available.
* This field is only valid if CEC_CAP_CONNECTOR_INFO is set. If that
* capability is set and @have_conn_info is zero, then that indicates
* that the HDMI connector device is not instantiated, either because
* the HDMI driver is still configuring the device or because the HDMI
struct cec_event_state_change {
* struct cec_event_lost_msgs - tells you how many messages were lost.
* @lost_msgs: how many messages were lost.
struct cec_event_lost_msgs {
* struct cec_event - CEC event structure
* @ts: the timestamp of when the event was sent.
* @state_change: the event payload for CEC_EVENT_STATE_CHANGE.
* @lost_msgs: the event payload for CEC_EVENT_LOST_MSGS.
* @raw: array to pad the union.
struct cec_event_state_change state_change;
struct cec_event_lost_msgs lost_msgs;
/* Adapter capabilities */
#define CEC_ADAP_G_CAPS _IOWR('a', 0, struct cec_caps)
* phys_addr is either 0 (if this is the CEC root device)
* or a valid physical address obtained from the sink's EDID
* as read by this CEC device (if this is a source device)
* or a physical address obtained and modified from a sink
* EDID and used for a sink CEC device.
* If nothing is connected, then phys_addr is 0xffff.
* See HDMI 1.4b, section 8.7 (Physical Address).
* The CEC_ADAP_S_PHYS_ADDR ioctl may not be available if that is handled
#define CEC_ADAP_G_PHYS_ADDR _IOR('a', 1, __u16)
#define CEC_ADAP_S_PHYS_ADDR _IOW('a', 2, __u16)
* Configure the CEC adapter. It sets the device type and which
* logical types it will try to claim. It will return which
* logical addresses it could actually claim.
* An error is returned if the adapter is disabled or if there
* is no physical address assigned.
#define CEC_ADAP_G_LOG_ADDRS _IOR('a', 3, struct cec_log_addrs)