2.11. ioctls CEC_RECEIVE 和 CEC_TRANSMIT

2.11.1. 名称

CEC_RECEIVE, CEC_TRANSMIT - 接收或发送 CEC 消息

2.11.2. 概要

CEC_RECEIVE

int ioctl(int fd, CEC_RECEIVE, struct cec_msg *argp)

CEC_TRANSMIT

int ioctl(int fd, CEC_TRANSMIT, struct cec_msg *argp)

2.11.3. 参数

fd

open() 返回的文件描述符。

argp

指向 struct cec_msg 的指针。

2.11.4. 描述

要接收 CEC 消息,应用程序必须填写结构体 cec_msgtimeout 字段,并将其传递给 ioctl CEC_RECEIVE。如果文件描述符处于非阻塞模式,并且没有待接收的消息,则它将返回 -1 并将 errno 设置为 EAGAIN 错误代码。如果文件描述符处于阻塞模式,并且 timeout 为非零值,并且在 timeout 毫秒内没有收到消息,则它将返回 -1 并将 errno 设置为 ETIMEDOUT 错误代码。

收到的消息可以是:

  1. 从另一个 CEC 设备接收的消息(sequence 字段将为 0, tx_status 将为 0,rx_status 将为非零)。

  2. 先前非阻塞发送的发送结果(sequence 字段将为非零,tx_status 将为非零,rx_status 将为 0)。

  3. 先前非阻塞发送的回复(sequence 字段将为非零,tx_status 将为 0,rx_status 将为非零)。

要发送 CEC 消息,应用程序必须填写结构体 cec_msg 并将其传递给 ioctl CEC_TRANSMIT。只有在设置了 CEC_CAP_TRANSMIT 时,ioctl CEC_TRANSMIT 才可用。如果发送队列中没有更多空间,则它将返回 -1 并将 errno 设置为 EBUSY 错误代码。发送队列有足够的空间容纳 18 条消息(大约 1 秒的 2 字节消息)。请注意,CEC 内核框架还会回复核心消息(请参阅 核心消息处理),因此完全填满发送队列不是一个好主意。

如果文件描述符处于非阻塞模式,则发送将返回 0,并且一旦发送完成,就可以通过 ioctl CEC_RECEIVE 获取发送结果。如果非阻塞发送还指定了等待回复,则回复将在以后的消息中到达。sequence 字段可用于将发送结果和回复与原始发送相关联。

通常,当物理地址无效(例如,由于断开连接)时调用 ioctl CEC_TRANSMIT 将返回 ENONET

但是,CEC 规范允许在物理地址无效时从“未注册”向“TV”发送消息,因为某些电视在进入待机状态或切换到其他输入时会将其 HDMI 连接器的热插拔检测引脚拉低。

当热插拔检测引脚变低时,EDID 消失,因此物理地址也消失,但电缆仍然连接,并且 CEC 仍然有效。为了检测/唤醒设备,允许从发起者 0xf(“未注册”)向目标 0(“TV”)发送轮询和“图像/文本视图开启”消息。

type cec_msg
struct cec_msg

__u64

tx_ts

消息的最后一个字节发送时的纳秒时间戳。时间戳取自 CLOCK_MONOTONIC 时钟。要从用户空间访问同一时钟,请使用 clock_gettime()

__u64

rx_ts

消息的最后一个字节接收时的纳秒时间戳。时间戳取自 CLOCK_MONOTONIC 时钟。要从用户空间访问同一时钟,请使用 clock_gettime()

__u32

len

消息的长度。对于 ioctl CEC_TRANSMIT,由应用程序填写。驱动程序将为 ioctl CEC_RECEIVE 填写此字段。对于 ioctl CEC_TRANSMIT,如果设置了 reply,驱动程序将用回复消息的长度填写此字段。

__u32

timeout

以毫秒为单位的超时。这是设备在超时之前等待接收消息的时间。如果设置为 0,则当由 ioctl CEC_RECEIVE 调用时,它将无限期等待。如果设置为 0,并且由 ioctl CEC_TRANSMIT 调用,则如果 reply 为非零值,则它将被替换为 1000,如果 reply 为 0,则将被忽略。

__u32

sequence

对于所有已发送的消息,CEC 框架会自动分配一个非零的序列号。当 CEC 框架为非阻塞发送排队发送结果时使用它。这允许应用程序将接收到的消息与原始发送相关联。

