6.1. 简介¶
LIRC 代表 Linux 红外遥控。LIRC 设备接口是一个双向接口,用于在用户空间和内核空间之间传输原始红外数据和解码后的扫描码数据。从根本上说,它只是一个字符设备 (/dev/lircX,其中 X = 0, 1, 2, ...),在其上定义了许多标准的 struct file_operations。关于来回传输原始红外数据和解码后的扫描码,基本的 fops 是 read、write 和 ioctl。
也可以将 BPF 程序附加到 LIRC 设备,用于将原始红外数据解码为扫描码。
驱动程序向 LIRC 注册后示例 dmesg 输出
$ dmesg |grep lirc_dev
rc rc0: lirc_dev: driver mceusb registered at minor = 0, raw IR receiver, raw IR transmitter
您应该看到的字符设备信息
$ ls -l /dev/lirc*
crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0
请注意,v4l-utils 软件包包含用于使用 LIRC 设备的工具
ir-ctl:可以接收原始红外数据和传输红外数据,以及查询 LIRC 设备功能。
ir-keytable:可以加载键映射;允许您设置红外内核协议;加载 BPF 红外解码器和测试红外解码。还提供了一些 BPF 红外解码器。
6.2. LIRC 模式¶
LIRC 支持一些接收和发送红外代码的模式,如下表所示。
LIRC_MODE_SCANCODE
此模式用于发送和接收红外数据。
对于传输(又名发送),创建一个
struct lirc_scancode
,并在scancode
成员中设置所需的扫描码,将rc_proto
设置为 红外协议,并将所有其他成员设置为 0。将此结构写入 lirc 设备。对于接收,您可以从 LIRC 设备读取
struct lirc_scancode
。scancode
字段设置为接收到的扫描码,红外协议在rc_proto
中设置。如果扫描码映射到有效的键代码,则将其设置在keycode
字段中,否则将其设置为KEY_RESERVED
。如果切换位在支持它的协议(例如 rc-5 和 rc-6)中设置,则
flags
可以设置LIRC_SCANCODE_FLAG_TOGGLE
,或者如果接收到支持它的协议的重复(例如 nec),则可以设置LIRC_SCANCODE_FLAG_REPEAT
。在 Sanyo 和 NEC 协议中,如果按住遥控器上的按钮,而不是重复整个扫描码,遥控器会发送一个更短的消息,其中没有扫描码,这仅仅意味着按钮被按住,即“重复”。当接收到此消息时,将设置
LIRC_SCANCODE_FLAG_REPEAT
,并且重复扫描码和键代码。使用 nec,无法区分“按钮按住”和“重复按下同一按钮”。rc-5 和 rc-6 协议有一个切换位。当释放一个按钮并再次按下时,切换位会反转。如果设置了切换位,则设置
LIRC_SCANCODE_FLAG_TOGGLE
。
timestamp
字段使用扫描码解码时的时间纳秒(在CLOCK_MONOTONIC
中)填充。
LIRC_MODE_MODE2
驱动程序将脉冲和空间代码的序列作为一系列 u32 值返回给用户空间。
此模式仅用于红外接收。
高 8 位确定数据包类型,低 24 位确定有效负载。使用
LIRC_VALUE()
宏来获取有效负载,宏LIRC_MODE2()
将为您提供类型,它是以下之一
LIRC_MODE2_PULSE
表示以微秒为单位的红外存在,也称为闪光。
LIRC_MODE2_SPACE
表示以微秒为单位的红外不存在,也称为间隙。
LIRC_MODE2_FREQUENCY
如果使用 ioctl LIRC_SET_MEASURE_CARRIER_MODE 启用了载波频率的测量,则此数据包会为您提供以赫兹为单位的载波频率。
LIRC_MODE2_TIMEOUT
由于未检测到红外信号,使用 ioctl LIRC_GET_REC_TIMEOUT 和 LIRC_SET_REC_TIMEOUT 设置的超时到期时,将发送此数据包,其中包含未检测到红外信号的微秒数。
LIRC_MODE2_OVERFLOW
表示红外接收器遇到溢出,并且丢失了一些红外信号。此后的红外数据应再次正确。实际值并不重要,但内核将其设置为 0xffffff 以与 lircd 兼容。
LIRC_MODE_PULSE
在脉冲模式下,一系列脉冲/空间整数值使用 LIRC write() 写入 lirc 设备。
这些值是以微秒为单位的脉冲和空间长度交替出现。第一个和最后一个条目必须是脉冲,因此必须有奇数个条目。
此模式仅用于红外发送。
6.3. LIRC_MODE_SCANCODE 使用的数据类型¶
-
struct lirc_scancode¶
解码后的扫描码,带有用于 LIRC_MODE_SCANCODE 的协议
定义:
struct lirc_scancode {
__u64 timestamp;
__u16 flags;
__u16 rc_proto;
__u32 keycode;
__u64 scancode;
};
成员
timestamp
使用 CLOCK_MONOTONIC 解码红外信号时的纳秒时间戳。
flags
对于传输应为 0。当接收扫描码时,可以根据协议设置 LIRC_SCANCODE_FLAG_TOGGLE 或 LIRC_SCANCODE_FLAG_REPEAT
rc_proto
请参阅
enum rc_proto
keycode
转换后的键代码。对于传输设置为 0。
scancode
接收或要发送的扫描码
-
enum rc_proto¶
远程控制器协议
常量
RC_PROTO_UNKNOWN
协议未知
RC_PROTO_OTHER
协议已知但专有
RC_PROTO_RC5
Philips RC5 协议
RC_PROTO_RC5X_20
Philips RC5x 20 位协议
RC_PROTO_RC5_SZ
RC5 的 StreamZap 变体
RC_PROTO_JVC
JVC 协议
RC_PROTO_SONY12
Sony 12 位协议
RC_PROTO_SONY15
Sony 15 位协议
RC_PROTO_SONY20
Sony 20 位协议
RC_PROTO_NEC
NEC 协议
RC_PROTO_NECX
扩展 NEC 协议
RC_PROTO_NEC32
NEC 32 位协议
RC_PROTO_SANYO
Sanyo 协议
RC_PROTO_MCIR2_KBD
类似 RC6 的 MCE 键盘
RC_PROTO_MCIR2_MSE
类似 RC6 的 MCE 鼠标
RC_PROTO_RC6_0
Philips RC6-0-16 协议
RC_PROTO_RC6_6A_20
Philips RC6-6A-20 协议
RC_PROTO_RC6_6A_24
Philips RC6-6A-24 协议
RC_PROTO_RC6_6A_32
Philips RC6-6A-32 协议
RC_PROTO_RC6_MCE
MCE (Philips RC6-6A-32 子类型) 协议
RC_PROTO_SHARP
Sharp 协议
RC_PROTO_XMP
XMP 协议
RC_PROTO_CEC
CEC 协议
RC_PROTO_IMON
iMon Pad 协议
RC_PROTO_RCMM12
RC-MM 协议 12 位
RC_PROTO_RCMM24
RC-MM 协议 24 位
RC_PROTO_RCMM32
RC-MM 协议 32 位
RC_PROTO_XBOX_DVD
Xbox DVD 电影播放套件协议
RC_PROTO_MAX
enum rc_proto
的最大值
6.4. 基于 BPF 的红外解码器¶
内核支持解码最常见的 红外协议,但有许多协议不受支持。为了支持这些协议,可以加载一个 BPF 程序来执行解码。这只能在支持读取原始红外信号的 LIRC 设备上完成。
首先,使用带有 BPF_LOAD_PROG
参数的 bpf(2) 系统调用,必须加载 BPF_PROG_TYPE_LIRC_MODE2
类型的程序。一旦附加到 LIRC 设备,就会在 LIRC 设备上的每个脉冲、空间或超时事件中调用此程序。BPF 程序的上下文是指向无符号整数的指针,它是 LIRC_MODE_MODE2 值。当程序解码扫描码后,可以使用 BPF 函数 bpf_rc_keydown()
或 bpf_rc_repeat()
提交它。可以使用 bpf_rc_pointer_rel()
报告鼠标或指针移动。
一旦您有了 BPF_PROG_TYPE_LIRC_MODE2
BPF 程序的文件描述符,就可以使用 bpf(2) 系统调用将其附加到 LIRC 设备。目标必须是 LIRC 设备的文件描述符,并且附加类型必须是 BPF_LIRC_MODE2
。一次最多可以将 64 个 BPF 程序附加到单个 LIRC 设备。