6.1. 简介¶
LIRC 代表 Linux 红外遥控。LIRC 设备接口是一个双向接口,用于在用户空间和内核空间之间传输原始 IR 和解码的扫描码数据。从根本上说,它只是一个字符设备(/dev/lircX,X = 0, 1, 2, ...),在其上定义了许多标准的 struct file_operations。关于来回传输原始 IR 和解码的扫描码,基本的操作是 read、write 和 ioctl。
还可以将 BPF 程序附加到 LIRC 设备,以将原始 IR 解码为扫描码。
驱动程序注册 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:可以接收原始 IR 并发送 IR,以及查询 LIRC 设备功能。
ir-keytable:可以加载键映射;允许您设置 IR 内核协议;加载 BPF IR 解码器并测试 IR 解码。还提供了一些 BPF IR 解码器。
6.2. LIRC 模式¶
LIRC 支持一些接收和发送 IR 代码的模式,如下表所示。
LIRC_MODE_SCANCODE
此模式用于发送和接收 IR。
对于发送(又名传输),创建一个
struct lirc_scancode
,其中scancode
成员中设置所需的扫描码,rc_proto
设置为 IR 协议,所有其他成员设置为 0。将此结构写入 lirc 设备。对于接收,您从 LIRC 设备读取
struct lirc_scancode
。scancode
字段设置为接收到的扫描码,并且 IR 协议 在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 值返回给用户空间。
此模式仅用于 IR 接收。
高 8 位确定数据包类型,低 24 位确定有效负载。使用
LIRC_VALUE()
宏获取有效负载,宏LIRC_MODE2()
将为您提供类型,它是以下之一
LIRC_MODE2_PULSE
表示以微秒为单位的 IR 的存在,也称为闪光。
LIRC_MODE2_SPACE
表示以微秒为单位的 IR 不存在,也称为间隔。
LIRC_MODE2_FREQUENCY
如果使用 ioctl LIRC_SET_MEASURE_CARRIER_MODE 启用了载波频率的测量,则此数据包会提供载波频率(以赫兹为单位)。
LIRC_MODE2_TIMEOUT
当由于未检测到 IR 而导致使用 ioctl LIRC_GET_REC_TIMEOUT 和 LIRC_SET_REC_TIMEOUT 设置的超时过期时,将发送此数据包,其中包含没有 IR 的微秒数。
LIRC_MODE2_OVERFLOW
表示 IR 接收器遇到溢出,并且缺少某些 IR。此后的 IR 数据应再次正确。实际值并不重要,但是内核将其设置为 0xffffff 以与 lircd 兼容。
LIRC_MODE_PULSE
在脉冲模式下,一系列脉冲/空间整数值使用 LIRC write() 写入 lirc 设备。
这些值是以微秒为单位的交替脉冲和空间长度。第一个和最后一个条目必须是脉冲,因此必须有奇数个条目。
此模式仅用于 IR 发送。
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
解码 IR 时,使用 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 的 IR 解码器¶
内核支持解码最常见的红外协议,但仍有许多协议不支持。为了支持这些协议,可以加载一个 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
。一次最多可以向单个 LIRC 设备附加 64 个 BPF 程序。