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 消息,应用程序必须填写 struct 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 消息,应用程序必须填写 struct 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 规范允许在物理地址无效时从“未注册”向“电视”发送消息,因为某些电视在进入待机状态或切换到另一个输入时会将 HDMI 连接器的热插拔检测引脚拉低。

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

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

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

__u8

tx_nack_cnt

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

__u8

tx_low_drive_cnt

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

__u8

tx_error_cnt

Arbitration Lost 或 Not Acknowledged 之外的传输错误数量的计数器。仅当硬件支持此功能时才会设置此值,否则始终为 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 操作码、Vendor ID(在消息的字节 1-4 中)以及 struct cec_msg reply 字段组成。

请注意,这假设 Vendor 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,或者从没有 CAP_SYS_RAWIO 功能的进程使用了 CEC_MSG_FL_RAW

ENONET

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

EBUSY

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

EINVAL

struct cec_msg 的内容无效。

ERESTARTSYS

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