此外,如果非阻塞发送将等待回复(即 timeout 不为 0),则回复的 sequence 字段将设置为原始发送的序列值。这允许应用程序将接收到的消息与原始发送相关联。

__u32

flags

标志。有关可用标志的列表,请参阅 struct cec_msg 的标志

__u8

msg[16]

消息有效负载。对于 ioctl CEC_TRANSMIT,由应用程序填写。驱动程序将为 ioctl CEC_RECEIVE 填写此字段。对于 ioctl CEC_TRANSMIT,如果设置了 timeout,驱动程序将用回复消息的有效负载填写此字段。

__u8

reply

等待此消息被回复。如果 reply 为 0 并且 timeout 为 0,则在发送消息后不等待回复,而是返回。ioctl CEC_RECEIVE 忽略此字段。专门允许 reply 为 0(这是 Feature Abort 消息的操作码)和 timeout 为非零值的情况,以便能够发送消息并等待长达 timeout 毫秒的 Feature Abort 回复。在这种情况下,rx_status 将设置为 CEC_RX_STATUS_TIMEOUTCEC_RX_STATUS_FEATURE_ABORT

如果发送器消息为 CEC_MSG_INITIATE_ARC,则 replyCEC_MSG_REPORT_ARC_INITIATEDCEC_MSG_REPORT_ARC_TERMINATED 的处理方式不同:这两个值都将匹配所有可能的回复。原因是 CEC_MSG_INITIATE_ARC 消息是唯一具有除 Feature Abort 之外的两个可能回复的 CEC 消息。reply 字段将使用实际回复更新,以便它与接收到的消息的内容同步。

__u8

rx_status

接收消息的状态位。有关可能的状态值,请参阅 CEC 接收状态

__u8

tx_status

传输消息的状态位。有关可能的状态值,请参阅 CEC 发送状态。当在非阻塞模式下调用 ioctl CEC_TRANSMIT 时,如果传输开始,则此字段将为 0;如果传输结果立即知晓,则此字段将为非 0。后者的情况发生在尝试向自己发送 Poll 消息时。这会导致 CEC_TX_STATUS_NACK,而实际上并未发送 Poll 消息。

__u8

tx_arb_lost_cnt

导致仲裁丢失错误的传输尝试次数计数器。仅当硬件支持此功能时才会设置此计数器,否则始终为 0。此计数器仅当设置了 CEC_TX_STATUS_ARB_LOST 状态位时才有效。

__u8

tx_nack_cnt

导致未确认错误的传输尝试次数计数器。仅当硬件支持此功能时才会设置此计数器,否则始终为 0。此计数器仅当设置了 CEC_TX_STATUS_NACK 状态位时才有效。

__u8

tx_low_drive_cnt

导致仲裁丢失错误的传输尝试次数计数器。仅当硬件支持此功能时才会设置此计数器,否则始终为 0。此计数器仅当设置了 CEC_TX_STATUS_LOW_DRIVE 状态位时才有效。

__u8

tx_error_cnt

除仲裁丢失或未确认之外的其他传输错误的计数器。仅当硬件支持此功能时才会设置此计数器,否则始终为 0。此计数器仅当设置了 CEC_TX_STATUS_ERROR 状态位时才有效。

struct cec_msg 的标志

CEC_MSG_FL_REPLY_TO_FOLLOWERS

1

如果 CEC 传输需要回复,则默认情况下,该回复仅发送到调用 ioctl CEC_TRANSMIT 的文件句柄。如果设置了此标志,则回复也会发送给所有关注者(如果有)。如果调用 ioctl CEC_TRANSMIT 的文件句柄也是关注者,则该文件句柄将收到两次回复:一次作为 ioctl CEC_TRANSMIT 的结果,另一次通过 ioctl CEC_RECEIVE

CEC_MSG_FL_RAW

2

通常,CEC 消息在传输之前会进行验证。如果在调用 ioctl CEC_TRANSMIT 时设置了此标志,则不会进行验证,并且消息将按原样传输。这在调试 CEC 问题时非常有用。仅当进程具有 CAP_SYS_RAWIO 功能时才允许使用此标志。如果未设置该标志,则返回 EPERM 错误代码。

CEC_MSG_FL_REPLY_VENDOR_ID

4

仅当设置了 CEC_CAP_REPLY_VENDOR_ID 功能时,此标志才可用。如果设置了此标志,则回复应由 CEC_MSG_VENDOR_COMMAND_WITH_ID 操作码(后跟消息的字节 1-4 中的供应商 ID)和 struct cec_msg reply 字段组成。

请注意,这假定供应商 ID 之后的字节是供应商特定的操作码。

此标志使等待供应商命令的回复更容易。

CEC 发送状态

CEC_TX_STATUS_OK

0x01

消息已成功发送。这与 CEC_TX_STATUS_MAX_RETRIES 是互斥的。如果早期的尝试在传输最终成功之前遇到失败,则仍可以设置其他位。

CEC_TX_STATUS_ARB_LOST

0x02

CEC 线仲裁丢失,即另一个具有更高优先级的传输同时开始。可选状态,并非所有硬件都能检测到此错误情况。

CEC_TX_STATUS_NACK

0x04

消息未被确认。请注意,某些硬件无法区分“未确认”状态和其他错误情况,即传输的结果仅为 OK 或 FAIL。在这种情况下,当传输失败时将返回此状态。

CEC_TX_STATUS_LOW_DRIVE

0x08

在 CEC 总线上检测到低驱动。这表示关注者检测到总线上有错误,并请求重新传输。可选状态,并非所有硬件都能检测到此错误情况。

CEC_TX_STATUS_ERROR

0x10

发生了一些错误。这用于不符合 CEC_TX_STATUS_ARB_LOSTCEC_TX_STATUS_LOW_DRIVE 的任何错误,无论是由于硬件无法判断发生哪种错误,还是因为硬件测试了除这两种之外的其他条件。可选状态。

CEC_TX_STATUS_MAX_RETRIES

0x20

一次或多次重试后,传输失败。此状态位与 CEC_TX_STATUS_OK 是互斥的。仍然可以设置其他位来解释看到了哪些失败。

CEC_TX_STATUS_ABORTED

0x40

由于 HDMI 断开连接、适配器未配置、传输被中断或驱动程序在尝试启动传输时返回错误,传输被中止。

CEC_TX_STATUS_TIMEOUT

0x80

传输超时。这通常不应该发生,这表示驱动程序存在问题。

CEC 接收状态

CEC_RX_STATUS_OK

0x01

消息已成功接收。

CEC_RX_STATUS_TIMEOUT

0x02

之前发送的消息的回复超时。

CEC_RX_STATUS_FEATURE_ABORT

0x04

消息已成功接收,但回复是 CEC_MSG_FEATURE_ABORT。仅当此消息是对之前发送的消息的回复时,才设置此状态。

CEC_RX_STATUS_ABORTED

0x08

等待对之前发送的消息的回复被中止,因为 HDMI 电缆已断开连接、适配器未配置或等待回复的 CEC_TRANSMIT 被中断。

2.11.5. 返回值

成功时返回 0,失败时返回 -1,并适当地设置 errno 变量。通用错误代码在 通用错误代码 章节中进行了描述。

ioctl CEC_RECEIVE 可以返回以下错误代码

EAGAIN

接收队列中没有消息,并且文件句柄处于非阻塞模式。

ETIMEDOUT

在等待消息时达到 timeout

ERESTARTSYS

等待消息被中断(例如,通过 Ctrl-C)。

ioctl CEC_TRANSMIT 可以返回以下错误代码

ENOTTY

未设置 CEC_CAP_TRANSMIT 功能,因此不支持此 ioctl。

EPERM

CEC 适配器未配置,即从未调用过 ioctl CEC_ADAP_S_LOG_ADDRS,或者 CEC_MSG_FL_RAW 是从没有 CAP_SYS_RAWIO 功能的进程中使用的。

ENONET

CEC 适配器未配置,即调用了 ioctl CEC_ADAP_S_LOG_ADDRS,但物理地址无效,因此没有声明逻辑地址。在这种情况下,从发起者 0xf(“未注册”)到目标 0(“电视”)的传输是一个例外。在这种情况下,传输将照常进行。

EBUSY

另一个文件句柄处于独占关注者或发起者模式,或者文件句柄处于 CEC_MODE_NO_INITIATOR 模式。如果传输队列已满,也会返回此错误。

EINVAL

struct cec_msg 的内容无效。

ERESTARTSYS

等待成功传输被中断(例如,通过 Ctrl-C)。